vpp_plugin/vlib/
node_generic.rs

1//! Generic node implementations
2//!
3//! This module contains generic implementations of VPP nodes following set patterns that can be
4//! reused across different plugins.
5
6use core::slice;
7use std::mem::MaybeUninit;
8
9use arrayvec::ArrayVec;
10
11use crate::vlib::{
12    buffer::BufferRef,
13    node::{FrameRef, NextNodes, Node, NodeRuntimeRef, FRAME_SIZE},
14    BufferIndex, MainRef,
15};
16
17/// Next node to send a buffer to from a generic node implementation
18#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
19pub enum FeatureNextNode<NextNode> {
20    /// A specific next node defined by the generic node implementation
21    DefinedNode(NextNode),
22    /// The next feature in the feature arc
23    NextFeature,
24}
25
26impl<NextNode> From<NextNode> for FeatureNextNode<NextNode> {
27    fn from(value: NextNode) -> Self {
28        Self::DefinedNode(value)
29    }
30}
31
32/// Trait for generic node implementations processing one buffer at a time in a feature arc
33pub trait GenericFeatureNodeX1<N: Node> {
34    /// Processing a buffer and determining the next node to send it to
35    ///
36    /// # Safety
37    ///
38    /// The safety preconditions vary depending on the specific implementation.
39    unsafe fn map_buffer_to_next(
40        &self,
41        vm: &MainRef,
42        node: &mut NodeRuntimeRef<N>,
43        b0: &mut BufferRef<N::FeatureData>,
44    ) -> FeatureNextNode<N::NextNodes>;
45}
46
47/// Generic implementation of a VPP node processing one buffer at a time in a feature arc
48///
49/// # Safety
50///
51/// - The preconditions of the [`GenericFeatureNodeX1::map_buffer_to_next`] method must be upheld.
52/// - Nodes with this node as a next node must send valid buffer indices in the Vector data.
53/// - This mode must be invoked as part of a feature arc.
54/// - All of the next nodes of this node must have a `Vector` type of `BufferIndex`, `Scalar` of
55///   `()` and `Aux` of `()` (or their C equivalents).
56#[inline(always)]
57pub unsafe fn generic_feature_node_x1<GenericNode, N, FeatureData>(
58    vm: &MainRef,
59    node: &mut NodeRuntimeRef<N>,
60    frame: &mut FrameRef<N>,
61    generic_node_impl: GenericNode,
62) -> u16
63where
64    N: Node<Vector = BufferIndex, Scalar = (), Aux = (), FeatureData = FeatureData>,
65    GenericNode: GenericFeatureNodeX1<N>,
66    FeatureData: Copy,
67{
68    let mut nexts: [MaybeUninit<u16>; FRAME_SIZE] = [MaybeUninit::uninit(); FRAME_SIZE];
69    let mut b = ArrayVec::new();
70
71    let from = frame.get_buffers::<FRAME_SIZE>(vm, &mut b);
72
73    for (i, b0) in b.iter_mut().enumerate() {
74        let next = generic_node_impl.map_buffer_to_next(vm, node, b0);
75        let next = match next {
76            FeatureNextNode::NextFeature => b0.vnet_feature_next().0 as u16,
77            FeatureNextNode::DefinedNode(next) => next.into_u16(),
78        };
79        nexts.get_unchecked_mut(i).write(next);
80    }
81
82    // SAFETY: since every buffer yielded a next node and the number of elements of nexts is the
83    // same as from, then every element is initialised. In addition, since we got all of the
84    // buffer indices from `frame.get_buffers()` then they must all be valid. All the next nodes
85    // expect to receive buffer indices and no other vector, aux or scalar data.
86    vm.buffer_enqueue_to_next(
87        node,
88        from,
89        std::mem::transmute::<&[MaybeUninit<u16>], &[u16]>(slice::from_raw_parts(
90            nexts.as_ptr(),
91            b.len(),
92        )),
93    );
94
95    frame.vector().len() as u16
96}