diff options
| author | Lu Qiuwen <[email protected]> | 2023-09-15 18:46:54 +0800 |
|---|---|---|
| committer | Lu Qiuwen <[email protected]> | 2023-09-19 18:14:32 +0800 |
| commit | 04baae0e96cbd6ea2b0aa2f4dfe339e56d33719e (patch) | |
| tree | 50ef3c163fd0d7da589f6e0f920c962e011d0f86 /bindings | |
| parent | cb674f9e168b6e709136e17a5bc87d3925c6f479 (diff) | |
feature: add binding for libmarsio.
Diffstat (limited to 'bindings')
| -rw-r--r-- | bindings/marsio/Cargo.toml | 12 | ||||
| -rw-r--r-- | bindings/marsio/build.rs | 4 | ||||
| -rw-r--r-- | bindings/marsio/src/lib.rs | 254 | ||||
| -rw-r--r-- | bindings/marsio/src/sys.rs | 193 | ||||
| -rw-r--r-- | bindings/marsio/tests/integration_test.rs | 106 |
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);
+ }
+}
|
