use std::{cell::UnsafeCell, marker::PhantomData};
use crate::{
bindings::{
feature_main, vlib_helper_remove_feature_from_registrations, vnet_feature_enable_disable,
vnet_feature_registration_t,
},
vlib::{
BarrierHeldMainRef,
node::{Node, NodeRegistration},
},
vnet::{error::VnetError, types::SwIfIndex},
};
pub struct FeatureRegistration<FeatureConfig> {
feat: UnsafeCell<vnet_feature_registration_t>,
_marker: PhantomData<FeatureConfig>,
}
impl<FeatureConfig> FeatureRegistration<FeatureConfig> {
pub const unsafe fn new<N: Node<FeatureData = FeatureConfig>, const N_NEXT_NODES: usize>(
mut feat: vnet_feature_registration_t,
node: &'static NodeRegistration<N, N_NEXT_NODES>,
) -> Self {
feat.node_name = node.name_ptr().cast_mut();
Self {
feat: UnsafeCell::new(feat),
_marker: PhantomData,
}
}
pub unsafe fn register(&'static self) {
unsafe {
let fm = std::ptr::addr_of_mut!(feature_main);
let r = self.feat.get();
(*r).next = (*fm).next_feature;
(*fm).next_feature = r;
}
}
pub unsafe fn unregister(&self) {
unsafe {
let fm = std::ptr::addr_of_mut!(feature_main);
let r = self.feat.get();
vlib_helper_remove_feature_from_registrations(fm, r);
}
}
pub fn enable(
&self,
_vm: &BarrierHeldMainRef,
sw_if_index: SwIfIndex,
feature_config: FeatureConfig,
) -> Result<(), VnetError> {
let ret = unsafe {
let feat = self.feat.get().cast_const();
vnet_feature_enable_disable(
(*feat).arc_name,
(*feat).node_name,
sw_if_index.into(),
1,
std::ptr::addr_of!(feature_config).cast_mut().cast(),
std::mem::size_of::<FeatureConfig>() as u32,
)
};
if ret == 0 { Ok(()) } else { Err(ret.into()) }
}
pub fn disable(
&self,
_vm: &BarrierHeldMainRef,
sw_if_index: SwIfIndex,
) -> Result<(), VnetError> {
let ret = unsafe {
let feat = self.feat.get().cast_const();
vnet_feature_enable_disable(
(*feat).arc_name,
(*feat).node_name,
sw_if_index.into(),
0,
std::ptr::null_mut(),
0,
)
};
if ret == 0 { Ok(()) } else { Err(ret.into()) }
}
}
unsafe impl<T> Sync for FeatureRegistration<T> {}