summaryrefslogtreecommitdiff
path: root/bindings
diff options
context:
space:
mode:
authorLu Qiuwen <[email protected]>2023-09-15 18:46:54 +0800
committerLu Qiuwen <[email protected]>2023-09-19 18:14:32 +0800
commit04baae0e96cbd6ea2b0aa2f4dfe339e56d33719e (patch)
tree50ef3c163fd0d7da589f6e0f920c962e011d0f86 /bindings
parentcb674f9e168b6e709136e17a5bc87d3925c6f479 (diff)
feature: add binding for libmarsio.
Diffstat (limited to 'bindings')
-rw-r--r--bindings/marsio/Cargo.toml12
-rw-r--r--bindings/marsio/build.rs4
-rw-r--r--bindings/marsio/src/lib.rs254
-rw-r--r--bindings/marsio/src/sys.rs193
-rw-r--r--bindings/marsio/tests/integration_test.rs106
5 files changed, 569 insertions, 0 deletions
diff --git a/bindings/marsio/Cargo.toml b/bindings/marsio/Cargo.toml
new file mode 100644
index 0000000..5b16d8f
--- /dev/null
+++ b/bindings/marsio/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "marsio"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+anyhow = "1.0.75"
+arrayvec = "0.7.4"
+libc = "0.2.147"
+static_init = "1.0.3"
diff --git a/bindings/marsio/build.rs b/bindings/marsio/build.rs
new file mode 100644
index 0000000..1dae047
--- /dev/null
+++ b/bindings/marsio/build.rs
@@ -0,0 +1,4 @@
+fn main() {
+ /* set the library search path for marsio */
+ println!("cargo:rustc-link-search=native=/opt/tsg/mrzcpd/znver1/lib/");
+}
diff --git a/bindings/marsio/src/lib.rs b/bindings/marsio/src/lib.rs
new file mode 100644
index 0000000..c4de824
--- /dev/null
+++ b/bindings/marsio/src/lib.rs
@@ -0,0 +1,254 @@
+use anyhow::Result;
+use anyhow::{anyhow, Context};
+use arrayvec::ArrayVec;
+use libc::cpu_set_t;
+use libc::{c_char, c_int};
+use std::ptr::null_mut;
+use std::ptr::NonNull;
+
+mod sys;
+
+const DEFAULT_RX_BURST: usize = 32;
+const DEFAULT_TX_BURST: usize = 32;
+type RecvBuf<'instance> = ArrayVec<MarsioBuff<'instance>, DEFAULT_RX_BURST>;
+type SendBuf<'instance> = ArrayVec<MarsioBuff<'instance>, DEFAULT_TX_BURST>;
+
+/* SAFE APIS */
+
+pub struct MarsioBuff<'instance> {
+ marsio_buff: NonNull<sys::marsio_buff_t>,
+ _marker: std::marker::PhantomData<&'instance MarsioInstance>,
+}
+
+pub struct CoreID(pub usize);
+
+impl<'instance> MarsioBuff<'instance> {
+ fn buffer(&self) -> &[u8] {
+ unsafe {
+ let buff_ptr = sys::marsio_buff_mtod(self.marsio_buff.as_ptr());
+ let buff_len = sys::marsio_buff_buflen(self.marsio_buff.as_ptr()) as usize;
+ return std::slice::from_raw_parts(buff_ptr as *const u8, buff_len);
+ }
+ }
+
+ fn buffer_mut(&self) -> &mut [u8] {
+ unsafe {
+ let buff_ptr = sys::marsio_buff_mtod(self.marsio_buff.as_ptr());
+ let buff_len = sys::marsio_buff_buflen(self.marsio_buff.as_ptr()) as usize;
+ return std::slice::from_raw_parts_mut(buff_ptr as *mut u8, buff_len);
+ }
+ }
+}
+
+impl<'instance> Drop for MarsioBuff<'instance> {
+ fn drop(&mut self) {
+ let buf_ptr_array = [self.marsio_buff; 1];
+
+ unsafe {
+ sys::marsio_buff_free_v2(
+ null_mut(),
+ buf_ptr_array.as_ptr() as *mut sys::marsio_buff_t,
+ buf_ptr_array.len() as i32,
+ );
+ }
+ }
+}
+
+pub struct MarsioDevice {
+ device_handle: NonNull<sys::mr_vdev_t>,
+ sendpath_handle: NonNull<sys::mr_sendpath_t>,
+}
+
+impl MarsioDevice {
+ pub fn recv_burst(&self, recv_buf: &mut RecvBuf, qid: u32) {
+ let mut recv_buf_raw_ptrs = ArrayVec::<_, DEFAULT_RX_BURST>::new();
+ unsafe {
+ let recv_count = sys::marsio_recv_burst(
+ self.device_handle.as_ptr(),
+ qid,
+ recv_buf_raw_ptrs.as_ptr(),
+ recv_buf_raw_ptrs.capacity() as c_int,
+ );
+
+ assert!(recv_count <= recv_buf_raw_ptrs.capacity() as c_int);
+ recv_buf_raw_ptrs.set_len(recv_count as usize);
+ };
+
+ /* map all recv_buf_raw_ptrs to Marsio Buff objects */
+ let recv_buf_new = recv_buf_raw_ptrs
+ .into_iter()
+ .map(|recv_buf_raw_ptr| MarsioBuff {
+ marsio_buff: NonNull::new(recv_buf_raw_ptr).unwrap(),
+ _marker: std::marker::PhantomData {},
+ })
+ .collect();
+
+ *recv_buf = recv_buf_new;
+ }
+
+ pub fn send_burst(&self, send_buf: &mut SendBuf, qid: u32) {
+ let send_buf_raw_ptrs: ArrayVec<_, DEFAULT_TX_BURST> = send_buf
+ .iter()
+ .map(|marsio_buff| marsio_buff.marsio_buff.as_ptr())
+ .collect();
+
+ unsafe {
+ sys::marsio_send_burst(
+ self.sendpath_handle.as_ptr(),
+ qid,
+ send_buf_raw_ptrs.as_ptr(),
+ send_buf_raw_ptrs.len() as c_int,
+ )
+ };
+
+ /* the send_buf should be empty */
+ assert_eq!(send_buf.len(), 0);
+ }
+}
+
+pub struct MarsioInstance {
+ mr_instance: NonNull<sys::mr_instance_t>,
+}
+
+impl MarsioInstance {
+ pub fn new() -> Result<MarsioInstance> {
+ let mr_instance_ptr = NonNull::new(unsafe { sys::marsio_create() })
+ .context("Failed to create marsio instance")?;
+
+ Ok(MarsioInstance {
+ mr_instance: mr_instance_ptr,
+ })
+ }
+
+ pub fn init(&mut self, app_name: &str) -> Result<()> {
+ let result = unsafe {
+ sys::marsio_init(
+ self.mr_instance.as_ptr(),
+ app_name.as_ptr() as *const c_char,
+ )
+ };
+
+ match result {
+ 0 => Ok(()),
+ _ => Err(anyhow!(
+ "Failed to init marsio instance, result: {}",
+ result
+ )),
+ }
+ }
+
+ pub fn set_thread_count(&mut self, thread_count: u32) -> Result<()> {
+ let result = unsafe {
+ sys::marsio_option_set(
+ self.mr_instance.as_ptr(),
+ sys::marsio_opt_type_t::MARSIO_OPT_THREAD_NUM,
+ &thread_count as *const u32 as *const std::ffi::c_void,
+ std::mem::size_of_val(&thread_count),
+ )
+ };
+
+ if result != 0 {
+ return Err(anyhow!(
+ "Failed to set thread count, thread_count: {}, result: {}",
+ thread_count,
+ result
+ ));
+ }
+
+ Ok(())
+ }
+
+ pub fn set_cpu_affinity(&mut self, core_ids: &[CoreID]) -> Result<()> {
+ let cpu_set = unsafe {
+ let mut cpu_set: cpu_set_t = std::mem::zeroed();
+ libc::CPU_ZERO(&mut cpu_set);
+
+ for core_id in core_ids {
+ libc::CPU_SET(core_id.0, &mut cpu_set);
+ }
+
+ cpu_set
+ };
+
+ let result = unsafe {
+ sys::marsio_option_set(
+ self.mr_instance.as_ptr(),
+ sys::marsio_opt_type_t::MARSIO_OPT_THREAD_MASK_IN_CPUSET,
+ &cpu_set as *const cpu_set_t as *mut std::ffi::c_void,
+ std::mem::size_of::<cpu_set_t>(),
+ )
+ };
+
+ if result != 0 {
+ return Err(anyhow!("Failed to set cpu set, result: {}", result));
+ }
+
+ Ok(())
+ }
+
+ pub fn open_device(
+ &mut self,
+ device_name: &str,
+ nr_rx_queues: i32,
+ nr_tx_queues: i32,
+ ) -> Result<MarsioDevice> {
+ let _device_handle = NonNull::new(unsafe {
+ sys::marsio_open_device(
+ self.mr_instance.as_ptr(),
+ device_name.as_ptr() as *const c_char,
+ nr_rx_queues,
+ nr_tx_queues,
+ )
+ })
+ .context(format!(
+ "Failed to open device, device_name: {}",
+ device_name
+ ))?;
+
+ let _send_path_handle =
+ NonNull::new(unsafe { sys::marsio_sendpath_create_by_vdev(_device_handle.as_ptr()) })
+ .context(format!(
+ "Failed to get device send path, device_name: {}",
+ device_name
+ ))?;
+
+ Ok(MarsioDevice {
+ device_handle: _device_handle,
+ sendpath_handle: _send_path_handle,
+ })
+ }
+
+ pub fn buf_alloc(&mut self) -> Option<MarsioBuff> {
+ let mut out_buf = [std::ptr::null_mut(); 1];
+ unsafe {
+ sys::marsio_buff_alloc_v2(
+ self.mr_instance.as_ptr(),
+ out_buf.as_mut_ptr() as *mut sys::marsio_buff_t,
+ out_buf.len() as i32,
+ )
+ };
+
+ let buf_ptr = NonNull::new(out_buf[0])?;
+ Some(MarsioBuff {
+ marsio_buff: buf_ptr,
+ _marker: std::marker::PhantomData {},
+ })
+ }
+}
+
+impl Drop for MarsioDevice {
+ fn drop(&mut self) {
+ unsafe {
+ sys::marsio_sendpath_destory(self.sendpath_handle.as_ptr());
+ sys::marsio_close_device(self.device_handle.as_ptr());
+ };
+ }
+}
+
+impl Drop for MarsioInstance {
+ fn drop(&mut self) {
+ unsafe {
+ sys::marsio_destroy(self.mr_instance.as_ptr());
+ }
+ }
+}
diff --git a/bindings/marsio/src/sys.rs b/bindings/marsio/src/sys.rs
new file mode 100644
index 0000000..849b959
--- /dev/null
+++ b/bindings/marsio/src/sys.rs
@@ -0,0 +1,193 @@
+use libc::{c_char, c_int, c_void, size_t};
+
+#[allow(non_camel_case_types)]
+#[repr(C)]
+pub enum marsio_opt_type_t {
+ MARSIO_OPT_THREAD_NUM,
+ MARSIO_OPT_THREAD_MASK,
+ MARSIO_OPT_EXIT_WHEN_ERR,
+ MARSIO_OPT_THREAD_MASK_IN_CPUSET,
+}
+
+#[allow(non_camel_case_types)]
+#[repr(C)]
+pub enum marsio_opt_send_t {
+ MARSIO_SEND_OPT_NO_FREE = 1 << 0,
+ /* 发送时计算发包哈希值,用于分流 */
+ MARSIO_SEND_OPT_REHASH = 1 << 1,
+ /* 快速报文路径 */
+ MARSIO_SEND_OPT_FAST = 1 << 2,
+ /* 报文追踪标记 */
+ MARSIO_SEND_OPT_TRACE = 1 << 3,
+ /* 控制报文标记 */
+ MARSIO_SEND_OPT_CTRL = 1 << 4,
+}
+
+#[allow(non_camel_case_types)]
+#[repr(C)]
+enum mr_sendpath_type {
+ /* 去往特定虚设备的发包路径 */
+ MR_SENDPATH_VDEV,
+ /* 路由查表确定发包路径 */
+ MR_SENDPATH_ROUTE_NORMAL,
+ /* 特定设备路由查表确定发包路径 */
+ MR_SENDPATH_ROUTE_SPEC_DEV,
+ /* MAX标记 */
+ MR_SENDPATH_MAX,
+}
+
+#[allow(non_camel_case_types)]
+#[repr(C)]
+enum mr_sendpath_option {
+ /* 构建四层报文头 */
+ MR_SENDPATH_OPT_BUILD_L4 = 0,
+ /* 构建三层报文头 */
+ MR_SENDPATH_OPT_BUILD_L3 = 1,
+ /* 构建二层报文头 */
+ MR_SENDPATH_OPT_BUILD_L2 = 2,
+ /* 构建前Hook点回调 */
+ MR_SENDPATH_OPT_HOOK_PREBUILD = 50,
+ /* 构建后Hook点回调 */
+ MR_SENDPATH_OPT_HOOK_POSTBUILD = 51,
+}
+
+#[allow(non_camel_case_types)]
+#[repr(C)]
+enum mr_clone_options {
+ /* 拷贝区域 */
+ MR_BUFF_CLONE_DATA = 1 << 0,
+ MR_BUFF_CLONE_BUFF = 1 << 1,
+ MR_BUFF_CLONE_CTRLZONE = 1 << 2,
+}
+
+#[allow(non_camel_case_types)]
+#[repr(C)]
+enum mr_thread_affinity_mode {
+ /* 禁用线程亲和性设置 */
+ MR_THREAD_AFFINITY_DISABLE = 0,
+ /* 自动线程亲和性设置 */
+ MR_THREAD_AFFINITY_AUTO = 1,
+ /* 自定义线程亲和性设置 */
+ MR_THREAD_AFFINITY_USER = 255,
+}
+
+#[allow(non_camel_case_types)]
+#[repr(C)]
+enum mr_timestamp_type {
+ /* 从网卡收取时或报文缓冲区申请时的时间戳 */
+ MR_TIMESTAMP_RX_OR_ALLOC = 0,
+}
+
+#[allow(non_camel_case_types)]
+#[repr(C)]
+enum mr_buff_metadata_type {
+ /* Rehash Index */
+ MR_BUFF_REHASH_INDEX = 0,
+ /* VLAN TCI */
+ MR_BUFF_METADATA_VLAN_TCI = 1,
+ /* dispatch ctx */
+ MR_BUFF_ROUTE_CTX = 2,
+ /* session id */
+ MR_BUFF_SESSION_ID = 3,
+ /* dir, internal->external or external->internal */
+ MR_BUFF_DIR = 4,
+ /* payload offset */
+ MR_BUFF_PAYLOAD_OFFSET = 5,
+ /* user 0 */
+ MR_BUFF_USER_0 = 254,
+}
+
+#[allow(non_camel_case_types)]
+pub type mr_instance_t = c_void;
+#[allow(non_camel_case_types)]
+pub type marsio_buff_t = c_void;
+#[allow(non_camel_case_types)]
+pub type mr_vdev_t = c_void;
+#[allow(non_camel_case_types)]
+pub type mr_sendpath_t = c_void;
+
+#[allow(non_camel_case_types)]
+pub type cpu_mask_t = u64;
+#[allow(non_camel_case_types)]
+pub type port_id_t = u32;
+#[allow(non_camel_case_types)]
+pub type queue_id_t = u32;
+#[allow(non_camel_case_types)]
+pub type thread_id_t = u32;
+
+#[link(name = "marsio")]
+extern "C" {
+ /* options and init */
+ pub fn marsio_option_get(
+ mr_instance: *mut mr_instance_t,
+ opt_type: c_int,
+ out_opt: *mut c_void,
+ out_opt_buffer: size_t,
+ ) -> c_int;
+ pub fn marsio_option_set(
+ mr_instance: *mut mr_instance_t,
+ opt_type: marsio_opt_type_t,
+ opt: *const c_void,
+ sz_opt: size_t,
+ ) -> c_int;
+ pub fn marsio_init(mr_instance: *mut mr_instance_t, app_name: *const c_char) -> c_int;
+ pub fn marsio_thread_init(mr_instance: *mut mr_instance_t) -> c_int;
+ pub fn marsio_destroy(mr_instance: *mut mr_instance_t) -> c_int;
+ pub fn marsio_create() -> *mut mr_instance_t;
+
+ /* devices */
+ pub fn marsio_open_device(
+ mr_instance: *mut mr_instance_t,
+ devsym: *const c_char,
+ nr_rxstream: c_int,
+ nr_txstream: c_int,
+ ) -> *mut mr_vdev_t;
+ pub fn marsio_close_device(vdev: *mut mr_vdev_t);
+ pub fn marsio_device_lookup(
+ mr_instance: *const mr_instance_t,
+ devsym: *const c_char,
+ ) -> *mut mr_vdev_t;
+ pub fn marsio_sendpath_create_by_vdev(vdev: *mut mr_vdev_t) -> *mut mr_sendpath_t;
+ pub fn marsio_sendpath_destory(sendpath: *mut mr_sendpath_t);
+ pub fn marsio_buff_mtod(m: *mut marsio_buff_t) -> *mut c_void;
+ pub fn marsio_buff_buflen(m: *mut marsio_buff_t) -> u32;
+
+ /* packet i/o */
+ pub fn marsio_recv_burst(
+ vdev: *mut mr_vdev_t,
+ qid: queue_id_t,
+ mbufs: *const *mut marsio_buff_t,
+ nr_mbufs: c_int,
+ ) -> c_int;
+ pub fn marsio_recv_all_burst(
+ mr_instance: *mut mr_instance_t,
+ qid: queue_id_t,
+ mbufs: *const *mut marsio_buff_t,
+ nr_mbufs: c_int,
+ ) -> c_int;
+ pub fn marsio_send_burst(
+ sendpath: *mut mr_sendpath_t,
+ qid: queue_id_t,
+ mbufs: *const *mut marsio_buff_t,
+ nr_mbufs: c_int,
+ ) -> c_int;
+ pub fn marsio_send_burst_with_options(
+ sendpath: *mut mr_sendpath_t,
+ sid: queue_id_t,
+ mbufs: *mut marsio_buff_t,
+ nr_mbufs: c_int,
+ options: u16,
+ ) -> c_int;
+
+ pub fn marsio_buff_alloc_v2(
+ mr_instance: *mut mr_instance_t,
+ buffs: *mut marsio_buff_t,
+ nr_buffs: c_int,
+ ) -> c_int;
+
+ pub fn marsio_buff_free_v2(
+ mr_instance: *mut mr_instance_t,
+ buffs: *mut marsio_buff_t,
+ nr_buffs: c_int,
+ ) -> c_int;
+}
diff --git a/bindings/marsio/tests/integration_test.rs b/bindings/marsio/tests/integration_test.rs
new file mode 100644
index 0000000..ada89f0
--- /dev/null
+++ b/bindings/marsio/tests/integration_test.rs
@@ -0,0 +1,106 @@
+use arrayvec::ArrayVec;
+use marsio::*;
+use static_init::dynamic;
+use std::process::Command;
+
+struct TestFixture {
+ _mrzcpd_child: std::process::Child,
+ _mrzcpd_cfgfile: String,
+}
+
+impl TestFixture {
+ fn new() -> TestFixture {
+ /* write the tmp configration file */
+ let tmp_config_template = "";
+
+ std::fs::write("/tmp/mrzcpd_startup.conf", tmp_config_template).unwrap();
+
+ /* run the program as backgroup */
+ let mut child = Command::new("/opt/tsg/mrzcpd/bin/mrzcpd")
+ .arg("-c")
+ .arg("/tmp/mrzcpd_startup.conf")
+ .spawn()
+ .unwrap();
+
+ TestFixture {
+ _mrzcpd_child: child,
+ _mrzcpd_cfgfile: tmp_config_template.to_string(),
+ }
+ }
+}
+
+impl Drop for TestFixture {
+ fn drop(&mut self) {
+ self._mrzcpd_child.kill().unwrap();
+ }
+}
+
+/*
+#[dynamic(drop)]
+static mut TEST_FIXTURE_OBJECT: TestFixture = TestFixture::new();
+*/
+
+#[test]
+fn test_marsio_instance_create_and_destroy() {
+ let mr_instance = MarsioInstance::new();
+ assert!(mr_instance.is_ok());
+
+ let mut mr_instance = mr_instance.unwrap();
+ assert!(mr_instance.set_thread_count(1).is_ok());
+}
+
+#[test]
+fn test_marsio_one_thread() {
+ let mut mr_instance = MarsioInstance::new().unwrap();
+
+ /* Bind the thread to core 1,2 */
+ let core_ids = [CoreID(1), CoreID(2)];
+ mr_instance.set_cpu_affinity(&core_ids).unwrap();
+ mr_instance.init("integration_test").unwrap();
+
+ /* open the test device with one rx/tx queue */
+ let mut device = mr_instance.open_device("test", 1, 1).unwrap();
+
+ /* try to recv the mbuf */
+ let mut mbuf_array = ArrayVec::<MarsioBuff, 32>::new();
+ device.recv_burst(&mut mbuf_array, 0);
+
+ /* for now, should be empty */
+ assert_eq!(mbuf_array.len(), 0);
+
+ /* try to alloc mbuf */
+ let mut send_buf = ArrayVec::<MarsioBuff, 32>::new();
+ let mut send_mbuf = mr_instance.buf_alloc().unwrap();
+
+ /* set the mbuf data */
+ send_buf.push(send_mbuf);
+ device.send_burst(&mut send_buf, 0);
+}
+
+#[test]
+fn test_marsio_multiple_thread() {
+ let mut mr_instance = MarsioInstance::new().unwrap();
+
+ /* Bind the thread to core 1,2 */
+ let core_ids = [CoreID(1), CoreID(2)];
+ mr_instance.set_cpu_affinity(&core_ids).unwrap();
+ mr_instance.init("integration_test").unwrap();
+
+ /* open the test device */
+ let mut device = mr_instance.open_device("test", 2, 2).unwrap();
+
+ let mut thread_join_handles = Vec::new();
+ for tid in 0..1 {
+ let thread_join_handle = std::thread::spawn(|| {
+ let mut send_buf = ArrayVec::<MarsioBuff, 32>::new();
+ let mut send_mbuf = mr_instance.buf_alloc().unwrap();
+ send_buf.push(send_mbuf);
+ });
+ thread_join_handles.push(thread_join_handle);
+ }
+
+ for join_handle in thread_join_handles {
+ let join_result = join_handle.join().unwrap();
+ println!("join_handle_result = {:?}", join_result);
+ }
+}