1use crate::error::{DpdkError, DpdkResult};
7use crate::mbuf::{Mbuf, Mempool};
8use std::ptr;
9
10pub const DEFAULT_RX_DESC: u16 = 1024;
12pub const DEFAULT_TX_DESC: u16 = 1024;
13
14pub const DEFAULT_BURST_SIZE: u16 = 32;
16
17#[derive(Debug, Clone, Copy, Default)]
19pub struct RxOffload {
20 pub vlan_strip: bool,
22 pub ipv4_cksum: bool,
24 pub udp_cksum: bool,
26 pub tcp_cksum: bool,
28}
29
30impl RxOffload {
31 pub fn to_flags(&self) -> u64 {
33 let mut flags = 0u64;
34 if self.vlan_strip {
35 flags |= dpdk_sys::RTE_ETH_RX_OFFLOAD_VLAN_STRIP as u64;
36 }
37 if self.ipv4_cksum {
38 flags |= dpdk_sys::RTE_ETH_RX_OFFLOAD_IPV4_CKSUM as u64;
39 }
40 if self.udp_cksum {
41 flags |= dpdk_sys::RTE_ETH_RX_OFFLOAD_UDP_CKSUM as u64;
42 }
43 if self.tcp_cksum {
44 flags |= dpdk_sys::RTE_ETH_RX_OFFLOAD_TCP_CKSUM as u64;
45 }
46 flags
47 }
48}
49
50#[derive(Debug, Clone, Copy, Default)]
52pub struct TxOffload {
53 pub vlan_insert: bool,
55 pub ipv4_cksum: bool,
57 pub udp_cksum: bool,
59 pub tcp_cksum: bool,
61}
62
63impl TxOffload {
64 pub fn to_flags(&self) -> u64 {
66 let mut flags = 0u64;
67 if self.vlan_insert {
68 flags |= dpdk_sys::RTE_ETH_TX_OFFLOAD_VLAN_INSERT as u64;
69 }
70 if self.ipv4_cksum {
71 flags |= dpdk_sys::RTE_ETH_TX_OFFLOAD_IPV4_CKSUM as u64;
72 }
73 if self.udp_cksum {
74 flags |= dpdk_sys::RTE_ETH_TX_OFFLOAD_UDP_CKSUM as u64;
75 }
76 if self.tcp_cksum {
77 flags |= dpdk_sys::RTE_ETH_TX_OFFLOAD_TCP_CKSUM as u64;
78 }
79 flags
80 }
81}
82
83#[derive(Debug, Clone)]
85pub struct PortConfig {
86 pub nb_rx_queues: u16,
88 pub nb_tx_queues: u16,
90 pub nb_rx_desc: u16,
92 pub nb_tx_desc: u16,
94 pub promiscuous: bool,
96 pub mtu: u32,
98 pub rx_offload: RxOffload,
100 pub tx_offload: TxOffload,
102}
103
104impl Default for PortConfig {
105 fn default() -> Self {
106 Self {
107 nb_rx_queues: 1,
108 nb_tx_queues: 1,
109 nb_rx_desc: DEFAULT_RX_DESC,
110 nb_tx_desc: DEFAULT_TX_DESC,
111 promiscuous: true,
112 mtu: 0,
113 rx_offload: RxOffload::default(),
114 tx_offload: TxOffload::default(),
115 }
116 }
117}
118
119impl PortConfig {
120 pub fn new() -> Self {
122 Self::default()
123 }
124
125 pub fn with_queues(mut self, rx: u16, tx: u16) -> Self {
127 self.nb_rx_queues = rx;
128 self.nb_tx_queues = tx;
129 self
130 }
131
132 pub fn with_descriptors(mut self, rx: u16, tx: u16) -> Self {
134 self.nb_rx_desc = rx;
135 self.nb_tx_desc = tx;
136 self
137 }
138
139 pub fn with_promiscuous(mut self, enable: bool) -> Self {
141 self.promiscuous = enable;
142 self
143 }
144
145 pub fn with_mtu(mut self, mtu: u32) -> Self {
147 self.mtu = mtu;
148 self
149 }
150
151 pub fn with_rx_offload(mut self, offload: RxOffload) -> Self {
153 self.rx_offload = offload;
154 self
155 }
156
157 pub fn with_tx_offload(mut self, offload: TxOffload) -> Self {
159 self.tx_offload = offload;
160 self
161 }
162
163 pub fn with_checksum_offload(mut self) -> Self {
165 self.rx_offload.ipv4_cksum = true;
166 self.rx_offload.udp_cksum = true;
167 self.rx_offload.tcp_cksum = true;
168 self.tx_offload.ipv4_cksum = true;
169 self.tx_offload.udp_cksum = true;
170 self.tx_offload.tcp_cksum = true;
171 self
172 }
173
174 pub fn with_vlan_offload(mut self) -> Self {
180 self.rx_offload.vlan_strip = true;
181 self.tx_offload.vlan_insert = true;
182 self
183 }
184}
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
188pub struct MacAddress(pub [u8; 6]);
189
190impl MacAddress {
191 pub fn new(bytes: [u8; 6]) -> Self {
193 Self(bytes)
194 }
195
196 pub fn broadcast() -> Self {
198 Self([0xff; 6])
199 }
200
201 pub fn zero() -> Self {
203 Self([0; 6])
204 }
205
206 pub fn as_bytes(&self) -> &[u8; 6] {
208 &self.0
209 }
210
211 pub fn octets(&self) -> [u8; 6] {
213 self.0
214 }
215
216 pub fn is_broadcast(&self) -> bool {
218 self.0 == [0xff; 6]
219 }
220
221 pub fn is_multicast(&self) -> bool {
223 (self.0[0] & 0x01) != 0
224 }
225
226 pub fn is_zero(&self) -> bool {
228 self.0 == [0; 6]
229 }
230}
231
232impl std::fmt::Display for MacAddress {
233 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234 write!(
235 f,
236 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
237 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
238 )
239 }
240}
241
242#[derive(Debug, Clone, Copy, Default)]
244pub struct LinkStatus {
245 pub speed: u32,
247 pub full_duplex: bool,
249 pub autoneg: bool,
251 pub link_up: bool,
253}
254
255#[derive(Debug, Clone, Copy, Default)]
257pub struct PortStats {
258 pub rx_packets: u64,
260 pub tx_packets: u64,
262 pub rx_bytes: u64,
264 pub tx_bytes: u64,
266 pub rx_missed: u64,
270 pub rx_errors: u64,
272 pub tx_errors: u64,
274 pub rx_nombuf: u64,
277}
278
279#[derive(Debug, Clone, Copy, Default)]
281pub struct DeviceCapabilities {
282 pub rx_offload_capa: u64,
284 pub tx_offload_capa: u64,
286 pub max_rx_queues: u16,
288 pub max_tx_queues: u16,
290}
291
292impl DeviceCapabilities {
293 pub fn supports_rx_ipv4_cksum(&self) -> bool {
295 (self.rx_offload_capa & dpdk_sys::RTE_ETH_RX_OFFLOAD_IPV4_CKSUM as u64) != 0
296 }
297
298 pub fn supports_rx_udp_cksum(&self) -> bool {
300 (self.rx_offload_capa & dpdk_sys::RTE_ETH_RX_OFFLOAD_UDP_CKSUM as u64) != 0
301 }
302
303 pub fn supports_tx_ipv4_cksum(&self) -> bool {
305 (self.tx_offload_capa & dpdk_sys::RTE_ETH_TX_OFFLOAD_IPV4_CKSUM as u64) != 0
306 }
307
308 pub fn supports_tx_udp_cksum(&self) -> bool {
310 (self.tx_offload_capa & dpdk_sys::RTE_ETH_TX_OFFLOAD_UDP_CKSUM as u64) != 0
311 }
312
313 pub fn supports_vlan_strip(&self) -> bool {
315 (self.rx_offload_capa & dpdk_sys::RTE_ETH_RX_OFFLOAD_VLAN_STRIP as u64) != 0
316 }
317
318 pub fn supports_vlan_insert(&self) -> bool {
320 (self.tx_offload_capa & dpdk_sys::RTE_ETH_TX_OFFLOAD_VLAN_INSERT as u64) != 0
321 }
322}
323
324pub struct Port {
326 port_id: u16,
327 config: PortConfig,
328 started: bool,
329 mac_address: MacAddress,
330 capabilities: DeviceCapabilities,
332 active_rx_offload: u64,
334 active_tx_offload: u64,
335}
336
337impl Port {
338 pub fn count_available() -> u16 {
340 unsafe { dpdk_sys::rte_eth_dev_count_avail() }
341 }
342
343 pub fn is_valid(port_id: u16) -> bool {
345 port_id < Self::count_available()
346 }
347
348 pub fn init(port_id: u16, config: PortConfig, mempool: &Mempool) -> DpdkResult<Self> {
356 if !Self::is_valid(port_id) {
358 return Err(DpdkError::InvalidPortId(port_id));
359 }
360
361 let mut dev_info = dpdk_sys::rte_eth_dev_info::default();
363 let ret = unsafe { dpdk_sys::rte_eth_dev_info_get(port_id, &mut dev_info) };
364 if ret != 0 {
365 return Err(DpdkError::PortConfigFailed(ret));
366 }
367
368 let capabilities = DeviceCapabilities {
370 rx_offload_capa: dev_info.rx_offload_capa,
371 tx_offload_capa: dev_info.tx_offload_capa,
372 max_rx_queues: dev_info.max_rx_queues,
373 max_tx_queues: dev_info.max_tx_queues,
374 };
375
376 let nb_rx_queues = config.nb_rx_queues.min(dev_info.max_rx_queues);
378 let nb_tx_queues = config.nb_tx_queues.min(dev_info.max_tx_queues);
379
380 let requested_rx_offload = config.rx_offload.to_flags();
382 let requested_tx_offload = config.tx_offload.to_flags();
383 let active_rx_offload = requested_rx_offload & dev_info.rx_offload_capa;
384 let active_tx_offload = requested_tx_offload & dev_info.tx_offload_capa;
385
386 if active_rx_offload != requested_rx_offload {
388 let unsupported = requested_rx_offload & !dev_info.rx_offload_capa;
389 eprintln!("Warning: Some RX offloads not supported by device (flags: 0x{:x})", unsupported);
390 }
391 if active_tx_offload != requested_tx_offload {
392 let unsupported = requested_tx_offload & !dev_info.tx_offload_capa;
393 eprintln!("Warning: Some TX offloads not supported by device (flags: 0x{:x})", unsupported);
394 }
395
396 let eth_conf = dpdk_sys::rte_eth_conf {
398 rxmode: dpdk_sys::rte_eth_rxmode {
399 mtu: config.mtu,
400 offloads: active_rx_offload,
401 ..Default::default()
402 },
403 txmode: dpdk_sys::rte_eth_txmode {
404 offloads: active_tx_offload,
405 ..Default::default()
406 },
407 ..Default::default()
408 };
409
410 let ret = unsafe {
411 dpdk_sys::rte_eth_dev_configure(port_id, nb_rx_queues, nb_tx_queues, ð_conf)
412 };
413 if ret != 0 {
414 return Err(DpdkError::PortConfigFailed(ret));
415 }
416
417 let socket_id = unsafe { dpdk_sys::rte_socket_id() };
419
420 for queue_id in 0..nb_rx_queues {
422 let ret = unsafe {
423 dpdk_sys::rte_eth_rx_queue_setup(
424 port_id,
425 queue_id,
426 config.nb_rx_desc,
427 socket_id as u32,
428 ptr::null(),
429 mempool.as_raw(),
430 )
431 };
432 if ret != 0 {
433 return Err(DpdkError::PortConfigFailed(ret));
434 }
435 }
436
437 for queue_id in 0..nb_tx_queues {
439 let ret = unsafe {
440 dpdk_sys::rte_eth_tx_queue_setup(
441 port_id,
442 queue_id,
443 config.nb_tx_desc,
444 socket_id as u32,
445 ptr::null(),
446 )
447 };
448 if ret != 0 {
449 return Err(DpdkError::PortConfigFailed(ret));
450 }
451 }
452
453 let mut mac_addr = dpdk_sys::rte_ether_addr::default();
455 let ret = unsafe { dpdk_sys::rte_eth_macaddr_get(port_id, &mut mac_addr) };
456 if ret != 0 {
457 return Err(DpdkError::PortConfigFailed(ret));
458 }
459
460 let mac_address = MacAddress::new(mac_addr.addr_bytes);
461
462 Ok(Self {
463 port_id,
464 config: PortConfig {
465 nb_rx_queues,
466 nb_tx_queues,
467 ..config
468 },
469 started: false,
470 mac_address,
471 capabilities,
472 active_rx_offload,
473 active_tx_offload,
474 })
475 }
476
477 pub fn new(port_id: u16) -> DpdkResult<Self> {
479 if !Self::is_valid(port_id) {
480 return Err(DpdkError::InvalidPortId(port_id));
481 }
482
483 Ok(Self {
484 port_id,
485 config: PortConfig::default(),
486 started: false,
487 mac_address: MacAddress::default(),
488 capabilities: DeviceCapabilities::default(),
489 active_rx_offload: 0,
490 active_tx_offload: 0,
491 })
492 }
493
494 pub fn capabilities(&self) -> &DeviceCapabilities {
496 &self.capabilities
497 }
498
499 pub fn numa_node(&self) -> i32 {
505 unsafe { dpdk_sys::rte_eth_dev_socket_id(self.port_id) }
506 }
507
508 pub fn active_rx_offload(&self) -> u64 {
510 self.active_rx_offload
511 }
512
513 pub fn active_tx_offload(&self) -> u64 {
515 self.active_tx_offload
516 }
517
518 pub fn is_rx_offload_active(&self, offload: u64) -> bool {
520 (self.active_rx_offload & offload) != 0
521 }
522
523 pub fn is_tx_offload_active(&self, offload: u64) -> bool {
525 (self.active_tx_offload & offload) != 0
526 }
527
528 pub fn port_id(&self) -> u16 {
530 self.port_id
531 }
532
533 pub fn mac_address(&self) -> MacAddress {
535 self.mac_address
536 }
537
538 pub fn config(&self) -> &PortConfig {
540 &self.config
541 }
542
543 pub fn is_started(&self) -> bool {
545 self.started
546 }
547
548 pub fn start(&mut self) -> DpdkResult<()> {
550 if self.started {
551 return Ok(());
552 }
553
554 let ret = unsafe { dpdk_sys::rte_eth_dev_start(self.port_id) };
555 if ret != 0 {
556 return Err(DpdkError::PortConfigFailed(ret));
557 }
558
559 if self.config.promiscuous {
561 unsafe {
562 dpdk_sys::rte_eth_promiscuous_enable(self.port_id);
563 }
564 }
565
566 self.started = true;
567 Ok(())
568 }
569
570 pub fn stop(&mut self) -> DpdkResult<()> {
572 if !self.started {
573 return Ok(());
574 }
575
576 let ret = unsafe { dpdk_sys::rte_eth_dev_stop(self.port_id) };
577 if ret != 0 {
578 return Err(DpdkError::PortConfigFailed(ret));
579 }
580
581 self.started = false;
582 Ok(())
583 }
584
585 pub fn link_status(&self) -> LinkStatus {
587 let mut link = dpdk_sys::rte_eth_link::default();
588 unsafe {
589 dpdk_sys::rte_eth_link_get_nowait(self.port_id, &mut link);
590 }
591
592 LinkStatus {
593 speed: link.link_speed,
594 full_duplex: link.link_duplex() != 0,
595 autoneg: link.link_autoneg() != 0,
596 link_up: link.link_status() != 0,
597 }
598 }
599
600 pub fn stats(&self) -> DpdkResult<PortStats> {
602 let mut stats = dpdk_sys::rte_eth_stats::default();
603 let ret = unsafe { dpdk_sys::rte_eth_stats_get(self.port_id, &mut stats) };
604 if ret != 0 {
605 return Err(DpdkError::PortConfigFailed(ret));
606 }
607
608 Ok(PortStats {
609 rx_packets: stats.ipackets,
610 tx_packets: stats.opackets,
611 rx_bytes: stats.ibytes,
612 tx_bytes: stats.obytes,
613 rx_missed: stats.imissed,
614 rx_errors: stats.ierrors,
615 tx_errors: stats.oerrors,
616 rx_nombuf: stats.rx_nombuf,
617 })
618 }
619
620 pub fn reset_stats(&self) -> DpdkResult<()> {
622 let ret = unsafe { dpdk_sys::rte_eth_stats_reset(self.port_id) };
623 if ret != 0 {
624 return Err(DpdkError::PortConfigFailed(ret));
625 }
626 Ok(())
627 }
628
629 pub fn rx_burst(&self, queue_id: u16, max_packets: u16) -> DpdkResult<Vec<Mbuf>> {
634 if !self.started {
635 return Ok(Vec::new());
636 }
637
638 let mut rx_pkts: Vec<*mut dpdk_sys::rte_mbuf> = vec![ptr::null_mut(); max_packets as usize];
639
640 let nb_rx = unsafe {
641 dpdk_sys::rte_eth_rx_burst(
642 self.port_id,
643 queue_id,
644 rx_pkts.as_mut_ptr(),
645 max_packets,
646 )
647 };
648
649 let mut mbufs = Vec::with_capacity(nb_rx as usize);
650 for i in 0..nb_rx as usize {
651 if let Some(mbuf) = unsafe { Mbuf::from_raw(rx_pkts[i]) } {
652 mbufs.push(mbuf);
653 }
654 }
655
656 Ok(mbufs)
657 }
658
659 pub fn tx_burst(&self, queue_id: u16, packets: &mut Vec<Mbuf>) -> DpdkResult<u16> {
664 if !self.started || packets.is_empty() {
665 return Ok(0);
666 }
667
668 let mut tx_pkts: Vec<*mut dpdk_sys::rte_mbuf> = packets
670 .iter()
671 .map(|m| m.as_raw())
672 .collect();
673
674 let nb_tx = unsafe {
675 dpdk_sys::rte_eth_tx_burst(
676 self.port_id,
677 queue_id,
678 tx_pkts.as_mut_ptr(),
679 tx_pkts.len() as u16,
680 )
681 };
682
683 for mbuf in packets.drain(..nb_tx as usize) {
686 std::mem::forget(mbuf);
687 }
688
689 Ok(nb_tx)
690 }
691
692 pub fn set_promiscuous(&mut self, enable: bool) -> DpdkResult<()> {
701 let ret = if enable {
702 unsafe { dpdk_sys::rte_eth_promiscuous_enable(self.port_id) }
703 } else {
704 unsafe { dpdk_sys::rte_eth_promiscuous_disable(self.port_id) }
705 };
706
707 if ret != 0 {
708 return Err(DpdkError::PortConfigFailed(ret));
709 }
710
711 self.config.promiscuous = enable;
712 Ok(())
713 }
714
715 pub fn is_promiscuous(&self) -> bool {
717 unsafe { dpdk_sys::rte_eth_promiscuous_get(self.port_id) != 0 }
718 }
719
720 pub fn set_allmulticast(&self, enable: bool) -> DpdkResult<()> {
729 let ret = if enable {
730 unsafe { dpdk_sys::rte_eth_allmulticast_enable(self.port_id) }
731 } else {
732 unsafe { dpdk_sys::rte_eth_allmulticast_disable(self.port_id) }
733 };
734
735 if ret != 0 {
736 return Err(DpdkError::PortConfigFailed(ret));
737 }
738 Ok(())
739 }
740
741 pub fn is_allmulticast(&self) -> bool {
743 unsafe { dpdk_sys::rte_eth_allmulticast_get(self.port_id) != 0 }
744 }
745
746 pub fn set_multicast_addrs(&self, addrs: &[MacAddress]) -> DpdkResult<()> {
755 if addrs.is_empty() {
756 let ret = unsafe {
758 dpdk_sys::rte_eth_dev_set_mc_addr_list(
759 self.port_id,
760 ptr::null_mut(),
761 0,
762 )
763 };
764 if ret != 0 {
765 return Err(DpdkError::PortConfigFailed(ret));
766 }
767 return Ok(());
768 }
769
770 let mut mc_addrs: Vec<dpdk_sys::rte_ether_addr> = addrs
772 .iter()
773 .map(|mac| dpdk_sys::rte_ether_addr {
774 addr_bytes: mac.octets(),
775 })
776 .collect();
777
778 let ret = unsafe {
779 dpdk_sys::rte_eth_dev_set_mc_addr_list(
780 self.port_id,
781 mc_addrs.as_mut_ptr(),
782 mc_addrs.len() as u32,
783 )
784 };
785
786 if ret != 0 {
787 return Err(DpdkError::PortConfigFailed(ret));
788 }
789 Ok(())
790 }
791}
792
793impl Drop for Port {
794 fn drop(&mut self) {
795 if self.started {
796 let _ = self.stop();
797 }
798 unsafe {
799 dpdk_sys::rte_eth_dev_close(self.port_id);
800 }
801 }
802}
803
804#[cfg(test)]
809mod tests {
810 use super::*;
811
812 #[test]
813 fn test_mac_address_display() {
814 let mac = MacAddress::new([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
815 assert_eq!(mac.to_string(), "02:00:00:00:00:01");
816 }
817
818 #[test]
819 fn test_mac_address_broadcast() {
820 let broadcast = MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
821 assert!(broadcast.is_broadcast());
822 assert!(broadcast.is_multicast());
823
824 let unicast = MacAddress::new([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
825 assert!(!unicast.is_broadcast());
826 assert!(!unicast.is_multicast());
827 }
828
829 #[test]
830 fn test_mac_address_multicast() {
831 let multicast = MacAddress::new([0x01, 0x00, 0x5e, 0x00, 0x00, 0x01]);
833 assert!(multicast.is_multicast());
834 assert!(!multicast.is_broadcast());
835 }
836
837 #[test]
838 fn test_mac_address_zero() {
839 let zero = MacAddress::default();
840 assert!(zero.is_zero());
841
842 let non_zero = MacAddress::new([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
843 assert!(!non_zero.is_zero());
844 }
845
846 #[test]
847 fn test_port_config_default() {
848 let config = PortConfig::default();
849 assert_eq!(config.nb_rx_queues, 1);
850 assert_eq!(config.nb_tx_queues, 1);
851 assert_eq!(config.nb_rx_desc, DEFAULT_RX_DESC);
852 assert_eq!(config.nb_tx_desc, DEFAULT_TX_DESC);
853 assert!(config.promiscuous);
854 }
855
856 #[test]
857 fn test_link_status_default() {
858 let status = LinkStatus::default();
859 assert_eq!(status.speed, 0);
860 assert!(!status.full_duplex);
861 assert!(!status.link_up);
862 }
863
864 #[test]
865 fn test_port_stats_default() {
866 let stats = PortStats::default();
867 assert_eq!(stats.rx_packets, 0);
868 assert_eq!(stats.tx_packets, 0);
869 assert_eq!(stats.rx_bytes, 0);
870 assert_eq!(stats.tx_bytes, 0);
871 }
872
873 #[test]
874 fn test_port_count_available() {
875 let count = Port::count_available();
877 assert!(count >= 1);
878 }
879
880 #[test]
881 fn test_port_is_valid() {
882 assert!(Port::is_valid(0));
884 assert!(!Port::is_valid(100));
886 }
887
888 #[test]
889 fn test_port_new() {
890 let port = Port::new(0);
891 assert!(port.is_ok());
892 let port = port.unwrap();
893 assert_eq!(port.port_id(), 0);
894 assert!(!port.is_started());
895 }
896
897 #[test]
898 fn test_port_new_invalid() {
899 let port = Port::new(100);
900 assert!(port.is_err());
901 match port {
902 Err(DpdkError::InvalidPortId(id)) => assert_eq!(id, 100),
903 _ => panic!("Expected InvalidPortId error"),
904 }
905 }
906
907 #[test]
908 fn test_port_start_stop() {
909 let mut port = Port::new(0).unwrap();
910
911 assert!(port.start().is_ok());
913 assert!(port.is_started());
914
915 assert!(port.start().is_ok());
917
918 assert!(port.stop().is_ok());
920 assert!(!port.is_started());
921
922 assert!(port.stop().is_ok());
924 }
925
926 #[test]
927 fn test_port_link_status() {
928 let port = Port::new(0).unwrap();
929 let status = port.link_status();
930 assert!(status.link_up);
932 assert_eq!(status.speed, 10000);
933 }
934
935 #[test]
936 fn test_port_stats() {
937 let port = Port::new(0).unwrap();
938 let stats = port.stats();
939 assert!(stats.is_ok());
940 let stats = stats.unwrap();
941 assert_eq!(stats.rx_packets, 0);
942 assert_eq!(stats.tx_packets, 0);
943 }
944
945 #[test]
946 fn test_port_reset_stats() {
947 let port = Port::new(0).unwrap();
948 assert!(port.reset_stats().is_ok());
949 }
950
951 #[test]
952 fn test_port_rx_burst_not_started() {
953 let port = Port::new(0).unwrap();
954 let packets = port.rx_burst(0, 32);
955 assert!(packets.is_ok());
956 assert!(packets.unwrap().is_empty()); }
958
959 #[test]
960 fn test_port_tx_burst_not_started() {
961 let port = Port::new(0).unwrap();
962 let mut packets: Vec<Mbuf> = Vec::new();
963 let sent = port.tx_burst(0, &mut packets);
964 assert!(sent.is_ok());
965 assert_eq!(sent.unwrap(), 0); }
967}