Skip to content

Kyle6012/netmap-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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).

Prerequisites

System Requirements

IMPORTANT: This crate requires the Netmap C library to be installed on your system. Without it, the sys feature will not work.

Installing Netmap C Library

On Linux

  1. Install build dependencies:

    # Ubuntu/Debian
    sudo apt-get update
    sudo apt-get install build-essential git linux-headers-$(uname -r)
    
    # CentOS/RHEL
    sudo yum install gcc git kernel-devel-$(uname -r)
  2. Download and build netmap:

    git clone https://github.com/luigirizzo/netmap.git
    cd netmap/LINUX
    ./configure
    make
    sudo make install
  3. Load the kernel module:

    sudo insmod netmap.ko
    # Verify it's loaded
    ls /dev/netmap

On FreeBSD

Netmap is included by default in FreeBSD 11+. No additional installation is required.

Custom Installation Paths

If you installed netmap in a non-standard location, set the NETMAP_LOCATION environment variable:

export NETMAP_LOCATION=/opt/netmap
# Then build your project

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.3", features = ["sys"] }

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.3", 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::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()?;

    // 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!";

    // Send the packet.
    // The `send` method queues the packet.
    tx_ring.send(packet_data)?;
    // `sync` ensures that queued packets are made available to the hardware.
    tx_ring.sync();
    println!("Sent packet: {:?}", packet_data);

    // Attempt to receive the packet.
    let mut received = false;
    for _ in 0..5 { // 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 see new packets.
        rx_ring.sync();
        while let Some(frame) = rx_ring.recv() {
            println!("Received packet: {:?}", frame.payload());
            assert_eq!(frame.payload(), packet_data);
            received = true;
            break;
        }
        if received {
            break;
        }
        sleep(Duration::from_millis(100)); // Wait a bit for the packet to arrive
    }

    if !received {
        eprintln!("Failed to receive the packet back.");
        // Depending on the setup (e.g. loopback interface), this might indicate an issue.
    }

    Ok(())
}

Troubleshooting

Build Errors

"netmap_user.h not found"

This means the Netmap C library is not installed or not found. Make sure to:

  1. Install the Netmap C library (see Prerequisites section)
  2. Set NETMAP_LOCATION if installed in a non-standard path

"undefined reference to nm_open"

This indicates the Netmap library is not being linked properly. Ensure:

  1. The sys feature is enabled in Cargo.toml
  2. Netmap is properly installed with the library files

Feature Flag Issues

If you get errors like "NetmapBuilder not found", make sure you have enabled the sys feature:

[dependencies]
netmap-rs = { version = "0.3", features = ["sys"] }

Runtime Errors

"Failed to open interface"

Common causes:

  1. Permission issues: You need root/sudo access to use netmap

    sudo ./your_program
  2. Interface doesn't exist: Check available interfaces with:

    ip link show
  3. Netmap kernel module not loaded:

    sudo insmod netmap.ko
  4. Driver not supported: Not all network drivers support netmap. Check supported drivers:

    cd netmap/LINUX
    ./configure --show-drivers

"Operation would block"

This is normal behavior when the ring buffer is full or empty. Implement proper retry logic in your application.

Advanced Usage

Thread-per-Ring Pattern

For maximum performance, dedicate threads to individual rings:

use netmap_rs::prelude::*;
use std::thread;

fn main() -> Result<(), Error> {
    let nm = NetmapBuilder::new("eth0")
        .num_tx_rings(4)
        .num_rx_rings(4)
        .build()?;

    let mut handles = vec![];

    // Spawn RX threads
    for i in 0..nm.num_rx_rings() {
        let rx_ring = nm.rx_ring(i)?;
        let handle = thread::spawn(move || {
            // Process packets on this ring
            // ...
        });
        handles.push(handle);
    }

    // Spawn TX threads
    for i in 0..nm.num_tx_rings() {
        let tx_ring = nm.tx_ring(i)?;
        let handle = thread::spawn(move || {
            // Send packets on this ring
            // ...
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    Ok(())
}

Async Support

Enable the tokio-async feature for async/await support:

use netmap_rs::tokio_async::*;
use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let nm = TokioNetmap::new("eth0").await?;
    let mut rx_ring = nm.async_rx_ring(0).await?;
    
    loop {
        if let Some(frame) = rx_ring.recv().await? {
            println!("Received: {:?}", frame.payload());
        }
        sleep(Duration::from_millis(10)).await;
    }
}

Examples

The examples/ directory contains several complete examples:

  • ping_pong.rs - Basic send/receive example
  • sliding_window_arq.rs - Reliable delivery with ARQ
  • fec.rs - Forward Error Correction
  • thread_per_ring.rs - Thread-per-ring pattern

Run examples with:

cargo run --example ping_pong --features sys

Performance Tips

  1. Use batch operations where possible to amortize system call overhead
  2. Pin threads to cores using core_affinity for consistent performance
  3. Pre-allocate buffers to avoid allocation during packet processing
  4. Use multiple rings to leverage multi-core systems
  5. Consider NUMA topology when pinning threads to cores

License

This project is licensed under either of:

at your option.

AUTHOR

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Acknowledgments

  • The Netmap project for the excellent kernel-bypass networking framework
  • The Rust community for the safe systems programming language

About

Safe, zero-cost abstractions for Netmap kernel-bypass networking for Rust Language.

Topics

Resources

License

Unknown, MIT licenses found

Licenses found

Unknown
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Contributors 2

  •  
  •