Skip to main content

vpp_plugin/vnet/
buffer.rs

1#![allow(missing_docs)]
2
3//! VNET buffer flags
4
5use bitflags::bitflags;
6
7use crate::{
8    bindings::{
9        VNET_BUFFER_F_AVAIL1, VNET_BUFFER_F_AVAIL2, VNET_BUFFER_F_AVAIL3, VNET_BUFFER_F_AVAIL4,
10        VNET_BUFFER_F_AVAIL5, VNET_BUFFER_F_AVAIL6, VNET_BUFFER_F_AVAIL7, VNET_BUFFER_F_AVAIL8,
11        VNET_BUFFER_F_AVAIL9, VNET_BUFFER_F_FLOW_REPORT, VNET_BUFFER_F_GSO, VNET_BUFFER_F_IS_DVR,
12        VNET_BUFFER_F_IS_IP4, VNET_BUFFER_F_IS_IP6, VNET_BUFFER_F_IS_NATED,
13        VNET_BUFFER_F_L2_HDR_OFFSET_VALID, VNET_BUFFER_F_L3_HDR_OFFSET_VALID,
14        VNET_BUFFER_F_L4_CHECKSUM_COMPUTED, VNET_BUFFER_F_L4_CHECKSUM_CORRECT,
15        VNET_BUFFER_F_L4_HDR_OFFSET_VALID, VNET_BUFFER_F_LOCALLY_ORIGINATED,
16        VNET_BUFFER_F_LOOP_COUNTER_VALID, VNET_BUFFER_F_OFFLOAD, VNET_BUFFER_F_QOS_DATA_VALID,
17        VNET_BUFFER_F_SPAN_CLONE, VNET_BUFFER_F_VLAN_1_DEEP, VNET_BUFFER_F_VLAN_2_DEEP,
18        feature_main, vlib_rx_or_tx_t_VLIB_RX, vlib_rx_or_tx_t_VLIB_TX, vnet_buffer_opaque_t,
19        vnet_config_main_t,
20    },
21    vnet::types::SwIfIndex,
22};
23
24bitflags! {
25    /// VNET buffer flags
26    pub struct BufferFlags: u32 {
27        const L4_CHECKSUM_COMPUTED = VNET_BUFFER_F_L4_CHECKSUM_COMPUTED as u32;
28        const L4_CHECKSUM_CORRECT = VNET_BUFFER_F_L4_CHECKSUM_CORRECT as u32;
29        const VLAN_2_DEEP = VNET_BUFFER_F_VLAN_2_DEEP as u32;
30        const VLAN_1_DEEP = VNET_BUFFER_F_VLAN_1_DEEP as u32;
31        const SPAN_CLONE = VNET_BUFFER_F_SPAN_CLONE as u32;
32        const LOOP_COUNTER_VALID = VNET_BUFFER_F_LOOP_COUNTER_VALID as u32;
33        const LOCALLY_ORIGINATED = VNET_BUFFER_F_LOCALLY_ORIGINATED as u32;
34        const IS_IP4 = VNET_BUFFER_F_IS_IP4 as u32;
35        const IS_IP6 = VNET_BUFFER_F_IS_IP6 as u32;
36        const OFFLOAD = VNET_BUFFER_F_OFFLOAD as u32;
37        const IS_NATED = VNET_BUFFER_F_IS_NATED as u32;
38        const L2_HDR_OFFSET_VALID = VNET_BUFFER_F_L2_HDR_OFFSET_VALID as u32;
39        const L3_HDR_OFFSET_VALID = VNET_BUFFER_F_L3_HDR_OFFSET_VALID as u32;
40        const L4_HDR_OFFSET_VALID = VNET_BUFFER_F_L4_HDR_OFFSET_VALID as u32;
41        const FLOW_REPORT = VNET_BUFFER_F_FLOW_REPORT as u32;
42        const IS_DVR = VNET_BUFFER_F_IS_DVR as u32;
43        const QOS_DATA_VALID = VNET_BUFFER_F_QOS_DATA_VALID as u32;
44        const GSO = VNET_BUFFER_F_GSO as u32;
45        const AVAIL1 = VNET_BUFFER_F_AVAIL1 as u32;
46        const AVAIL2 = VNET_BUFFER_F_AVAIL2 as u32;
47        const AVAIL3 = VNET_BUFFER_F_AVAIL3 as u32;
48        const AVAIL4 = VNET_BUFFER_F_AVAIL4 as u32;
49        const AVAIL5 = VNET_BUFFER_F_AVAIL5 as u32;
50        const AVAIL6 = VNET_BUFFER_F_AVAIL6 as u32;
51        const AVAIL7 = VNET_BUFFER_F_AVAIL7 as u32;
52        const AVAIL8 = VNET_BUFFER_F_AVAIL8 as u32;
53        const AVAIL9 = VNET_BUFFER_F_AVAIL9 as u32;
54
55        // vlib flags not represented here
56        const _ = !0;
57    }
58}
59
60impl BufferFlags {
61    /// Get the VLIB buffer flags from the VNET buffer flags
62    pub fn as_vlib_flags(&self) -> crate::vlib::buffer::BufferFlags {
63        crate::vlib::buffer::BufferFlags::from_bits_retain(self.bits())
64    }
65}
66
67impl crate::vlib::buffer::BufferFlags {
68    /// Get the VNET buffer flags from the VLIB buffer flags
69    pub fn vnet_flags(&self) -> BufferFlags {
70        BufferFlags::from_bits_retain(self.bits())
71    }
72}
73
74/// Reference to a VNET buffer
75///
76/// A `&mut BufferRef` is equivalent to a `vnet_buffer_opaque_t *` in C (a `*vnet_buffer_opaque_t`
77/// in Rust).
78#[repr(transparent)]
79pub struct BufferRef(foreign_types::Opaque);
80
81impl BufferRef {
82    /// Create a `&BufferRef` from a raw pointer
83    ///
84    /// # Safety
85    ///
86    /// - The pointer must be a valid and properly initialised `vlib_buffer_t`.
87    /// - The pointer must stay valid and the contents must not be mutated for the duration of the
88    ///   lifetime of the returned object.
89    #[inline(always)]
90    pub unsafe fn from_ptr<'a>(ptr: *const vnet_buffer_opaque_t) -> &'a BufferRef {
91        // SAFETY: The safety requirements are documented in the function's safety comment.
92        unsafe { &*(ptr as *mut _) }
93    }
94
95    /// Create a `&mut BufferRef` from a raw pointer
96    ///
97    /// # Safety
98    ///
99    /// - The pointer must be a valid and properly initialised `vlib_buffer_t`.
100    /// - The pointer must stay valid and the contents must not be mutated for the duration of the
101    ///   lifetime of the returned object.
102    #[inline(always)]
103    pub unsafe fn from_ptr_mut<'a>(ptr: *mut vnet_buffer_opaque_t) -> &'a mut BufferRef {
104        // SAFETY: The safety requirements are documented in the function's safety comment.
105        unsafe { &mut *(ptr as *mut _) }
106    }
107
108    /// Returns the raw pointer to the underlying `vnet_buffer_opaque_t`
109    #[inline(always)]
110    pub fn as_ptr(&self) -> *mut vnet_buffer_opaque_t {
111        self as *const _ as *mut _
112    }
113
114    /// Returns the index of the feature arc that the buffer is being processed from
115    #[inline(always)]
116    pub fn feature_arc_index(&self) -> u8 {
117        // SAFETY: since the reference to self is valid, so must be the pointer
118        unsafe { (*self.as_ptr()).feature_arc_index }
119    }
120
121    /// Returns the index of the receive software interface
122    pub fn rx_sw_if_index(&self) -> SwIfIndex {
123        // SAFETY: since the reference to self is valid, so must be the pointer
124        SwIfIndex::new(unsafe { (*self.as_ptr()).sw_if_index[vlib_rx_or_tx_t_VLIB_RX as usize] })
125    }
126
127    /// Set the index of the receive software interface
128    pub fn set_rx_sw_if_index(&mut self, sw_if_index: SwIfIndex) {
129        // SAFETY: since the reference to self is valid, so must be the pointer
130        unsafe {
131            (*self.as_ptr()).sw_if_index[vlib_rx_or_tx_t_VLIB_TX as usize] = sw_if_index.into()
132        };
133    }
134
135    /// Returns the index of the transmit software interface
136    pub fn tx_sw_if_index(&self) -> Option<SwIfIndex> {
137        // SAFETY: since the reference to self is valid, so must be the pointer
138        let sw_if_index = unsafe { (*self.as_ptr()).sw_if_index[vlib_rx_or_tx_t_VLIB_TX as usize] };
139        if sw_if_index == u32::MAX {
140            None
141        } else {
142            Some(sw_if_index.into())
143        }
144    }
145
146    /// Set the index of the transmit software interface
147    ///
148    /// If `sw_if_index` is `None` then it will be set to [`u32::MAX`], which indicates to
149    /// various nodes to use the interface from forwarding lookups.
150    pub fn set_tx_sw_if_index(&mut self, sw_if_index: Option<SwIfIndex>) {
151        let sw_if_index = sw_if_index.map(u32::from).unwrap_or(u32::MAX);
152        // SAFETY: since the reference to self is valid, so must be the pointer
153        unsafe { (*self.as_ptr()).sw_if_index[vlib_rx_or_tx_t_VLIB_TX as usize] = sw_if_index };
154    }
155}
156
157impl<FeatureData> crate::vlib::BufferRef<FeatureData> {
158    pub fn vnet_buffer(&self) -> &BufferRef {
159        let ptr = &self.as_metadata().opaque as *const _;
160        // SAFETY: ptr is valid since reference to self is valid, and the representation is a
161        // valid `vnet_buffer_opaque_t`
162        unsafe { BufferRef::from_ptr(ptr as *const vnet_buffer_opaque_t) }
163    }
164
165    pub fn vnet_buffer_mut(&mut self) -> &mut BufferRef {
166        let ptr = &mut self.as_metadata_mut().opaque as *mut _;
167        // SAFETY: ptr is valid since reference to self is valid, and the representation is a
168        // valid `vnet_buffer_opaque_t`
169        unsafe { BufferRef::from_ptr_mut(ptr as *mut vnet_buffer_opaque_t) }
170    }
171}
172
173/// Returns VNET config data for the given config index
174///
175/// In the process, the config index is advanced to the next one.
176///
177/// # Safety
178///
179/// - `cm` must be a valid pointer to a `vnet_config_main_t` structure.
180/// - `(*cm).config_string_heap` must be a valid pointer to a contiguous heap of `u32` values.
181/// - `*config_index` must be a valid index into the heap: `index + (size_of::<FeatureData>() /
182///   size_of::<u32>()) + 1 <= heap_length` must be satisfied, where `heap_length` is the
183///   number of `u32` elements in the heap. Additionally, the memory at
184///   `(*cm).config_string_heap.add(index)` must be properly aligned for `FeatureData` and
185///   contain valid data of that type, followed by a valid `u32` next-index value.
186/// - `FeatureData` must exactly match the type that was stored at this config index during
187///   configuration creation, including any alignment and representation requirements.
188#[inline(always)]
189unsafe fn vnet_get_config_data<FeatureData: Copy>(
190    cm: *const vnet_config_main_t,
191    config_index: &mut u32,
192) -> (u32, FeatureData) {
193    // SAFETY: function preconditions mean that this pointer arithmetic is valid and matches what
194    // VPP expects
195    unsafe {
196        let index = *config_index;
197
198        let d = (*cm).config_string_heap.add(index as usize);
199
200        let n = std::mem::size_of::<FeatureData>().div_ceil(std::mem::size_of_val(&*d));
201
202        // The last u32 is the next index
203        let next = *d.add(n);
204
205        // Advance config index to next config
206        *config_index = index + n as u32 + 1;
207
208        (next, *(d as *const FeatureData))
209    }
210}
211
212impl<FeatureData: Copy> crate::vlib::BufferRef<FeatureData> {
213    /// Get the next feature node and feature data for this buffer
214    ///
215    /// Used when continuing to the next feature node in a node invoked from a feature arc.
216    ///
217    /// # Safety
218    ///
219    /// Must only be used from nodes when invoked from a feature arc.
220    #[inline(always)]
221    pub unsafe fn vnet_feature_next(&mut self) -> (u32, FeatureData) {
222        let arc = self.vnet_buffer().feature_arc_index();
223        // SAFETY: method precondition means that arc is a valid index into
224        // `feature_main.feature_config_mains`, and then also that the `current_config_index`
225        // buffer field is a valid config index for that feature arc.
226        // Access to `feature_main.feature_config_mains` is safe without locking because VPP only
227        // modifies this during init, before any buffers are allocated.
228        unsafe {
229            let cm = *feature_main.feature_config_mains.add(arc as usize);
230
231            vnet_get_config_data(
232                &cm.config_main,
233                &mut self.as_metadata_mut().__bindgen_anon_1.current_config_index,
234            )
235        }
236    }
237}