Skip to main content

dpdk_sys/
stubs.rs

1//! Stub implementations of DPDK functions and types
2//!
3//! These stubs allow the crate to compile and run without DPDK installed.
4//! They provide the same API surface but don't perform actual packet I/O.
5
6use libc::{c_char, c_int, c_uint, c_void};
7use std::ptr;
8
9// ============================================================================
10// Constants
11// ============================================================================
12
13pub const RTE_MAX_ETHPORTS: usize = 32;
14pub const RTE_MAX_LCORE: usize = 128;
15pub const RTE_ETHER_ADDR_LEN: usize = 6;
16pub const RTE_ETHER_TYPE_IPV4: u16 = 0x0800;
17pub const RTE_ETHER_TYPE_IPV6: u16 = 0x86DD;
18pub const RTE_ETHER_TYPE_ARP: u16 = 0x0806;
19pub const RTE_ETHER_TYPE_VLAN: u16 = 0x8100;
20
21pub const RTE_MBUF_DEFAULT_BUF_SIZE: u16 = 2048 + 128; // RTE_PKTMBUF_HEADROOM
22pub const RTE_PKTMBUF_HEADROOM: u16 = 128;
23
24pub const RTE_ETH_TX_OFFLOAD_VLAN_INSERT: u64 = 0x00000001;
25pub const RTE_ETH_TX_OFFLOAD_IPV4_CKSUM: u64 = 0x00000002;
26pub const RTE_ETH_TX_OFFLOAD_UDP_CKSUM: u64 = 0x00000004;
27pub const RTE_ETH_TX_OFFLOAD_TCP_CKSUM: u64 = 0x00000008;
28
29pub const RTE_ETH_RX_OFFLOAD_VLAN_STRIP: u64 = 0x00000001;
30pub const RTE_ETH_RX_OFFLOAD_IPV4_CKSUM: u64 = 0x00000002;
31pub const RTE_ETH_RX_OFFLOAD_UDP_CKSUM: u64 = 0x00000004;
32pub const RTE_ETH_RX_OFFLOAD_TCP_CKSUM: u64 = 0x00000008;
33
34// Error codes
35pub const RTE_ERRNO_BASE: c_int = 1000;
36
37// NUMA socket constants
38pub const SOCKET_ID_ANY: c_int = -1;
39
40// ============================================================================
41// Core Types
42// ============================================================================
43
44/// Ethernet address (MAC address)
45#[repr(C)]
46#[derive(Debug, Clone, Copy, Default)]
47pub struct rte_ether_addr {
48    pub addr_bytes: [u8; RTE_ETHER_ADDR_LEN],
49}
50
51/// Ethernet header
52#[repr(C, packed)]
53#[derive(Debug, Clone, Copy, Default)]
54pub struct rte_ether_hdr {
55    pub dst_addr: rte_ether_addr,
56    pub src_addr: rte_ether_addr,
57    pub ether_type: u16,
58}
59
60/// IPv4 header
61#[repr(C, packed)]
62#[derive(Debug, Clone, Copy, Default)]
63pub struct rte_ipv4_hdr {
64    pub version_ihl: u8,
65    pub type_of_service: u8,
66    pub total_length: u16,
67    pub packet_id: u16,
68    pub fragment_offset: u16,
69    pub time_to_live: u8,
70    pub next_proto_id: u8,
71    pub hdr_checksum: u16,
72    pub src_addr: u32,
73    pub dst_addr: u32,
74}
75
76/// UDP header
77#[repr(C, packed)]
78#[derive(Debug, Clone, Copy, Default)]
79pub struct rte_udp_hdr {
80    pub src_port: u16,
81    pub dst_port: u16,
82    pub dgram_len: u16,
83    pub dgram_cksum: u16,
84}
85
86/// TCP header
87#[repr(C, packed)]
88#[derive(Debug, Clone, Copy, Default)]
89pub struct rte_tcp_hdr {
90    pub src_port: u16,
91    pub dst_port: u16,
92    pub sent_seq: u32,
93    pub recv_ack: u32,
94    pub data_off: u8,
95    pub tcp_flags: u8,
96    pub rx_win: u16,
97    pub cksum: u16,
98    pub tcp_urp: u16,
99}
100
101// ============================================================================
102// Memory Buffer (mbuf) Types
103// ============================================================================
104
105/// Memory buffer for packet data
106#[repr(C)]
107#[derive(Debug)]
108pub struct rte_mbuf {
109    pub buf_addr: *mut c_void,
110    pub buf_iova: u64,
111
112    // First cache line
113    pub data_off: u16,
114    pub refcnt: u16,
115    pub nb_segs: u16,
116    pub port: u16,
117    pub ol_flags: u64,
118
119    // Packet metadata
120    pub packet_type: u32,
121    pub pkt_len: u32,
122    pub data_len: u16,
123    pub vlan_tci: u16,
124
125    // Hash
126    pub hash: rte_mbuf_hash,
127
128    pub vlan_tci_outer: u16,
129    pub buf_len: u16,
130
131    pub pool: *mut rte_mempool,
132
133    // Second cache line
134    pub next: *mut rte_mbuf,
135
136    // Tx offload
137    pub tx_offload: u64,
138
139    pub priv_size: u16,
140    pub timesync: u16,
141    pub seqn: u32,
142
143    pub dynfield1: [u64; 2],
144}
145
146impl Default for rte_mbuf {
147    fn default() -> Self {
148        Self {
149            buf_addr: ptr::null_mut(),
150            buf_iova: 0,
151            data_off: RTE_PKTMBUF_HEADROOM,
152            refcnt: 1,
153            nb_segs: 1,
154            port: 0,
155            ol_flags: 0,
156            packet_type: 0,
157            pkt_len: 0,
158            data_len: 0,
159            vlan_tci: 0,
160            hash: rte_mbuf_hash::default(),
161            vlan_tci_outer: 0,
162            buf_len: 0,
163            pool: ptr::null_mut(),
164            next: ptr::null_mut(),
165            tx_offload: 0,
166            priv_size: 0,
167            timesync: 0,
168            seqn: 0,
169            dynfield1: [0; 2],
170        }
171    }
172}
173
174/// Hash union for rte_mbuf
175#[repr(C)]
176#[derive(Debug, Clone, Copy, Default)]
177pub struct rte_mbuf_hash {
178    pub rss: u32,
179}
180
181// ============================================================================
182// Memory Pool Types
183// ============================================================================
184
185/// Memory pool (simplified stub version for testing)
186#[repr(C)]
187#[derive(Debug, Default)]
188pub struct rte_mempool {
189    /// Pool name
190    pub name: [c_char; 32],
191    /// Total size of the mempool
192    pub size: c_uint,
193    /// Number of elements populated
194    pub populated_size: c_uint,
195    /// Element size
196    pub elt_size: c_uint,
197    /// Flags
198    pub flags: c_uint,
199}
200
201/// Memory pool cache (opaque)
202#[repr(C)]
203pub struct rte_mempool_cache {
204    _private: [u8; 0],
205}
206
207// ============================================================================
208// Ethernet Device Types
209// ============================================================================
210
211/// Ethernet device info
212#[repr(C)]
213#[derive(Debug)]
214pub struct rte_eth_dev_info {
215    pub device: *mut c_void,
216    pub driver_name: *const c_char,
217    pub if_index: c_uint,
218    pub min_mtu: u16,
219    pub max_mtu: u16,
220    pub dev_flags: *const u32,
221    pub min_rx_bufsize: u32,
222    pub max_rx_pktlen: u32,
223    pub max_lro_pkt_size: u32,
224    pub max_rx_queues: u16,
225    pub max_tx_queues: u16,
226    pub max_mac_addrs: u32,
227    pub max_vfs: u16,
228    pub max_vmdq_pools: u16,
229    pub rx_offload_capa: u64,
230    pub tx_offload_capa: u64,
231    pub rx_queue_offload_capa: u64,
232    pub tx_queue_offload_capa: u64,
233    pub reta_size: u16,
234    pub hash_key_size: u8,
235    pub flow_type_rss_offloads: u64,
236    pub default_rxconf: rte_eth_rxconf,
237    pub default_txconf: rte_eth_txconf,
238    pub vmdq_queue_base: u16,
239    pub vmdq_queue_num: u16,
240    pub vmdq_pool_base: u16,
241    pub rx_desc_lim: rte_eth_desc_lim,
242    pub tx_desc_lim: rte_eth_desc_lim,
243    pub speed_capa: u32,
244    pub nb_rx_queues: u16,
245    pub nb_tx_queues: u16,
246    pub dev_capa: u64,
247}
248
249impl Default for rte_eth_dev_info {
250    fn default() -> Self {
251        Self {
252            device: ptr::null_mut(),
253            driver_name: ptr::null(),
254            if_index: 0,
255            min_mtu: 0,
256            max_mtu: 0,
257            dev_flags: ptr::null(),
258            min_rx_bufsize: 0,
259            max_rx_pktlen: 0,
260            max_lro_pkt_size: 0,
261            max_rx_queues: 0,
262            max_tx_queues: 0,
263            max_mac_addrs: 0,
264            max_vfs: 0,
265            max_vmdq_pools: 0,
266            rx_offload_capa: 0,
267            tx_offload_capa: 0,
268            rx_queue_offload_capa: 0,
269            tx_queue_offload_capa: 0,
270            reta_size: 0,
271            hash_key_size: 0,
272            flow_type_rss_offloads: 0,
273            default_rxconf: rte_eth_rxconf::default(),
274            default_txconf: rte_eth_txconf::default(),
275            vmdq_queue_base: 0,
276            vmdq_queue_num: 0,
277            vmdq_pool_base: 0,
278            rx_desc_lim: rte_eth_desc_lim::default(),
279            tx_desc_lim: rte_eth_desc_lim::default(),
280            speed_capa: 0,
281            nb_rx_queues: 0,
282            nb_tx_queues: 0,
283            dev_capa: 0,
284        }
285    }
286}
287
288/// Ethernet device configuration
289#[repr(C)]
290#[derive(Debug, Default, Clone)]
291pub struct rte_eth_conf {
292    pub link_speeds: u32,
293    pub rxmode: rte_eth_rxmode,
294    pub txmode: rte_eth_txmode,
295    pub lpbk_mode: u32,
296    pub rx_adv_conf: rte_eth_rx_adv_conf,
297    pub tx_adv_conf: rte_eth_tx_adv_conf,
298    pub dcb_capability_en: u32,
299    pub intr_conf: rte_eth_intr_conf,
300}
301
302#[repr(C)]
303#[derive(Debug, Clone)]
304pub struct rte_eth_rxmode {
305    pub mq_mode: u32,
306    pub mtu: u32,
307    pub max_lro_pkt_size: u32,
308    pub offloads: u64,
309    pub reserved_64s: [u64; 2],
310    pub reserved_ptrs: [*mut c_void; 2],
311}
312
313impl Default for rte_eth_rxmode {
314    fn default() -> Self {
315        Self {
316            mq_mode: 0,
317            mtu: 0,
318            max_lro_pkt_size: 0,
319            offloads: 0,
320            reserved_64s: [0; 2],
321            reserved_ptrs: [ptr::null_mut(); 2],
322        }
323    }
324}
325
326#[repr(C)]
327#[derive(Debug, Clone)]
328pub struct rte_eth_txmode {
329    pub mq_mode: u32,
330    pub offloads: u64,
331    pub pvid: u16,
332    pub reserved_64s: [u64; 2],
333    pub reserved_ptrs: [*mut c_void; 2],
334}
335
336impl Default for rte_eth_txmode {
337    fn default() -> Self {
338        Self {
339            mq_mode: 0,
340            offloads: 0,
341            pvid: 0,
342            reserved_64s: [0; 2],
343            reserved_ptrs: [ptr::null_mut(); 2],
344        }
345    }
346}
347
348#[repr(C)]
349#[derive(Debug, Clone, Copy)]
350pub struct rte_eth_rxconf {
351    pub rx_thresh: rte_eth_thresh,
352    pub rx_free_thresh: u16,
353    pub rx_drop_en: u8,
354    pub rx_deferred_start: u8,
355    pub rx_nseg: u16,
356    pub share_group: u16,
357    pub share_qid: u16,
358    pub offloads: u64,
359    pub rx_seg: *mut c_void,
360    pub reserved_64s: [u64; 2],
361    pub reserved_ptrs: [*mut c_void; 2],
362}
363
364impl Default for rte_eth_rxconf {
365    fn default() -> Self {
366        Self {
367            rx_thresh: rte_eth_thresh::default(),
368            rx_free_thresh: 0,
369            rx_drop_en: 0,
370            rx_deferred_start: 0,
371            rx_nseg: 0,
372            share_group: 0,
373            share_qid: 0,
374            offloads: 0,
375            rx_seg: ptr::null_mut(),
376            reserved_64s: [0; 2],
377            reserved_ptrs: [ptr::null_mut(); 2],
378        }
379    }
380}
381
382#[repr(C)]
383#[derive(Debug, Clone, Copy)]
384pub struct rte_eth_txconf {
385    pub tx_thresh: rte_eth_thresh,
386    pub tx_rs_thresh: u16,
387    pub tx_free_thresh: u16,
388    pub tx_deferred_start: u8,
389    pub offloads: u64,
390    pub reserved_64s: [u64; 2],
391    pub reserved_ptrs: [*mut c_void; 2],
392}
393
394impl Default for rte_eth_txconf {
395    fn default() -> Self {
396        Self {
397            tx_thresh: rte_eth_thresh::default(),
398            tx_rs_thresh: 0,
399            tx_free_thresh: 0,
400            tx_deferred_start: 0,
401            offloads: 0,
402            reserved_64s: [0; 2],
403            reserved_ptrs: [ptr::null_mut(); 2],
404        }
405    }
406}
407
408#[repr(C)]
409#[derive(Debug, Default, Clone, Copy)]
410pub struct rte_eth_thresh {
411    pub pthresh: u8,
412    pub hthresh: u8,
413    pub wthresh: u8,
414}
415
416#[repr(C)]
417#[derive(Debug, Default, Clone, Copy)]
418pub struct rte_eth_desc_lim {
419    pub nb_max: u16,
420    pub nb_min: u16,
421    pub nb_align: u16,
422    pub nb_seg_max: u16,
423    pub nb_mtu_seg_max: u16,
424}
425
426#[repr(C)]
427#[derive(Debug, Default, Clone)]
428pub struct rte_eth_rx_adv_conf {
429    pub rss_conf: rte_eth_rss_conf,
430}
431
432#[repr(C)]
433#[derive(Debug, Default, Clone)]
434pub struct rte_eth_tx_adv_conf {
435    _placeholder: u8,
436}
437
438#[repr(C)]
439#[derive(Debug, Clone)]
440pub struct rte_eth_rss_conf {
441    pub rss_key: *mut u8,
442    pub rss_key_len: u8,
443    pub rss_hf: u64,
444}
445
446impl Default for rte_eth_rss_conf {
447    fn default() -> Self {
448        Self {
449            rss_key: ptr::null_mut(),
450            rss_key_len: 0,
451            rss_hf: 0,
452        }
453    }
454}
455
456#[repr(C)]
457#[derive(Debug, Default, Clone, Copy)]
458pub struct rte_eth_intr_conf {
459    pub lsc: u16,
460    pub rxq: u16,
461    pub rmv: u16,
462}
463
464/// Link status
465#[repr(C)]
466#[derive(Debug, Default, Clone, Copy)]
467pub struct rte_eth_link {
468    pub link_speed: u32,
469    pub link_duplex: u16,
470    pub link_autoneg: u16,
471    pub link_status: u16,
472}
473
474// Accessor methods matching the bindgen-generated bitfield accessors
475// so that `link.link_duplex()` works identically for stubs and real DPDK.
476impl rte_eth_link {
477    pub fn link_duplex(&self) -> u16 {
478        self.link_duplex
479    }
480    pub fn link_autoneg(&self) -> u16 {
481        self.link_autoneg
482    }
483    pub fn link_status(&self) -> u16 {
484        self.link_status
485    }
486}
487
488/// Ethernet statistics
489#[repr(C)]
490#[derive(Debug, Default, Clone, Copy)]
491pub struct rte_eth_stats {
492    pub ipackets: u64,
493    pub opackets: u64,
494    pub ibytes: u64,
495    pub obytes: u64,
496    pub imissed: u64,
497    pub ierrors: u64,
498    pub oerrors: u64,
499    pub rx_nombuf: u64,
500    pub q_ipackets: [u64; 16],
501    pub q_opackets: [u64; 16],
502    pub q_ibytes: [u64; 16],
503    pub q_obytes: [u64; 16],
504    pub q_errors: [u64; 16],
505}
506
507// ============================================================================
508// Ring Buffer Types
509// ============================================================================
510
511/// Ring buffer (opaque)
512#[repr(C)]
513pub struct rte_ring {
514    _private: [u8; 0],
515}
516
517// ============================================================================
518// Stub Function Implementations
519// ============================================================================
520
521// EAL Functions
522
523/// EAL lifecycle state tracking — detects use-after-cleanup bugs in stubs.
524/// Real DPDK segfaults when you call rte_pktmbuf_pool_create after rte_eal_cleanup
525/// because rte_config->mem_config is NULL. This state lets stubs catch the same bug.
526///
527/// Three states:
528///   0 = never initialized (permissive — allows mempool creation for backward compat)
529///   1 = initialized (rte_eal_init called)
530///  -1 = cleaned up (rte_eal_cleanup called after init — mempool creation denied)
531use std::sync::atomic::{AtomicI32, Ordering};
532static STUB_EAL_STATE: AtomicI32 = AtomicI32::new(0);
533
534/// Returns true if EAL is currently initialized (init called, cleanup not yet called).
535/// Exposed for tests to verify lifecycle behavior.
536pub fn stub_eal_is_initialized() -> bool {
537    STUB_EAL_STATE.load(Ordering::SeqCst) == 1
538}
539
540/// Returns true if EAL was cleaned up after being initialized.
541/// This is the state that causes segfaults with real DPDK.
542pub fn stub_eal_is_cleaned_up() -> bool {
543    STUB_EAL_STATE.load(Ordering::SeqCst) == -1
544}
545
546/// Reset EAL state to "never initialized" (0). For use in test teardown
547/// so serial tests don't leak state to the next test.
548pub fn stub_eal_reset() {
549    STUB_EAL_STATE.store(0, Ordering::SeqCst);
550    STUB_RTE_ERRNO.store(0, Ordering::SeqCst);
551}
552
553#[no_mangle]
554pub extern "C" fn rte_eal_init(_argc: c_int, _argv: *mut *mut c_char) -> c_int {
555    STUB_EAL_STATE.store(1, Ordering::SeqCst);
556    0 // Success
557}
558
559#[no_mangle]
560pub extern "C" fn rte_eal_cleanup() -> c_int {
561    STUB_EAL_STATE.store(-1, Ordering::SeqCst);
562    0
563}
564
565#[no_mangle]
566pub extern "C" fn rte_lcore_id() -> c_uint {
567    0
568}
569
570#[no_mangle]
571pub extern "C" fn rte_lcore_count() -> c_uint {
572    1
573}
574
575#[no_mangle]
576pub extern "C" fn rte_get_main_lcore() -> c_uint {
577    0
578}
579
580#[no_mangle]
581pub extern "C" fn rte_socket_id() -> c_int {
582    0
583}
584
585// Memory Pool Functions
586
587/// Stub mempool tracking for testing
588/// We use thread_local to track allocated mempools and mbufs
589use std::cell::RefCell;
590
591thread_local! {
592    static STUB_MEMPOOL_COUNTER: RefCell<u32> = const { RefCell::new(0) };
593    static STUB_MBUF_COUNTER: RefCell<u32> = const { RefCell::new(0) };
594}
595
596#[no_mangle]
597pub extern "C" fn rte_pktmbuf_pool_create(
598    _name: *const c_char,
599    n: c_uint,
600    _cache_size: c_uint,
601    _priv_size: u16,
602    _data_room_size: u16,
603    _socket_id: c_int,
604) -> *mut rte_mempool {
605    // Guard: real DPDK segfaults if EAL was cleaned up (rte_config->mem_config is NULL).
606    // Return NULL to surface the same class of bug without crashing.
607    // Only block when EAL was explicitly cleaned up (-1), not when never initialized (0),
608    // so existing tests that create mempools without calling rte_eal_init() still work.
609    if stub_eal_is_cleaned_up() {
610        // Set rte_errno to ENODEV so callers get a meaningful error
611        STUB_RTE_ERRNO.store(19, Ordering::SeqCst); // ENODEV
612        return ptr::null_mut();
613    }
614
615    // Create a stub mempool for testing
616    let mempool = Box::new(rte_mempool {
617        size: n,
618        populated_size: n,
619        ..Default::default()
620    });
621    Box::into_raw(mempool)
622}
623
624#[no_mangle]
625pub extern "C" fn rte_mempool_free(mp: *mut rte_mempool) {
626    if !mp.is_null() {
627        unsafe {
628            let _ = Box::from_raw(mp);
629        }
630    }
631}
632
633#[no_mangle]
634pub extern "C" fn rte_pktmbuf_alloc(_mp: *mut rte_mempool) -> *mut rte_mbuf {
635    // Allocate a stub mbuf with a real buffer
636    let buf_size = 2048usize;
637    let buf: Vec<u8> = vec![0u8; buf_size];
638    let buf_ptr = Box::into_raw(buf.into_boxed_slice()) as *mut c_void;
639
640    let mbuf = Box::new(rte_mbuf {
641        buf_addr: buf_ptr,
642        buf_len: buf_size as u16,
643        data_off: RTE_PKTMBUF_HEADROOM,
644        data_len: 0,
645        pkt_len: 0,
646        ..Default::default()
647    });
648    Box::into_raw(mbuf)
649}
650
651#[no_mangle]
652pub extern "C" fn rte_pktmbuf_alloc_bulk(
653    _mp: *mut rte_mempool,
654    mbufs: *mut *mut rte_mbuf,
655    count: c_uint,
656) -> c_int {
657    if mbufs.is_null() {
658        return -1;
659    }
660
661    for i in 0..count as usize {
662        let mbuf = rte_pktmbuf_alloc(_mp);
663        if mbuf.is_null() {
664            // Free previously allocated mbufs
665            for j in 0..i {
666                unsafe {
667                    rte_pktmbuf_free(*mbufs.add(j));
668                }
669            }
670            return -1;
671        }
672        unsafe {
673            *mbufs.add(i) = mbuf;
674        }
675    }
676    0
677}
678
679#[no_mangle]
680pub extern "C" fn rte_pktmbuf_free(m: *mut rte_mbuf) {
681    if !m.is_null() {
682        unsafe {
683            let mbuf = Box::from_raw(m);
684            // Free the buffer if it exists
685            // We allocated it with Box::into_raw(vec.into_boxed_slice())
686            // so we need to reconstruct the boxed slice to free it
687            if !mbuf.buf_addr.is_null() && mbuf.buf_len > 0 {
688                let slice = std::slice::from_raw_parts_mut(
689                    mbuf.buf_addr as *mut u8,
690                    mbuf.buf_len as usize,
691                );
692                let _ = Box::from_raw(slice as *mut [u8]);
693            }
694        }
695    }
696}
697
698#[no_mangle]
699pub extern "C" fn rte_pktmbuf_clone(
700    _md: *mut rte_mbuf,
701    _mp: *mut rte_mempool,
702) -> *mut rte_mbuf {
703    ptr::null_mut()
704}
705
706#[no_mangle]
707pub extern "C" fn rte_mempool_avail_count(mp: *mut rte_mempool) -> c_uint {
708    if mp.is_null() {
709        return 0;
710    }
711    unsafe { (*mp).populated_size }
712}
713
714#[no_mangle]
715pub extern "C" fn rte_mempool_in_use_count(_mp: *mut rte_mempool) -> c_uint {
716    // Stub: always return 0 (nothing in use)
717    0
718}
719
720#[no_mangle]
721pub extern "C" fn rte_mempool_full(mp: *mut rte_mempool) -> c_int {
722    // Stub: return 1 (true) if pool has elements
723    if mp.is_null() {
724        return 0;
725    }
726    1
727}
728
729#[no_mangle]
730pub extern "C" fn rte_mempool_empty(mp: *mut rte_mempool) -> c_int {
731    // Stub: return 0 (false) - pool is not empty
732    if mp.is_null() {
733        return 1;
734    }
735    0
736}
737
738// Ethernet Device Functions
739#[no_mangle]
740pub extern "C" fn rte_eth_dev_count_avail() -> u16 {
741    1 // Pretend we have one device for testing
742}
743
744#[no_mangle]
745pub extern "C" fn rte_eth_dev_configure(
746    _port_id: u16,
747    _nb_rx_queue: u16,
748    _nb_tx_queue: u16,
749    _eth_conf: *const rte_eth_conf,
750) -> c_int {
751    0
752}
753
754#[no_mangle]
755pub extern "C" fn rte_eth_rx_queue_setup(
756    _port_id: u16,
757    _rx_queue_id: u16,
758    _nb_rx_desc: u16,
759    _socket_id: c_uint,
760    _rx_conf: *const rte_eth_rxconf,
761    _mb_pool: *mut rte_mempool,
762) -> c_int {
763    0
764}
765
766#[no_mangle]
767pub extern "C" fn rte_eth_tx_queue_setup(
768    _port_id: u16,
769    _tx_queue_id: u16,
770    _nb_tx_desc: u16,
771    _socket_id: c_uint,
772    _tx_conf: *const rte_eth_txconf,
773) -> c_int {
774    0
775}
776
777#[no_mangle]
778pub extern "C" fn rte_eth_dev_start(_port_id: u16) -> c_int {
779    0
780}
781
782#[no_mangle]
783pub extern "C" fn rte_eth_dev_stop(_port_id: u16) -> c_int {
784    0
785}
786
787#[no_mangle]
788pub extern "C" fn rte_eth_dev_close(_port_id: u16) -> c_int {
789    0
790}
791
792#[no_mangle]
793pub extern "C" fn rte_eth_promiscuous_enable(_port_id: u16) -> c_int {
794    0
795}
796
797#[no_mangle]
798pub extern "C" fn rte_eth_promiscuous_disable(_port_id: u16) -> c_int {
799    0
800}
801
802#[no_mangle]
803pub extern "C" fn rte_eth_promiscuous_get(_port_id: u16) -> c_int {
804    1 // Promiscuous is enabled by default in stubs
805}
806
807#[no_mangle]
808pub extern "C" fn rte_eth_allmulticast_enable(_port_id: u16) -> c_int {
809    0
810}
811
812#[no_mangle]
813pub extern "C" fn rte_eth_allmulticast_disable(_port_id: u16) -> c_int {
814    0
815}
816
817#[no_mangle]
818pub extern "C" fn rte_eth_allmulticast_get(_port_id: u16) -> c_int {
819    0 // All-multicast disabled by default
820}
821
822#[no_mangle]
823pub extern "C" fn rte_eth_dev_set_mc_addr_list(
824    _port_id: u16,
825    _mc_addr_set: *mut rte_ether_addr,
826    _nb_mc_addr: u32,
827) -> c_int {
828    0 // Success
829}
830
831#[no_mangle]
832pub extern "C" fn rte_eth_dev_info_get(
833    _port_id: u16,
834    dev_info: *mut rte_eth_dev_info,
835) -> c_int {
836    if !dev_info.is_null() {
837        unsafe {
838            (*dev_info).max_rx_queues = 16;
839            (*dev_info).max_tx_queues = 16;
840        }
841    }
842    0
843}
844
845#[no_mangle]
846pub extern "C" fn rte_eth_dev_socket_id(_port_id: u16) -> c_int {
847    0 // NUMA node 0
848}
849
850#[no_mangle]
851pub extern "C" fn rte_eth_link_get(_port_id: u16, link: *mut rte_eth_link) -> c_int {
852    if !link.is_null() {
853        unsafe {
854            (*link).link_speed = 10000; // 10 Gbps
855            (*link).link_duplex = 1;
856            (*link).link_status = 1; // Link up
857        }
858    }
859    0
860}
861
862#[no_mangle]
863pub extern "C" fn rte_eth_link_get_nowait(_port_id: u16, link: *mut rte_eth_link) -> c_int {
864    rte_eth_link_get(_port_id, link)
865}
866
867#[no_mangle]
868pub extern "C" fn rte_eth_stats_get(_port_id: u16, _stats: *mut rte_eth_stats) -> c_int {
869    0
870}
871
872#[no_mangle]
873pub extern "C" fn rte_eth_stats_reset(_port_id: u16) -> c_int {
874    0
875}
876
877#[no_mangle]
878pub extern "C" fn rte_eth_macaddr_get(_port_id: u16, mac_addr: *mut rte_ether_addr) -> c_int {
879    if !mac_addr.is_null() {
880        unsafe {
881            (*mac_addr).addr_bytes = [0x02, 0x00, 0x00, 0x00, 0x00, 0x01];
882        }
883    }
884    0
885}
886
887// Packet RX/TX Functions
888#[no_mangle]
889pub extern "C" fn rte_eth_rx_burst(
890    _port_id: u16,
891    _queue_id: u16,
892    _rx_pkts: *mut *mut rte_mbuf,
893    _nb_pkts: u16,
894) -> u16 {
895    0 // No packets received (stub)
896}
897
898#[no_mangle]
899pub extern "C" fn rte_eth_tx_burst(
900    _port_id: u16,
901    _queue_id: u16,
902    _tx_pkts: *mut *mut rte_mbuf,
903    _nb_pkts: u16,
904) -> u16 {
905    0 // No packets sent (stub)
906}
907
908// Error handling
909
910/// Stub rte_errno — set by stub functions that need to report errors
911static STUB_RTE_ERRNO: AtomicI32 = AtomicI32::new(0);
912
913#[no_mangle]
914pub extern "C" fn rte_errno() -> c_int {
915    STUB_RTE_ERRNO.load(Ordering::SeqCst)
916}
917
918#[no_mangle]
919pub extern "C" fn rte_strerror(_errnum: c_int) -> *const c_char {
920    b"No error (stub)\0".as_ptr() as *const c_char
921}
922
923// Utility functions
924#[no_mangle]
925pub extern "C" fn rte_cpu_to_be_16(x: u16) -> u16 {
926    x.to_be()
927}
928
929#[no_mangle]
930pub extern "C" fn rte_cpu_to_be_32(x: u32) -> u32 {
931    x.to_be()
932}
933
934#[no_mangle]
935pub extern "C" fn rte_be_to_cpu_16(x: u16) -> u16 {
936    u16::from_be(x)
937}
938
939#[no_mangle]
940pub extern "C" fn rte_be_to_cpu_32(x: u32) -> u32 {
941    u32::from_be(x)
942}
943
944// Checksum functions
945#[no_mangle]
946pub extern "C" fn rte_ipv4_cksum(_ipv4_hdr: *const rte_ipv4_hdr) -> u16 {
947    0 // Stub - would compute checksum
948}
949
950#[no_mangle]
951pub extern "C" fn rte_ipv4_udptcp_cksum(
952    _ipv4_hdr: *const rte_ipv4_hdr,
953    _l4_hdr: *const c_void,
954) -> u16 {
955    0 // Stub - would compute checksum
956}
957
958#[cfg(test)]
959mod tests {
960    use super::*;
961
962    #[test]
963    fn test_eal_init() {
964        let result = rte_eal_init(0, ptr::null_mut());
965        assert_eq!(result, 0);
966    }
967
968    #[test]
969    fn test_eth_dev_count() {
970        let count = rte_eth_dev_count_avail();
971        assert_eq!(count, 1);
972    }
973
974    #[test]
975    fn test_lcore_id() {
976        let id = rte_lcore_id();
977        assert_eq!(id, 0);
978    }
979}