Skip to main content

vpp_plugin/vnet/
types.rs

1//! VPP networking types
2
3use std::{ffi::CStr, fmt, str::FromStr};
4
5use crate::{
6    bindings::{
7        ip4_header_t, ip6_address_t, ip6_header_t, vlib_helper_format_ip4_header,
8        vlib_helper_format_ip6_header, vlib_helper_format_vnet_sw_if_index_name,
9        vlib_helper_unformat_vnet_sw_interface, vnet_get_main,
10    },
11    vppinfra,
12};
13
14impl ip6_address_t {
15    /// Creates a new IPv6 address with all bytes set to zero
16    pub const fn new() -> Self {
17        Self { as_u8: [0; 16] }
18    }
19}
20
21impl ip6_header_t {
22    /// Creates a new IPv6 header with all fields set to zero
23    pub const fn new() -> Self {
24        Self {
25            ip_version_traffic_class_and_flow_label: 0,
26            payload_length: 0,
27            protocol: 0,
28            hop_limit: 0,
29            src_address: ip6_address_t::new(),
30            dst_address: ip6_address_t::new(),
31        }
32    }
33}
34
35impl fmt::Debug for ip6_header_t {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        <Self as fmt::Display>::fmt(self, f)
38    }
39}
40
41impl fmt::Display for ip6_header_t {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        // SAFETY: vlib_helper_format_ip4_header returns a valid Vec representing a C string (on
44        // allocation failure it aborts)
45        unsafe {
46            let s = vppinfra::vec::Vec::from_raw(vlib_helper_format_ip6_header(
47                std::ptr::null_mut(),
48                self,
49                std::mem::size_of::<Self>(),
50            ));
51            let cstr = CStr::from_bytes_with_nul_unchecked(&s);
52            write!(f, "{}", cstr.to_string_lossy())
53        }
54    }
55}
56
57impl Clone for ip6_header_t {
58    fn clone(&self) -> Self {
59        // SAFETY: if self is a valid reference then it must also be a valid pointer for reading
60        // its fields, and reading unaligned from a valid pointer is always safe
61        unsafe {
62            Self {
63                ip_version_traffic_class_and_flow_label: std::ptr::read_unaligned(
64                    std::ptr::addr_of!(self.ip_version_traffic_class_and_flow_label),
65                ),
66                payload_length: std::ptr::read_unaligned(std::ptr::addr_of!(self.payload_length)),
67                protocol: self.protocol,
68                hop_limit: self.hop_limit,
69                src_address: self.src_address,
70                dst_address: self.dst_address,
71            }
72        }
73    }
74}
75
76/// Software interface index
77#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
78pub struct SwIfIndex(u32);
79
80impl SwIfIndex {
81    /// The local0 interface
82    pub const LOCAL0: Self = SwIfIndex::new(0);
83
84    /// Creates a software interface index from a `u32` value
85    pub const fn new(sw_if_index: u32) -> Self {
86        Self(sw_if_index)
87    }
88}
89
90impl fmt::Display for SwIfIndex {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        // SAFETY: the variable argument list matches what the format_vnet_sw_if_index_name
93        // implementation in VPP expects, and it's allowed for the s parameter to be null as
94        // this is a VPP vector which automatically allocates on null. The function cannot fail
95        // so the return value is always a valid vector pointer.
96        unsafe {
97            let s = vppinfra::vec::Vec::from_raw(vlib_helper_format_vnet_sw_if_index_name(
98                std::ptr::null_mut(),
99                vnet_get_main(),
100                self.0,
101            ));
102            let cstr = CStr::from_bytes_with_nul_unchecked(&s);
103            write!(f, "{}", cstr.to_string_lossy())
104        }
105    }
106}
107
108impl From<u32> for SwIfIndex {
109    fn from(value: u32) -> Self {
110        Self(value)
111    }
112}
113
114impl From<SwIfIndex> for u32 {
115    fn from(value: SwIfIndex) -> Self {
116        value.0
117    }
118}
119
120impl FromStr for SwIfIndex {
121    type Err = ();
122
123    fn from_str(s: &str) -> Result<Self, Self::Err> {
124        let mut i = vppinfra::unformat::UnformatInput::from(s);
125        let mut sw_if_index = 0;
126        // SAFETY: the variable argument list matches what the unformat_vnet_sw_interface
127        // implementation in VPP expects.
128        let ret = unsafe {
129            vlib_helper_unformat_vnet_sw_interface(i.as_ptr(), vnet_get_main(), &mut sw_if_index)
130        };
131        if ret > 0 {
132            Ok(Self(sw_if_index))
133        } else {
134            Err(())
135        }
136    }
137}
138
139impl fmt::Debug for ip4_header_t {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        <Self as fmt::Display>::fmt(self, f)
142    }
143}
144
145impl fmt::Display for ip4_header_t {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        // SAFETY: vlib_helper_format_ip4_header returns a valid Vec representing a C string (on
148        // allocation failure it aborts)
149        unsafe {
150            let s = vppinfra::vec::Vec::from_raw(vlib_helper_format_ip4_header(
151                std::ptr::null_mut(),
152                self,
153                std::mem::size_of::<Self>(),
154            ));
155            let cstr = CStr::from_bytes_with_nul_unchecked(&s);
156            write!(f, "{}", cstr.to_string_lossy())
157        }
158    }
159}