netmap-rs 0.2.1

Safe, zero-cost abstractions for Netmap kernel-bypass networking
Documentation

netmap-rs

netmap-rs provides safe, zero-cost abstractions for Netmap kernel-bypass networking in Rust. It aims to offer high-performance packet I/O by leveraging Netmap's efficient memory-mapped ring buffers.

Features

  • Zero-copy packet I/O: Directly access packet buffers in memory shared with the kernel.
  • High Performance: Designed for low-latency and high-throughput applications.
  • Safe Abstractions: Provides a safe Rust API over the underlying netmap C structures.
  • Feature Flags: Customizable build via feature flags (e.g., sys for core Netmap functionality, tokio-async for Tokio integration).

Adding netmap-rs to your project

To use netmap-rs in your project, add it to your Cargo.toml.

Crucially, for most use cases, you will need to enable the sys feature. This feature compiles and links against the necessary netmap C libraries and enables the core structures like NetmapBuilder, Netmap, TxRing, and RxRing.

[dependencies]
netmap-rs = { version = "0.1.2", features = ["sys"] }
# Replace "0.1.2" with the desired version from crates.io

If you intend to use netmap-rs with Tokio for asynchronous operations, you should also enable the tokio-async feature:

[dependencies]
netmap-rs = { version = "0.1.2", features = ["sys", "tokio-async"] }

Basic Usage Example

Here's a basic example of how to open a Netmap interface, send, and receive a packet. This example assumes you have a loopback interface or a setup where packets sent on an interface can be received on it.

use netmap_rs::NetmapBuilder; // Or use netmap_rs::prelude::*;
use netmap_rs::Error; // If not using prelude
use std::thread::sleep;
use std::time::Duration;

fn main() -> Result<(), Error> {
    // Ensure you have enabled the "sys" feature for netmap-rs in your Cargo.toml
    // e.g., netmap-rs = { version = "...", features = ["sys"] }

    // Attempt to open a netmap interface.
    // Replace "eth0" with your desired interface.
    // NetmapBuilder will prefix with "netmap:" if needed.
    // Use "eth0^" to access host stack rings.
    let nm = NetmapBuilder::new("eth0") // Or "netmap:eth0"
        .num_tx_rings(1) // Configure one transmission ring
        .num_rx_rings(1) // Configure one reception ring
        .build()?; // This can fail if Netmap is not available or the interface doesn't exist.

    println!(
        "Opened netmap interface: {} TX rings, {} RX rings, Host interface: {}",
        nm.num_tx_rings(),
        nm.num_rx_rings(),
        nm.is_host_if()
    );

    // Get handles to the first transmission and reception rings.
    let mut tx_ring = nm.tx_ring(0)?;
    let mut rx_ring = nm.rx_ring(0)?;

    // Prepare a packet to send.
    let packet_data = b"hello netmap-rs!";

    // Send the packet.
    // The `send` method stages the packet in the ring's buffer.
    if tx_ring.send(packet_data).is_err() {
        eprintln!("Failed to stage packet for sending. Ring full or packet too large?");
        // Potentially call tx_ring.sync() here if you expect the ring to be full
        // and want to force transmission before trying to send again.
    }

    // `sync` makes queued packets available to the hardware for transmission.
    // It also updates the kernel's view of consumed buffers on the RX side.
    tx_ring.sync();
    println!("Sent packet: {:?}", packet_data);

    // Attempt to receive the packet.
    let mut received_packet = false;
    println!("Attempting to receive packet...");
    for _ in 0..10 { // Try a few times with a delay
        // `sync` on the rx_ring tells the kernel we are done with previously received packets
        // and updates the ring's state to make new packets visible.
        rx_ring.sync();

        while let Some(frame) = rx_ring.recv() {
            println!("Received packet: {:?}", frame.payload());
            // Simple loopback check
            if frame.payload() == packet_data {
                println!("Successfully received the sent packet!");
                received_packet = true;
            }
            // Release the received frame buffer back to Netmap
            // In this simplified recv() loop, the frame is dropped at the end of scope,
            // which handles buffer release if Frame implements Drop appropriately.
            // If Frame doesn't, manual management would be needed.
            // (Assuming Frame's Drop implementation correctly returns the buffer to the ring)
            if received_packet { break; }
        }
        if received_packet {
            break;
        }
        sleep(Duration::from_millis(200)); // Wait a bit for the packet to arrive/loopback
    }

    if !received_packet {
        eprintln!("Failed to receive the packet back. Ensure your interface is configured for loopback or testing appropriately.");
    }

    Ok(())
}

Note on Netmap Setup: Using netmap-rs (with the sys feature) requires that your system has the Netmap kernel module installed, along with its userspace C libraries and development headers. You will also need clang installed, as it's used by the build process to generate bindings.

Please refer to the official Netmap project page or the Netmap GitHub repository for instructions on how to compile and install Netmap on your operating system. You may also need appropriate permissions to access network interfaces via Netmap.

Troubleshooting Build Issues (Netmap C Library Not Found):

If the build fails with errors indicating that net/netmap_user.h or the Netmap library cannot be found, it means the build script for the netmap-min-sys dependency could not locate your Netmap C installation.

  • Standard Paths: The build script checks standard locations like /usr/local.
  • Custom Installation Path: If you have installed Netmap in a custom directory (e.g., /opt/netmap), you need to inform the build system by setting the NETMAP_LOCATION environment variable before running cargo build:
    NETMAP_LOCATION=/opt/netmap cargo build
    
    Replace /opt/netmap with the root directory of your Netmap installation (this directory should contain include and lib subdirectories for Netmap).
  • Further Details: For more information on build-time environment variables like NETMAP_LOCATION and DISABLE_NETMAP_KERNEL (for compiling without Netmap), refer to the README.md file within the netmap-min-sys crate.

Building Examples

The crate includes several examples in the examples/ directory. To run an example, ensure you have the sys feature enabled for the crate when building:

cargo run --example <example_name> --features netmap-rs/sys

(If netmap-rs is the current crate, you might not need the netmap-rs/ prefix for features).

For example, to run ping_pong:

cargo run --example ping_pong --features sys
# Or if it's a dependency:
# cargo run --example ping_pong --features netmap-rs/sys

Make sure to adapt the interface names used within the examples to your specific setup.

License

This crate is licensed under