1use crate::error::{DpdkError, DpdkResult};
7use std::ffi::CString;
8use std::ptr::NonNull;
9
10pub struct Mbuf {
16 raw: NonNull<dpdk_sys::rte_mbuf>,
17}
18
19unsafe impl Send for Mbuf {}
22
23impl Mbuf {
24 pub unsafe fn from_raw(ptr: *mut dpdk_sys::rte_mbuf) -> Option<Self> {
33 NonNull::new(ptr).map(|raw| Self { raw })
34 }
35
36 pub fn as_raw(&self) -> *mut dpdk_sys::rte_mbuf {
38 self.raw.as_ptr()
39 }
40
41 pub fn into_raw(self) -> *mut dpdk_sys::rte_mbuf {
45 let ptr = self.raw.as_ptr();
46 std::mem::forget(self); ptr
48 }
49
50 pub fn data_offset(&self) -> u16 {
52 unsafe { (*self.raw.as_ptr()).data_off }
53 }
54
55 pub fn packet_len(&self) -> u32 {
57 unsafe { (*self.raw.as_ptr()).pkt_len }
58 }
59
60 pub fn data_len(&self) -> u16 {
62 unsafe { (*self.raw.as_ptr()).data_len }
63 }
64
65 pub fn buf_len(&self) -> u16 {
67 unsafe { (*self.raw.as_ptr()).buf_len }
68 }
69
70 pub fn data(&self) -> Option<&[u8]> {
74 unsafe {
75 let mbuf = self.raw.as_ptr();
76 let buf_addr = (*mbuf).buf_addr;
77 if buf_addr.is_null() {
78 return None;
79 }
80 let data_ptr = (buf_addr as *const u8).add((*mbuf).data_off as usize);
81 Some(std::slice::from_raw_parts(data_ptr, (*mbuf).data_len as usize))
82 }
83 }
84
85 pub fn data_mut(&mut self) -> Option<&mut [u8]> {
89 unsafe {
90 let mbuf = self.raw.as_ptr();
91 let buf_addr = (*mbuf).buf_addr;
92 if buf_addr.is_null() {
93 return None;
94 }
95 let data_ptr = (buf_addr as *mut u8).add((*mbuf).data_off as usize);
96 Some(std::slice::from_raw_parts_mut(data_ptr, (*mbuf).data_len as usize))
97 }
98 }
99
100 pub fn set_data_len(&mut self, len: u16) {
102 unsafe {
103 (*self.raw.as_ptr()).data_len = len;
104 }
105 }
106
107 pub fn set_packet_len(&mut self, len: u32) {
109 unsafe {
110 (*self.raw.as_ptr()).pkt_len = len;
111 }
112 }
113
114 pub fn ol_flags(&self) -> u64 {
116 unsafe { (*self.raw.as_ptr()).ol_flags }
117 }
118
119 pub fn set_ol_flags(&mut self, flags: u64) {
121 unsafe {
122 (*self.raw.as_ptr()).ol_flags = flags;
123 }
124 }
125
126 pub fn vlan_tci(&self) -> u16 {
132 unsafe { (*self.raw.as_ptr()).vlan_tci }
133 }
134
135 pub fn set_vlan_tci(&mut self, tci: u16) {
140 unsafe {
141 (*self.raw.as_ptr()).vlan_tci = tci;
142 }
143 }
144
145 pub fn set_tx_offload(&mut self, l2_len: u8, l3_len: u16, l4_len: u8) {
154 let tx_offload = (l2_len as u64)
155 | ((l3_len as u64) << 7)
156 | ((l4_len as u64) << 16);
157 unsafe {
158 dpdk_sys::mbuf_set_tx_offload(self.raw.as_ptr(), tx_offload);
159 }
160 }
161}
162
163impl Drop for Mbuf {
164 fn drop(&mut self) {
165 unsafe {
166 dpdk_sys::rte_pktmbuf_free(self.raw.as_ptr());
167 }
168 }
169}
170
171pub struct Mempool {
176 raw: NonNull<dpdk_sys::rte_mempool>,
177 name: String,
178}
179
180unsafe impl Send for Mempool {}
182unsafe impl Sync for Mempool {}
183
184pub const DEFAULT_POOL_SIZE: u32 = 8192;
186
187pub const DEFAULT_CACHE_SIZE: u32 = 256;
189
190pub const DEFAULT_DATA_ROOM_SIZE: u16 = dpdk_sys::RTE_MBUF_DEFAULT_BUF_SIZE as u16;
192
193pub const MAX_MEMPOOL_NAME_LEN: usize = 32;
195
196#[derive(Debug, Clone)]
198pub struct MempoolConfig {
199 pub n: u32,
201 pub cache_size: u32,
203 pub data_room_size: u16,
205 pub socket_id: i32,
207}
208
209impl Default for MempoolConfig {
210 fn default() -> Self {
211 Self {
212 n: DEFAULT_POOL_SIZE,
213 cache_size: DEFAULT_CACHE_SIZE,
214 data_room_size: DEFAULT_DATA_ROOM_SIZE,
215 socket_id: dpdk_sys::SOCKET_ID_ANY,
216 }
217 }
218}
219
220impl MempoolConfig {
221 pub fn new() -> Self {
223 Self::default()
224 }
225
226 pub fn with_size(mut self, n: u32) -> Self {
228 self.n = n;
229 self
230 }
231
232 pub fn with_cache_size(mut self, cache_size: u32) -> Self {
234 self.cache_size = cache_size;
235 self
236 }
237
238 pub fn with_data_room_size(mut self, size: u16) -> Self {
240 self.data_room_size = size;
241 self
242 }
243
244 pub fn with_socket_id(mut self, socket_id: i32) -> Self {
246 self.socket_id = socket_id;
247 self
248 }
249}
250
251impl Mempool {
252 pub fn create(
269 name: &str,
270 n: u32,
271 cache_size: u32,
272 data_room_size: u16,
273 socket_id: i32,
274 ) -> DpdkResult<Self> {
275 if name.is_empty() {
277 return Err(DpdkError::InvalidName("mempool name cannot be empty".to_string()));
278 }
279 if name.len() > MAX_MEMPOOL_NAME_LEN {
280 return Err(DpdkError::InvalidName(format!(
281 "mempool name too long (max {} characters)",
282 MAX_MEMPOOL_NAME_LEN
283 )));
284 }
285
286 let c_name = CString::new(name).map_err(|_| {
288 DpdkError::InvalidName("mempool name contains null bytes".to_string())
289 })?;
290
291 let ptr = unsafe {
293 dpdk_sys::rte_pktmbuf_pool_create(
294 c_name.as_ptr(),
295 n,
296 cache_size,
297 0, data_room_size,
299 socket_id,
300 )
301 };
302
303 NonNull::new(ptr)
304 .map(|raw| Self {
305 raw,
306 name: name.to_string(),
307 })
308 .ok_or_else(|| {
309 let errno = unsafe { dpdk_sys::rte_errno() };
311 DpdkError::MempoolCreateFailed(format!(
312 "rte_pktmbuf_pool_create failed for '{}' (errno: {})",
313 name, errno
314 ))
315 })
316 }
317
318 pub fn create_with_config(name: &str, config: &MempoolConfig) -> DpdkResult<Self> {
325 Self::create(
326 name,
327 config.n,
328 config.cache_size,
329 config.data_room_size,
330 config.socket_id,
331 )
332 }
333
334 pub fn create_default(name: &str) -> DpdkResult<Self> {
336 Self::create_with_config(name, &MempoolConfig::default())
337 }
338
339 pub fn name(&self) -> &str {
341 &self.name
342 }
343
344 pub fn alloc(&self) -> DpdkResult<Mbuf> {
346 unsafe {
347 let ptr = dpdk_sys::rte_pktmbuf_alloc(self.raw.as_ptr());
348 Mbuf::from_raw(ptr).ok_or(DpdkError::MemoryAllocationFailed)
349 }
350 }
351
352 pub fn alloc_bulk(&self, count: usize) -> DpdkResult<Vec<Mbuf>> {
357 if count == 0 {
358 return Ok(Vec::new());
359 }
360
361 let mut ptrs: Vec<*mut dpdk_sys::rte_mbuf> =
362 vec![std::ptr::null_mut(); count];
363
364 let ret = unsafe {
365 dpdk_sys::rte_pktmbuf_alloc_bulk(
366 self.raw.as_ptr(),
367 ptrs.as_mut_ptr(),
368 count as u32,
369 )
370 };
371
372 if ret != 0 {
373 return Err(DpdkError::MemoryAllocationFailed);
374 }
375
376 let mbufs: Vec<Mbuf> = ptrs
377 .into_iter()
378 .filter_map(|ptr| unsafe { Mbuf::from_raw(ptr) })
379 .collect();
380
381 if mbufs.len() != count {
382 return Err(DpdkError::MemoryAllocationFailed);
385 }
386
387 Ok(mbufs)
388 }
389
390 pub fn available_count(&self) -> u32 {
392 unsafe { dpdk_sys::rte_mempool_avail_count(self.raw.as_ptr()) }
393 }
394
395 pub fn in_use_count(&self) -> u32 {
397 unsafe { dpdk_sys::rte_mempool_in_use_count(self.raw.as_ptr()) }
398 }
399
400 pub fn is_full(&self) -> bool {
402 unsafe { dpdk_sys::rte_mempool_full(self.raw.as_ptr()) != 0 }
403 }
404
405 pub fn is_empty(&self) -> bool {
407 unsafe { dpdk_sys::rte_mempool_empty(self.raw.as_ptr()) != 0 }
408 }
409
410 pub fn as_raw(&self) -> *mut dpdk_sys::rte_mempool {
412 self.raw.as_ptr()
413 }
414}
415
416impl Drop for Mempool {
417 fn drop(&mut self) {
418 unsafe {
419 dpdk_sys::rte_mempool_free(self.raw.as_ptr());
420 }
421 }
422}
423
424pub struct MbufBuilder {
426 data: Vec<u8>,
427}
428
429impl MbufBuilder {
430 pub fn new() -> Self {
431 Self { data: Vec::new() }
432 }
433
434 pub fn ethernet(mut self, dst_mac: [u8; 6], src_mac: [u8; 6], ethertype: u16) -> Self {
436 self.data.extend_from_slice(&dst_mac);
437 self.data.extend_from_slice(&src_mac);
438 self.data.extend_from_slice(ðertype.to_be_bytes());
439 self
440 }
441
442 pub fn ipv4(mut self, src: [u8; 4], dst: [u8; 4], protocol: u8, payload_len: u16) -> Self {
444 let total_len = 20 + payload_len;
445 self.data.push(0x45); self.data.push(0x00); self.data.extend_from_slice(&total_len.to_be_bytes());
448 self.data.extend_from_slice(&[0, 0]); self.data.extend_from_slice(&[0, 0]); self.data.push(64); self.data.push(protocol);
452 self.data.extend_from_slice(&[0, 0]); self.data.extend_from_slice(&src);
454 self.data.extend_from_slice(&dst);
455 self
456 }
457
458 pub fn udp(mut self, src_port: u16, dst_port: u16, payload_len: u16) -> Self {
460 let udp_len = 8 + payload_len;
461 self.data.extend_from_slice(&src_port.to_be_bytes());
462 self.data.extend_from_slice(&dst_port.to_be_bytes());
463 self.data.extend_from_slice(&udp_len.to_be_bytes());
464 self.data.extend_from_slice(&[0, 0]); self
466 }
467
468 pub fn payload(mut self, data: &[u8]) -> Self {
470 self.data.extend_from_slice(data);
471 self
472 }
473
474 pub fn build(self) -> Vec<u8> {
476 self.data
477 }
478}
479
480impl Default for MbufBuilder {
481 fn default() -> Self {
482 Self::new()
483 }
484}
485
486#[cfg(test)]
487mod tests {
488 use super::*;
489
490 #[test]
495 fn test_mbuf_builder() {
496 let frame = MbufBuilder::new()
497 .ethernet([0xff; 6], [0x00; 6], 0x0800)
498 .ipv4([192, 168, 1, 1], [192, 168, 1, 2], 17, 16)
499 .udp(12345, 9000, 8)
500 .payload(b"test")
501 .build();
502
503 assert_eq!(frame.len(), 14 + 20 + 8 + 4);
505 }
506
507 #[test]
508 fn test_mbuf_builder_empty() {
509 let frame = MbufBuilder::new().build();
510 assert!(frame.is_empty());
511 }
512
513 #[test]
514 fn test_mbuf_builder_payload_only() {
515 let payload = b"hello world";
516 let frame = MbufBuilder::new().payload(payload).build();
517 assert_eq!(frame.len(), payload.len());
518 assert_eq!(&frame, payload);
519 }
520
521 #[test]
522 fn test_mbuf_builder_ethernet_only() {
523 let frame = MbufBuilder::new()
524 .ethernet([0x01, 0x02, 0x03, 0x04, 0x05, 0x06], [0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f], 0x0800)
525 .build();
526
527 assert_eq!(frame.len(), 14);
529
530 assert_eq!(&frame[0..6], &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
532 assert_eq!(&frame[6..12], &[0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]);
534 assert_eq!(&frame[12..14], &[0x08, 0x00]);
536 }
537
538 #[test]
543 fn test_mempool_config_default() {
544 let config = MempoolConfig::default();
545 assert_eq!(config.n, DEFAULT_POOL_SIZE);
546 assert_eq!(config.cache_size, DEFAULT_CACHE_SIZE);
547 assert_eq!(config.data_room_size, DEFAULT_DATA_ROOM_SIZE);
548 assert_eq!(config.socket_id, dpdk_sys::SOCKET_ID_ANY);
549 }
550
551 #[test]
552 fn test_mempool_config_builder() {
553 let config = MempoolConfig::new()
554 .with_size(4096)
555 .with_cache_size(128)
556 .with_data_room_size(2048)
557 .with_socket_id(0);
558
559 assert_eq!(config.n, 4096);
560 assert_eq!(config.cache_size, 128);
561 assert_eq!(config.data_room_size, 2048);
562 assert_eq!(config.socket_id, 0);
563 }
564
565 #[test]
566 fn test_mempool_config_chaining() {
567 let config = MempoolConfig::new()
569 .with_size(1024)
570 .with_cache_size(64);
571
572 assert_eq!(config.n, 1024);
573 assert_eq!(config.cache_size, 64);
574 assert_eq!(config.data_room_size, DEFAULT_DATA_ROOM_SIZE);
576 }
577
578 #[test]
583 fn test_mempool_create() {
584 let pool = Mempool::create("test_pool", 128, 32, 2048, -1);
585 assert!(pool.is_ok());
586 let pool = pool.unwrap();
587 assert_eq!(pool.name(), "test_pool");
588 }
589
590 #[test]
591 fn test_mempool_create_with_config() {
592 let config = MempoolConfig::new().with_size(256).with_cache_size(64);
593 let pool = Mempool::create_with_config("config_pool", &config);
594 assert!(pool.is_ok());
595 let pool = pool.unwrap();
596 assert_eq!(pool.name(), "config_pool");
597 }
598
599 #[test]
600 fn test_mempool_create_default() {
601 let pool = Mempool::create_default("default_pool");
602 assert!(pool.is_ok());
603 let pool = pool.unwrap();
604 assert_eq!(pool.name(), "default_pool");
605 }
606
607 #[test]
608 fn test_mempool_create_empty_name() {
609 let result = Mempool::create("", 128, 32, 2048, -1);
610 assert!(result.is_err());
611 match result {
612 Err(DpdkError::InvalidName(msg)) => {
613 assert!(msg.contains("empty"));
614 }
615 _ => panic!("Expected InvalidName error"),
616 }
617 }
618
619 #[test]
620 fn test_mempool_create_name_too_long() {
621 let long_name = "a".repeat(MAX_MEMPOOL_NAME_LEN + 1);
622 let result = Mempool::create(&long_name, 128, 32, 2048, -1);
623 assert!(result.is_err());
624 match result {
625 Err(DpdkError::InvalidName(msg)) => {
626 assert!(msg.contains("too long"));
627 }
628 _ => panic!("Expected InvalidName error"),
629 }
630 }
631
632 #[test]
633 fn test_mempool_create_name_with_null() {
634 let result = Mempool::create("test\0pool", 128, 32, 2048, -1);
635 assert!(result.is_err());
636 match result {
637 Err(DpdkError::InvalidName(msg)) => {
638 assert!(msg.contains("null"));
639 }
640 _ => panic!("Expected InvalidName error"),
641 }
642 }
643
644 #[test]
645 fn test_mempool_name_max_length() {
646 let max_name = "a".repeat(MAX_MEMPOOL_NAME_LEN);
647 let result = Mempool::create(&max_name, 128, 32, 2048, -1);
648 assert!(result.is_ok());
649 }
650
651 #[test]
656 fn test_mempool_alloc() {
657 let pool = Mempool::create("alloc_pool", 128, 32, 2048, -1).unwrap();
658 let mbuf = pool.alloc();
659 assert!(mbuf.is_ok());
660 }
661
662 #[test]
663 fn test_mempool_alloc_bulk_zero() {
664 let pool = Mempool::create("bulk_zero_pool", 128, 32, 2048, -1).unwrap();
665 let mbufs = pool.alloc_bulk(0);
666 assert!(mbufs.is_ok());
667 assert!(mbufs.unwrap().is_empty());
668 }
669
670 #[test]
671 fn test_mempool_alloc_bulk() {
672 let pool = Mempool::create("bulk_pool", 128, 32, 2048, -1).unwrap();
673 let mbufs = pool.alloc_bulk(4);
674 assert!(mbufs.is_ok());
675 let mbufs = mbufs.unwrap();
676 assert_eq!(mbufs.len(), 4);
677 }
678
679 #[test]
680 fn test_mempool_available_count() {
681 let pool = Mempool::create("avail_pool", 128, 32, 2048, -1).unwrap();
682 let count = pool.available_count();
683 assert!(count > 0);
685 }
686
687 #[test]
688 fn test_mempool_in_use_count() {
689 let pool = Mempool::create("inuse_pool", 128, 32, 2048, -1).unwrap();
690 let count = pool.in_use_count();
691 assert_eq!(count, 0);
693 }
694
695 #[test]
696 fn test_mempool_is_full() {
697 let pool = Mempool::create("full_pool", 128, 32, 2048, -1).unwrap();
698 assert!(pool.is_full());
700 }
701
702 #[test]
703 fn test_mempool_is_empty() {
704 let pool = Mempool::create("empty_pool", 128, 32, 2048, -1).unwrap();
705 assert!(!pool.is_empty());
707 }
708
709 #[test]
710 fn test_mempool_as_raw() {
711 let pool = Mempool::create("raw_pool", 128, 32, 2048, -1).unwrap();
712 let raw = pool.as_raw();
713 assert!(!raw.is_null());
714 }
715
716 #[test]
721 fn test_mbuf_data_offset() {
722 let pool = Mempool::create("offset_pool", 128, 32, 2048, -1).unwrap();
723 let mbuf = pool.alloc().unwrap();
724 let offset = mbuf.data_offset();
726 assert!(offset >= 0);
727 }
728
729 #[test]
730 fn test_mbuf_packet_len() {
731 let pool = Mempool::create("pktlen_pool", 128, 32, 2048, -1).unwrap();
732 let mbuf = pool.alloc().unwrap();
733 assert_eq!(mbuf.packet_len(), 0);
735 }
736
737 #[test]
738 fn test_mbuf_data_len() {
739 let pool = Mempool::create("datalen_pool", 128, 32, 2048, -1).unwrap();
740 let mbuf = pool.alloc().unwrap();
741 assert_eq!(mbuf.data_len(), 0);
743 }
744
745 #[test]
746 fn test_mbuf_set_lengths() {
747 let pool = Mempool::create("setlen_pool", 128, 32, 2048, -1).unwrap();
748 let mut mbuf = pool.alloc().unwrap();
749
750 mbuf.set_data_len(100);
751 assert_eq!(mbuf.data_len(), 100);
752
753 mbuf.set_packet_len(100);
754 assert_eq!(mbuf.packet_len(), 100);
755 }
756
757 #[test]
758 fn test_mbuf_into_raw() {
759 let pool = Mempool::create("intoraw_pool", 128, 32, 2048, -1).unwrap();
760 let mbuf = pool.alloc().unwrap();
761 let raw = mbuf.into_raw();
762 assert!(!raw.is_null());
763
764 unsafe {
766 dpdk_sys::rte_pktmbuf_free(raw);
767 }
768 }
769
770 #[test]
771 fn test_mbuf_from_raw_null() {
772 let result = unsafe { Mbuf::from_raw(std::ptr::null_mut()) };
773 assert!(result.is_none());
774 }
775}