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](http://info.iet.unipi.it/~luigi/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`.

```toml
[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:

```toml
[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.

```rust
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](http://info.iet.unipi.it/~luigi/netmap/) or the [Netmap GitHub repository](https://github.com/netmap/netmap) 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`:
    ```bash
    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:

```bash
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`:
```bash
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
*   Apache License, Version 2.0, ([LICENSE-APACHE]LICENSE-APACHE).
*   MIT license ([LICENSE-MIT]LICENSE-MIT).