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
115impl Drop for Mbuf {
116 fn drop(&mut self) {
117 unsafe {
118 dpdk_sys::rte_pktmbuf_free(self.raw.as_ptr());
119 }
120 }
121}
122
123pub struct Mempool {
128 raw: NonNull<dpdk_sys::rte_mempool>,
129 name: String,
130}
131
132unsafe impl Send for Mempool {}
134unsafe impl Sync for Mempool {}
135
136pub const DEFAULT_POOL_SIZE: u32 = 8192;
138
139pub const DEFAULT_CACHE_SIZE: u32 = 256;
141
142pub const DEFAULT_DATA_ROOM_SIZE: u16 = dpdk_sys::RTE_MBUF_DEFAULT_BUF_SIZE as u16;
144
145pub const MAX_MEMPOOL_NAME_LEN: usize = 32;
147
148#[derive(Debug, Clone)]
150pub struct MempoolConfig {
151 pub n: u32,
153 pub cache_size: u32,
155 pub data_room_size: u16,
157 pub socket_id: i32,
159}
160
161impl Default for MempoolConfig {
162 fn default() -> Self {
163 Self {
164 n: DEFAULT_POOL_SIZE,
165 cache_size: DEFAULT_CACHE_SIZE,
166 data_room_size: DEFAULT_DATA_ROOM_SIZE,
167 socket_id: dpdk_sys::SOCKET_ID_ANY,
168 }
169 }
170}
171
172impl MempoolConfig {
173 pub fn new() -> Self {
175 Self::default()
176 }
177
178 pub fn with_size(mut self, n: u32) -> Self {
180 self.n = n;
181 self
182 }
183
184 pub fn with_cache_size(mut self, cache_size: u32) -> Self {
186 self.cache_size = cache_size;
187 self
188 }
189
190 pub fn with_data_room_size(mut self, size: u16) -> Self {
192 self.data_room_size = size;
193 self
194 }
195
196 pub fn with_socket_id(mut self, socket_id: i32) -> Self {
198 self.socket_id = socket_id;
199 self
200 }
201}
202
203impl Mempool {
204 pub fn create(
221 name: &str,
222 n: u32,
223 cache_size: u32,
224 data_room_size: u16,
225 socket_id: i32,
226 ) -> DpdkResult<Self> {
227 if name.is_empty() {
229 return Err(DpdkError::InvalidName("mempool name cannot be empty".to_string()));
230 }
231 if name.len() > MAX_MEMPOOL_NAME_LEN {
232 return Err(DpdkError::InvalidName(format!(
233 "mempool name too long (max {} characters)",
234 MAX_MEMPOOL_NAME_LEN
235 )));
236 }
237
238 let c_name = CString::new(name).map_err(|_| {
240 DpdkError::InvalidName("mempool name contains null bytes".to_string())
241 })?;
242
243 let ptr = unsafe {
245 dpdk_sys::rte_pktmbuf_pool_create(
246 c_name.as_ptr(),
247 n,
248 cache_size,
249 0, data_room_size,
251 socket_id,
252 )
253 };
254
255 NonNull::new(ptr)
256 .map(|raw| Self {
257 raw,
258 name: name.to_string(),
259 })
260 .ok_or_else(|| {
261 let errno = unsafe { dpdk_sys::rte_errno() };
263 DpdkError::MempoolCreateFailed(format!(
264 "rte_pktmbuf_pool_create failed for '{}' (errno: {})",
265 name, errno
266 ))
267 })
268 }
269
270 pub fn create_with_config(name: &str, config: &MempoolConfig) -> DpdkResult<Self> {
277 Self::create(
278 name,
279 config.n,
280 config.cache_size,
281 config.data_room_size,
282 config.socket_id,
283 )
284 }
285
286 pub fn create_default(name: &str) -> DpdkResult<Self> {
288 Self::create_with_config(name, &MempoolConfig::default())
289 }
290
291 pub fn name(&self) -> &str {
293 &self.name
294 }
295
296 pub fn alloc(&self) -> DpdkResult<Mbuf> {
298 unsafe {
299 let ptr = dpdk_sys::rte_pktmbuf_alloc(self.raw.as_ptr());
300 Mbuf::from_raw(ptr).ok_or(DpdkError::MemoryAllocationFailed)
301 }
302 }
303
304 pub fn alloc_bulk(&self, count: usize) -> DpdkResult<Vec<Mbuf>> {
309 if count == 0 {
310 return Ok(Vec::new());
311 }
312
313 let mut ptrs: Vec<*mut dpdk_sys::rte_mbuf> =
314 vec![std::ptr::null_mut(); count];
315
316 let ret = unsafe {
317 dpdk_sys::rte_pktmbuf_alloc_bulk(
318 self.raw.as_ptr(),
319 ptrs.as_mut_ptr(),
320 count as u32,
321 )
322 };
323
324 if ret != 0 {
325 return Err(DpdkError::MemoryAllocationFailed);
326 }
327
328 let mbufs: Vec<Mbuf> = ptrs
329 .into_iter()
330 .filter_map(|ptr| unsafe { Mbuf::from_raw(ptr) })
331 .collect();
332
333 if mbufs.len() != count {
334 return Err(DpdkError::MemoryAllocationFailed);
337 }
338
339 Ok(mbufs)
340 }
341
342 pub fn available_count(&self) -> u32 {
344 unsafe { dpdk_sys::rte_mempool_avail_count(self.raw.as_ptr()) }
345 }
346
347 pub fn in_use_count(&self) -> u32 {
349 unsafe { dpdk_sys::rte_mempool_in_use_count(self.raw.as_ptr()) }
350 }
351
352 pub fn is_full(&self) -> bool {
354 unsafe { dpdk_sys::rte_mempool_full(self.raw.as_ptr()) != 0 }
355 }
356
357 pub fn is_empty(&self) -> bool {
359 unsafe { dpdk_sys::rte_mempool_empty(self.raw.as_ptr()) != 0 }
360 }
361
362 pub fn as_raw(&self) -> *mut dpdk_sys::rte_mempool {
364 self.raw.as_ptr()
365 }
366}
367
368impl Drop for Mempool {
369 fn drop(&mut self) {
370 unsafe {
371 dpdk_sys::rte_mempool_free(self.raw.as_ptr());
372 }
373 }
374}
375
376pub struct MbufBuilder {
378 data: Vec<u8>,
379}
380
381impl MbufBuilder {
382 pub fn new() -> Self {
383 Self { data: Vec::new() }
384 }
385
386 pub fn ethernet(mut self, dst_mac: [u8; 6], src_mac: [u8; 6], ethertype: u16) -> Self {
388 self.data.extend_from_slice(&dst_mac);
389 self.data.extend_from_slice(&src_mac);
390 self.data.extend_from_slice(ðertype.to_be_bytes());
391 self
392 }
393
394 pub fn ipv4(mut self, src: [u8; 4], dst: [u8; 4], protocol: u8, payload_len: u16) -> Self {
396 let total_len = 20 + payload_len;
397 self.data.push(0x45); self.data.push(0x00); self.data.extend_from_slice(&total_len.to_be_bytes());
400 self.data.extend_from_slice(&[0, 0]); self.data.extend_from_slice(&[0, 0]); self.data.push(64); self.data.push(protocol);
404 self.data.extend_from_slice(&[0, 0]); self.data.extend_from_slice(&src);
406 self.data.extend_from_slice(&dst);
407 self
408 }
409
410 pub fn udp(mut self, src_port: u16, dst_port: u16, payload_len: u16) -> Self {
412 let udp_len = 8 + payload_len;
413 self.data.extend_from_slice(&src_port.to_be_bytes());
414 self.data.extend_from_slice(&dst_port.to_be_bytes());
415 self.data.extend_from_slice(&udp_len.to_be_bytes());
416 self.data.extend_from_slice(&[0, 0]); self
418 }
419
420 pub fn payload(mut self, data: &[u8]) -> Self {
422 self.data.extend_from_slice(data);
423 self
424 }
425
426 pub fn build(self) -> Vec<u8> {
428 self.data
429 }
430}
431
432impl Default for MbufBuilder {
433 fn default() -> Self {
434 Self::new()
435 }
436}
437
438#[cfg(test)]
439mod tests {
440 use super::*;
441
442 #[test]
447 fn test_mbuf_builder() {
448 let frame = MbufBuilder::new()
449 .ethernet([0xff; 6], [0x00; 6], 0x0800)
450 .ipv4([192, 168, 1, 1], [192, 168, 1, 2], 17, 16)
451 .udp(12345, 9000, 8)
452 .payload(b"test")
453 .build();
454
455 assert_eq!(frame.len(), 14 + 20 + 8 + 4);
457 }
458
459 #[test]
460 fn test_mbuf_builder_empty() {
461 let frame = MbufBuilder::new().build();
462 assert!(frame.is_empty());
463 }
464
465 #[test]
466 fn test_mbuf_builder_payload_only() {
467 let payload = b"hello world";
468 let frame = MbufBuilder::new().payload(payload).build();
469 assert_eq!(frame.len(), payload.len());
470 assert_eq!(&frame, payload);
471 }
472
473 #[test]
474 fn test_mbuf_builder_ethernet_only() {
475 let frame = MbufBuilder::new()
476 .ethernet([0x01, 0x02, 0x03, 0x04, 0x05, 0x06], [0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f], 0x0800)
477 .build();
478
479 assert_eq!(frame.len(), 14);
481
482 assert_eq!(&frame[0..6], &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
484 assert_eq!(&frame[6..12], &[0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]);
486 assert_eq!(&frame[12..14], &[0x08, 0x00]);
488 }
489
490 #[test]
495 fn test_mempool_config_default() {
496 let config = MempoolConfig::default();
497 assert_eq!(config.n, DEFAULT_POOL_SIZE);
498 assert_eq!(config.cache_size, DEFAULT_CACHE_SIZE);
499 assert_eq!(config.data_room_size, DEFAULT_DATA_ROOM_SIZE);
500 assert_eq!(config.socket_id, dpdk_sys::SOCKET_ID_ANY);
501 }
502
503 #[test]
504 fn test_mempool_config_builder() {
505 let config = MempoolConfig::new()
506 .with_size(4096)
507 .with_cache_size(128)
508 .with_data_room_size(2048)
509 .with_socket_id(0);
510
511 assert_eq!(config.n, 4096);
512 assert_eq!(config.cache_size, 128);
513 assert_eq!(config.data_room_size, 2048);
514 assert_eq!(config.socket_id, 0);
515 }
516
517 #[test]
518 fn test_mempool_config_chaining() {
519 let config = MempoolConfig::new()
521 .with_size(1024)
522 .with_cache_size(64);
523
524 assert_eq!(config.n, 1024);
525 assert_eq!(config.cache_size, 64);
526 assert_eq!(config.data_room_size, DEFAULT_DATA_ROOM_SIZE);
528 }
529
530 #[test]
535 fn test_mempool_create() {
536 let pool = Mempool::create("test_pool", 128, 32, 2048, -1);
537 assert!(pool.is_ok());
538 let pool = pool.unwrap();
539 assert_eq!(pool.name(), "test_pool");
540 }
541
542 #[test]
543 fn test_mempool_create_with_config() {
544 let config = MempoolConfig::new().with_size(256).with_cache_size(64);
545 let pool = Mempool::create_with_config("config_pool", &config);
546 assert!(pool.is_ok());
547 let pool = pool.unwrap();
548 assert_eq!(pool.name(), "config_pool");
549 }
550
551 #[test]
552 fn test_mempool_create_default() {
553 let pool = Mempool::create_default("default_pool");
554 assert!(pool.is_ok());
555 let pool = pool.unwrap();
556 assert_eq!(pool.name(), "default_pool");
557 }
558
559 #[test]
560 fn test_mempool_create_empty_name() {
561 let result = Mempool::create("", 128, 32, 2048, -1);
562 assert!(result.is_err());
563 match result {
564 Err(DpdkError::InvalidName(msg)) => {
565 assert!(msg.contains("empty"));
566 }
567 _ => panic!("Expected InvalidName error"),
568 }
569 }
570
571 #[test]
572 fn test_mempool_create_name_too_long() {
573 let long_name = "a".repeat(MAX_MEMPOOL_NAME_LEN + 1);
574 let result = Mempool::create(&long_name, 128, 32, 2048, -1);
575 assert!(result.is_err());
576 match result {
577 Err(DpdkError::InvalidName(msg)) => {
578 assert!(msg.contains("too long"));
579 }
580 _ => panic!("Expected InvalidName error"),
581 }
582 }
583
584 #[test]
585 fn test_mempool_create_name_with_null() {
586 let result = Mempool::create("test\0pool", 128, 32, 2048, -1);
587 assert!(result.is_err());
588 match result {
589 Err(DpdkError::InvalidName(msg)) => {
590 assert!(msg.contains("null"));
591 }
592 _ => panic!("Expected InvalidName error"),
593 }
594 }
595
596 #[test]
597 fn test_mempool_name_max_length() {
598 let max_name = "a".repeat(MAX_MEMPOOL_NAME_LEN);
599 let result = Mempool::create(&max_name, 128, 32, 2048, -1);
600 assert!(result.is_ok());
601 }
602
603 #[test]
608 fn test_mempool_alloc() {
609 let pool = Mempool::create("alloc_pool", 128, 32, 2048, -1).unwrap();
610 let mbuf = pool.alloc();
611 assert!(mbuf.is_ok());
612 }
613
614 #[test]
615 fn test_mempool_alloc_bulk_zero() {
616 let pool = Mempool::create("bulk_zero_pool", 128, 32, 2048, -1).unwrap();
617 let mbufs = pool.alloc_bulk(0);
618 assert!(mbufs.is_ok());
619 assert!(mbufs.unwrap().is_empty());
620 }
621
622 #[test]
623 fn test_mempool_alloc_bulk() {
624 let pool = Mempool::create("bulk_pool", 128, 32, 2048, -1).unwrap();
625 let mbufs = pool.alloc_bulk(4);
626 assert!(mbufs.is_ok());
627 let mbufs = mbufs.unwrap();
628 assert_eq!(mbufs.len(), 4);
629 }
630
631 #[test]
632 fn test_mempool_available_count() {
633 let pool = Mempool::create("avail_pool", 128, 32, 2048, -1).unwrap();
634 let count = pool.available_count();
635 assert!(count > 0);
637 }
638
639 #[test]
640 fn test_mempool_in_use_count() {
641 let pool = Mempool::create("inuse_pool", 128, 32, 2048, -1).unwrap();
642 let count = pool.in_use_count();
643 assert_eq!(count, 0);
645 }
646
647 #[test]
648 fn test_mempool_is_full() {
649 let pool = Mempool::create("full_pool", 128, 32, 2048, -1).unwrap();
650 assert!(pool.is_full());
652 }
653
654 #[test]
655 fn test_mempool_is_empty() {
656 let pool = Mempool::create("empty_pool", 128, 32, 2048, -1).unwrap();
657 assert!(!pool.is_empty());
659 }
660
661 #[test]
662 fn test_mempool_as_raw() {
663 let pool = Mempool::create("raw_pool", 128, 32, 2048, -1).unwrap();
664 let raw = pool.as_raw();
665 assert!(!raw.is_null());
666 }
667
668 #[test]
673 fn test_mbuf_data_offset() {
674 let pool = Mempool::create("offset_pool", 128, 32, 2048, -1).unwrap();
675 let mbuf = pool.alloc().unwrap();
676 let offset = mbuf.data_offset();
678 assert!(offset >= 0);
679 }
680
681 #[test]
682 fn test_mbuf_packet_len() {
683 let pool = Mempool::create("pktlen_pool", 128, 32, 2048, -1).unwrap();
684 let mbuf = pool.alloc().unwrap();
685 assert_eq!(mbuf.packet_len(), 0);
687 }
688
689 #[test]
690 fn test_mbuf_data_len() {
691 let pool = Mempool::create("datalen_pool", 128, 32, 2048, -1).unwrap();
692 let mbuf = pool.alloc().unwrap();
693 assert_eq!(mbuf.data_len(), 0);
695 }
696
697 #[test]
698 fn test_mbuf_set_lengths() {
699 let pool = Mempool::create("setlen_pool", 128, 32, 2048, -1).unwrap();
700 let mut mbuf = pool.alloc().unwrap();
701
702 mbuf.set_data_len(100);
703 assert_eq!(mbuf.data_len(), 100);
704
705 mbuf.set_packet_len(100);
706 assert_eq!(mbuf.packet_len(), 100);
707 }
708
709 #[test]
710 fn test_mbuf_into_raw() {
711 let pool = Mempool::create("intoraw_pool", 128, 32, 2048, -1).unwrap();
712 let mbuf = pool.alloc().unwrap();
713 let raw = mbuf.into_raw();
714 assert!(!raw.is_null());
715
716 unsafe {
718 dpdk_sys::rte_pktmbuf_free(raw);
719 }
720 }
721
722 #[test]
723 fn test_mbuf_from_raw_null() {
724 let result = unsafe { Mbuf::from_raw(std::ptr::null_mut()) };
725 assert!(result.is_none());
726 }
727}