API Guide
Complete C++ API reference for DAQIRI. Include the canonical public header, daqiri/daqiri.h. All symbols live in the daqiri:: namespace.
BurstParams
All packet data flows through the BurstParams structure. A burst is a batch of packets grouped together for efficient DMA transfer between the NIC and the application. BurstParams carries pointers to packet buffers (CPU or GPU), packet count, port/queue IDs, segment count, byte totals, and per-packet lengths and flow IDs. Interact with it only through the helper functions — the internal layout is opaque.
Zero-Copy Design
Only pointers are passed between the NIC, DAQIRI internals, and your application. When you receive packets, you are reading the same buffers the NIC DMA'd into — no copies. This means you must explicitly free buffers when done. Failure to free will exhaust the memory pool, causing the NIC to drop packets and DAQIRI to return NO_FREE_BURST_BUFFERS or NO_FREE_PACKET_BUFFERS.
Segments
A segment is a contiguous memory region (CPU or GPU) holding part of a packet. The most common case is header-data split (HDS): segment 0 = headers (CPU), segment 1 = payload (GPU). CPU-only and batched-GPU modes use a single segment (segment 0).
Initializes DAQIRI from a YAML config file or a NetworkConfig struct. After SUCCESS returns, all memory regions are allocated, NIC queues are configured, and worker threads are running.
#include <daqiri/daqiri.h> auto status = daqiri::daqiri_init("path/to/config.yaml"); if (status != daqiri::Status::SUCCESS) { // handle init failure }
See the configuration reference for the full YAML schema and worked examples for DPDK and RDMA backends.
Stops all worker threads, drains queues, and releases all memory regions and NIC resources. Call once at the end of your application.
The three-step RX workflow: get a burst → access packet data → free buffers.
Non-blocking. Returns SUCCESS when a complete batch is available, or NULL_PTR when no burst is ready yet. Three overloads:
// From a specific port + queue daqiri::get_rx_burst(&burst, port_id, queue_id); // From any queue on a port (round-robin) daqiri::get_rx_burst(&burst, port_id); // From any queue on any port (round-robin) daqiri::get_rx_burst(&burst);
Returns the number of packets in the burst. Always call this before iterating — do not assume batch_size.
Returns a pointer to the packet buffer for packet pkt_idx. For CPU-only or batched GPU (single-segment) configurations, this is the full packet. For HDS, use get_segment_packet_ptr() instead.
for (int i = 0; i < daqiri::get_num_packets(burst); i++) { void* pkt = daqiri::get_packet_ptr(burst, i); uint32_t len = daqiri::get_packet_length(burst, i); uint16_t flow = daqiri::get_packet_flow_id(burst, i); // process... }
Returns a pointer to segment seg_idx of packet pkt_idx. Use for header-data split (HDS) configurations: segment 0 is a CPU pointer to the packet headers; segment 1 is a GPU device pointer to the payload.
// Header-data split: two segments per packet for (int i = 0; i < daqiri::get_num_packets(burst); i++) { void* hdr = daqiri::get_segment_packet_ptr(burst, 0, i); // CPU void* pay = daqiri::get_segment_packet_ptr(burst, 1, i); // GPU uint32_t hlen = daqiri::get_segment_packet_length(burst, 0, i); uint32_t plen = daqiri::get_segment_packet_length(burst, 1, i); // pay is already on GPU — pass directly to CUDA kernel }
Buffers must be freed when done or the memory pool will be exhausted. Several options depending on how your pipeline releases buffers:
// Most common: free all packets + burst metadata daqiri::free_all_packets_and_burst_rx(burst); // Free a single packet (all segments) daqiri::free_packet(burst, pkt_idx); // Free one segment of one packet daqiri::free_packet_segment(burst, seg_idx, pkt_idx); // Free all packets for one segment, then the burst metadata daqiri::free_all_segment_packets(burst, seg_idx); daqiri::free_rx_burst(burst);
Forgetting to free buffers is the most common cause of dropped packets. If you see NO_FREE_BURST_BUFFERS or NO_FREE_PACKET_BUFFERS, check your free path first.
The three-step TX workflow: allocate a burst → fill packets → send.
Allocates a new TX BurstParams object. Follow with set_header() to configure port, queue, batch size, and segment count, then call get_tx_packet_burst() to acquire buffer space.
auto burst = daqiri::create_tx_burst_params(); daqiri::set_header(burst, port_id, queue_id, batch_size, num_segments); // Optionally check availability first if (daqiri::is_tx_burst_available(burst)) daqiri::get_tx_packet_burst(burst);
Helper functions to fill standard Ethernet/IP/UDP headers and payload for each packet in the burst. Or write raw packet data directly via get_packet_ptr().
for (int i = 0; i < batch_size; i++) { daqiri::set_eth_header(burst, i, dst_mac); daqiri::set_ipv4_header(burst, i, ip_payload_len, IPPROTO_UDP, src_ip, dst_ip); daqiri::set_udp_header(burst, i, udp_payload_len, src_port, dst_port); daqiri::set_udp_payload(burst, i, payload_ptr, payload_size); daqiri::set_packet_lengths(burst, i, {total_pkt_len}); }
Enqueues the burst to the TX worker thread, which sends it to the NIC via DMA. Returns immediately — the worker thread handles actual transmission asynchronously.
daqiri::send_tx_burst(burst);
Schedules a packet for hardware-timed transmission at the given PTP timestamp. Requires accurate_send: true in the TX config and ConnectX-7 or later hardware.
daqiri::set_packet_tx_time(burst, pkt_idx, ptp_timestamp);
Enable accurate send in YAML: tx.accurate_send: true. Not supported on ConnectX-6 Dx.
// Get MAC address of a NIC port char mac[6]; daqiri::get_mac_addr(port_id, mac); // Look up port ID by interface name or PCIe address int port = daqiri::get_port_id("rx_port"); // Traffic control daqiri::drop_all_traffic(port_id); // drop all incoming packets daqiri::allow_all_traffic(port_id); // restore normal reception // Drain stale packets from a queue daqiri::flush_port_queue(port_id, queue_id); // Print NIC statistics to stdout daqiri::print_stats(); // Graceful shutdown daqiri::shutdown();
All DAQIRI functions that can fail return daqiri::Status. Always check the return value in production code.
| Status | Meaning |
|---|---|
| SUCCESS | Operation completed successfully. |
| NULL_PTR | Burst or internal pointer not initialized, or no data is ready yet (normal on empty RX poll). |
| NO_FREE_BURST_BUFFERS | Metadata buffer pool exhausted. Increase tx/rx_meta_buffers in config, or free bursts faster. |
| NO_FREE_PACKET_BUFFERS | Packet buffer pool exhausted. Free buffers faster or increase num_bufs in memory region config. |
| NOT_READY | System not yet initialized — daqiri_init() has not been called or has not returned SUCCESS. |
| INVALID_PARAMETER | An invalid argument was passed (e.g., out-of-range port or queue ID). |
| NO_SPACE_AVAILABLE | Internal ring or queue is full. Back off and retry. |
| NOT_SUPPORTED | Operation is not supported by the current backend (e.g., timed TX on DPDK without ConnectX-7). |
| GENERIC_FAILURE | Unspecified failure. Check logs for more detail. |
| CONNECT_FAILURE | RDMA connection failed — verify IP addresses, port, and network reachability. |
| INTERNAL_ERROR | An internal error occurred in the backend. File an issue on GitHub with logs. |