diff --git a/src/Magma.DPDK/Interop/Dpdk.cs b/src/Magma.DPDK/Interop/Dpdk.cs
new file mode 100644
index 0000000..6348156
--- /dev/null
+++ b/src/Magma.DPDK/Interop/Dpdk.cs
@@ -0,0 +1,178 @@
+using System.Runtime.InteropServices;
+
+namespace Magma.DPDK.Interop;
+
+///
+/// P/Invoke declarations for DPDK (Data Plane Development Kit) functions.
+/// These bindings provide access to DPDK's low-level packet I/O operations.
+///
+internal static unsafe class Dpdk
+{
+ private const string LibraryName = "librte_ethdev.so";
+
+ ///
+ /// Initialize the EAL (Environment Abstraction Layer).
+ /// Must be called before any other DPDK function.
+ ///
+ /// Argument count
+ /// Argument vector
+ /// Number of parsed arguments on success, negative on error
+ [DllImport("librte_eal.so", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int rte_eal_init(int argc, byte** argv);
+
+ ///
+ /// Get the number of Ethernet devices available.
+ ///
+ /// Number of available Ethernet devices
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern ushort rte_eth_dev_count_avail();
+
+ ///
+ /// Configure an Ethernet device.
+ ///
+ /// Port identifier
+ /// Number of RX queues
+ /// Number of TX queues
+ /// Device configuration
+ /// 0 on success, negative on error
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int rte_eth_dev_configure(ushort port_id, ushort nb_rx_queue, ushort nb_tx_queue, ref rte_eth_conf eth_conf);
+
+ ///
+ /// Allocate and set up a receive queue for an Ethernet device.
+ ///
+ /// Port identifier
+ /// RX queue index (must be in range [0, nb_rx_queue - 1])
+ /// Number of RX descriptors
+ /// NUMA socket ID for memory allocation
+ /// RX queue configuration (can be null for defaults)
+ /// Memory pool from which to allocate rte_mbuf network memory buffers
+ /// 0 on success, negative on error
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int rte_eth_rx_queue_setup(ushort port_id, ushort rx_queue_id, ushort nb_rx_desc, uint socket_id, rte_eth_rxconf* rx_conf, void* mb_pool);
+
+ ///
+ /// Allocate and set up a transmit queue for an Ethernet device.
+ ///
+ /// Port identifier
+ /// TX queue index (must be in range [0, nb_tx_queue - 1])
+ /// Number of TX descriptors
+ /// NUMA socket ID for memory allocation
+ /// TX queue configuration (can be null for defaults)
+ /// 0 on success, negative on error
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int rte_eth_tx_queue_setup(ushort port_id, ushort tx_queue_id, ushort nb_tx_desc, uint socket_id, rte_eth_txconf* tx_conf);
+
+ ///
+ /// Start an Ethernet device.
+ /// The device start step is the last one before beginning to receive and transmit packets.
+ ///
+ /// Port identifier
+ /// 0 on success, negative on error
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int rte_eth_dev_start(ushort port_id);
+
+ ///
+ /// Stop an Ethernet device. The device can be restarted with rte_eth_dev_start().
+ ///
+ /// Port identifier
+ /// 0 on success, negative on error
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int rte_eth_dev_stop(ushort port_id);
+
+ ///
+ /// Close a stopped Ethernet device and release resources.
+ ///
+ /// Port identifier
+ /// 0 on success, negative on error
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int rte_eth_dev_close(ushort port_id);
+
+ ///
+ /// Enable receipt in promiscuous mode for an Ethernet device.
+ ///
+ /// Port identifier
+ /// 0 on success, negative on error
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int rte_eth_promiscuous_enable(ushort port_id);
+
+ ///
+ /// Disable receipt in promiscuous mode for an Ethernet device.
+ ///
+ /// Port identifier
+ /// 0 on success, negative on error
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int rte_eth_promiscuous_disable(ushort port_id);
+
+ ///
+ /// Retrieve a burst of input packets from an RX queue.
+ /// This is the main function for receiving packets in poll mode.
+ ///
+ /// Port identifier
+ /// RX queue index (must be in range [0, nb_rx_queue - 1])
+ /// Array of pointers to rte_mbuf structures for received packets
+ /// Maximum number of packets to retrieve
+ /// Number of packets actually retrieved (0 to nb_pkts)
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern ushort rte_eth_rx_burst(ushort port_id, ushort queue_id, rte_mbuf** rx_pkts, ushort nb_pkts);
+
+ ///
+ /// Send a burst of output packets on a TX queue.
+ /// This is the main function for transmitting packets in poll mode.
+ ///
+ /// Port identifier
+ /// TX queue index (must be in range [0, nb_tx_queue - 1])
+ /// Array of pointers to rte_mbuf structures for packets to send
+ /// Number of packets to transmit
+ /// Number of packets actually sent
+ [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
+ public static extern ushort rte_eth_tx_burst(ushort port_id, ushort queue_id, rte_mbuf** tx_pkts, ushort nb_pkts);
+
+ ///
+ /// Create a new mbuf pool.
+ ///
+ /// Name of the mbuf pool
+ /// Number of elements in the pool
+ /// Size of the per-core object cache
+ /// Size of application private data
+ /// Size of data buffer in each mbuf
+ /// NUMA socket ID
+ /// Pointer to the new mbuf pool, or null on error
+ [DllImport("librte_mbuf.so", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void* rte_pktmbuf_pool_create(byte* name, uint n, uint cache_size, ushort priv_size, ushort data_room_size, int socket_id);
+
+ ///
+ /// Free a packet mbuf back to its pool.
+ ///
+ /// Pointer to the mbuf to free
+ [DllImport("librte_mbuf.so", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void rte_pktmbuf_free(rte_mbuf* m);
+
+ ///
+ /// Allocate a new mbuf from a pool.
+ ///
+ /// Pointer to the mbuf pool
+ /// Pointer to the new mbuf, or null on error
+ [DllImport("librte_mbuf.so", CallingConvention = CallingConvention.Cdecl)]
+ public static extern rte_mbuf* rte_pktmbuf_alloc(void* mp);
+
+ ///
+ /// Get the NUMA socket ID for a given lcore.
+ ///
+ /// Logical core ID
+ /// NUMA socket ID
+ [DllImport("librte_eal.so", CallingConvention = CallingConvention.Cdecl)]
+ public static extern uint rte_lcore_to_socket_id(uint lcore_id);
+
+ ///
+ /// Get the ID of the current lcore.
+ ///
+ /// Current lcore ID
+ [DllImport("librte_eal.so", CallingConvention = CallingConvention.Cdecl)]
+ public static extern uint rte_lcore_id();
+
+ ///
+ /// Special socket ID value indicating "any socket" for NUMA-unaware allocation.
+ ///
+ public const int SOCKET_ID_ANY = -1;
+}
diff --git a/src/Magma.DPDK/Interop/DpdkStructs.cs b/src/Magma.DPDK/Interop/DpdkStructs.cs
new file mode 100644
index 0000000..1ced3f1
--- /dev/null
+++ b/src/Magma.DPDK/Interop/DpdkStructs.cs
@@ -0,0 +1,119 @@
+using System.Runtime.InteropServices;
+
+namespace Magma.DPDK.Interop;
+
+///
+/// DPDK mbuf (memory buffer) structure for packet data.
+/// This is a simplified version containing the essential fields needed for basic RX/TX operations.
+///
+[StructLayout(LayoutKind.Sequential)]
+internal unsafe struct rte_mbuf
+{
+ public void* buf_addr;
+ public ulong buf_iova;
+
+ // Rearm data marker
+ public ushort data_off;
+ public ushort refcnt;
+ public ushort nb_segs;
+ public ushort port;
+
+ public ulong ol_flags;
+
+ // Packet type and RSS hash
+ public uint packet_type;
+ public uint pkt_len;
+ public ushort data_len;
+ public ushort vlan_tci;
+
+ public ulong hash_rss;
+
+ public ushort vlan_tci_outer;
+ public ushort buf_len;
+
+ // Pool pointer
+ public void* pool;
+
+ // Second cache line - skip for now
+ // We'll access packet data via buf_addr + data_off
+}
+
+///
+/// DPDK Ethernet device configuration structure.
+///
+[StructLayout(LayoutKind.Sequential)]
+internal struct rte_eth_conf
+{
+ public uint link_speeds;
+ public rte_eth_rxmode rxmode;
+ public rte_eth_txmode txmode;
+ public uint lpbk_mode;
+ public rte_eth_rxconf rxconf;
+ public rte_eth_txconf txconf;
+}
+
+[StructLayout(LayoutKind.Sequential)]
+internal struct rte_eth_rxmode
+{
+ public ulong offloads;
+ public uint mtu;
+ public ushort max_lro_pkt_size;
+ public ushort split_hdr_size;
+}
+
+[StructLayout(LayoutKind.Sequential)]
+internal struct rte_eth_txmode
+{
+ public ulong offloads;
+ public ushort pvid;
+ public byte hw_vlan_reject_tagged;
+ public byte hw_vlan_reject_untagged;
+ public byte hw_vlan_insert_pvid;
+}
+
+[StructLayout(LayoutKind.Sequential)]
+internal struct rte_eth_rxconf
+{
+ public ushort rx_thresh_pthresh;
+ public ushort rx_thresh_hthresh;
+ public ushort rx_thresh_wthresh;
+ public byte rx_drop_en;
+ public byte rx_deferred_start;
+ public ulong offloads;
+}
+
+[StructLayout(LayoutKind.Sequential)]
+internal struct rte_eth_txconf
+{
+ public ushort tx_thresh_pthresh;
+ public ushort tx_thresh_hthresh;
+ public ushort tx_thresh_wthresh;
+ public ushort tx_rs_thresh;
+ public ushort tx_free_thresh;
+ public byte tx_deferred_start;
+ public ulong offloads;
+}
+
+///
+/// Link speeds
+///
+internal static class RteEthLinkSpeed
+{
+ public const uint RTE_ETH_LINK_SPEED_AUTONEG = 0;
+ public const uint RTE_ETH_LINK_SPEED_FIXED = 0x80000000;
+ public const uint RTE_ETH_LINK_SPEED_10M_HD = 0x00000001;
+ public const uint RTE_ETH_LINK_SPEED_10M = 0x00000002;
+ public const uint RTE_ETH_LINK_SPEED_100M_HD = 0x00000004;
+ public const uint RTE_ETH_LINK_SPEED_100M = 0x00000008;
+ public const uint RTE_ETH_LINK_SPEED_1G = 0x00000010;
+ public const uint RTE_ETH_LINK_SPEED_2_5G = 0x00000020;
+ public const uint RTE_ETH_LINK_SPEED_5G = 0x00000040;
+ public const uint RTE_ETH_LINK_SPEED_10G = 0x00000080;
+ public const uint RTE_ETH_LINK_SPEED_20G = 0x00000100;
+ public const uint RTE_ETH_LINK_SPEED_25G = 0x00000200;
+ public const uint RTE_ETH_LINK_SPEED_40G = 0x00000400;
+ public const uint RTE_ETH_LINK_SPEED_50G = 0x00000800;
+ public const uint RTE_ETH_LINK_SPEED_56G = 0x00001000;
+ public const uint RTE_ETH_LINK_SPEED_100G = 0x00002000;
+ public const uint RTE_ETH_LINK_SPEED_200G = 0x00004000;
+}
diff --git a/src/Magma.DPDK/Interop/MbufExtensions.cs b/src/Magma.DPDK/Interop/MbufExtensions.cs
new file mode 100644
index 0000000..9c2b46f
--- /dev/null
+++ b/src/Magma.DPDK/Interop/MbufExtensions.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Magma.DPDK.Interop;
+
+///
+/// Extension methods for working with DPDK mbufs and providing zero-copy access via Span<T>.
+///
+internal static unsafe class MbufExtensions
+{
+ ///
+ /// Get a Span<byte> view of the packet data in an mbuf (zero-copy).
+ ///
+ /// Pointer to the mbuf
+ /// Span representing the packet data
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span GetPacketData(this rte_mbuf* mbuf)
+ {
+ if (mbuf == null)
+ return Span.Empty;
+
+ var dataPtr = (byte*)mbuf->buf_addr + mbuf->data_off;
+ return new Span(dataPtr, mbuf->data_len);
+ }
+
+ ///
+ /// Get a pointer to the start of packet data in an mbuf.
+ ///
+ /// Pointer to the mbuf
+ /// Pointer to packet data
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static byte* GetDataPointer(this rte_mbuf* mbuf)
+ {
+ if (mbuf == null)
+ return null;
+
+ return (byte*)mbuf->buf_addr + mbuf->data_off;
+ }
+
+ ///
+ /// Set the packet length for an mbuf.
+ ///
+ /// Pointer to the mbuf
+ /// Packet length in bytes
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void SetPacketLength(this rte_mbuf* mbuf, ushort length)
+ {
+ mbuf->data_len = length;
+ mbuf->pkt_len = length;
+ }
+
+ ///
+ /// Copy data into an mbuf's packet buffer.
+ ///
+ /// Pointer to the mbuf
+ /// Source data to copy
+ /// True if successful, false if buffer too small
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool CopyPacketData(this rte_mbuf* mbuf, ReadOnlySpan source)
+ {
+ if (mbuf == null || source.Length > mbuf->buf_len - mbuf->data_off)
+ return false;
+
+ var dest = mbuf->GetPacketData();
+ source.CopyTo(dest);
+ mbuf->SetPacketLength((ushort)source.Length);
+ return true;
+ }
+
+ ///
+ /// Get the available buffer space in an mbuf for packet data.
+ ///
+ /// Pointer to the mbuf
+ /// Available space in bytes
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int GetAvailableSpace(this rte_mbuf* mbuf)
+ {
+ if (mbuf == null)
+ return 0;
+
+ return mbuf->buf_len - mbuf->data_off;
+ }
+}
diff --git a/src/Magma.DPDK/Magma.DPDK.csproj b/src/Magma.DPDK/Magma.DPDK.csproj
new file mode 100644
index 0000000..cca619b
--- /dev/null
+++ b/src/Magma.DPDK/Magma.DPDK.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net10.0
+ true
+ latest
+ DPDK (Data Plane Development Kit) integration for high-performance packet I/O with kernel bypass
+
+
+
+
+
+
+
+
+
+
+
+
+