smoltcp

repository·main·Indexed 26 days ago

https://github.com/smoltcp-rs/smoltcp

A standalone, event-driven TCP/IP stack designed for bare-metal and real-time systems. smoltcp operates without heap allocation and prioritizes simplicity and robustness. It features a layered architecture consisting of Socket, Interface, Physical, and Wire layers, supporting protocols such as IPv4, IPv6, TCP, UDP, ICMP, and DNS.

Tokens
8.9K
Snippets
22
Records
68
Agent score
88%

What's inside smoltcp

  1. Set up a bridged connection for DHCP support

    main

    To run DHCP examples, you can set up a bridged (switched) connection that allows smoltcp to speak directly to your LAN.

    Note: This only works with wired Ethernet connections, not WiFi. You must replace ETH with your actual wired interface name (e.g., enp0s20f0u1u1).

    # Replace with your wired Ethernet interface name
    ETH=enp0s20f0u1u1
    
    sudo modprobe bridge
    sudo modprobe br_netfilter
    
    sudo sysctl -w net.bridge.bridge-nf-call-arptables=0
    sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=0
    sudo sysctl -w net.bridge.bridge-nf-call-iptables=0
    
    sudo ip tuntap add name tap0 mode tap user $USER
    sudo brctl addbr br0
    sudo brctl addif br0 tap0
    sudo brctl addif br0 $ETH
    sudo ip link set tap0 up
    sudo ip link set $ETH up
    sudo ip link set br0 up
    
    # Connect host system to internet
    sudo dhcpcd br0

    To tear down the bridge:

    sudo killall dhcpcd
    sudo ip link set br0 down
    sudo brctl delbr br0
    ETH=enp0s20f0u1u1
    
    sudo modprobe bridge
    sudo modprobe br_netfilter
    
    sudo sysctl -w net.bridge.bridge-nf-call-arptables=0
    sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=0
    sudo sysctl -w net.bridge.bridge-nf-call-iptables=0
    
    sudo ip tuntap add name tap0 mode tap user $USER
    sudo brctl addbr br0
    sudo brctl addif br0 tap0
    sudo brctl addif br0 $ETH
    sudo ip link set tap0 up
    sudo ip link set $ETH up
    sudo ip link set br0 up
    
    sudo dhcpcd br0
  2. Set up a persistent tap interface for Linux userspace testing

    main

    Since smoltcp is a freestanding stack, testing in userspace on Linux requires a persistent tap interface. This allows a specific user to manipulate raw frames without requiring constant superuser privileges. Use the following commands to create and configure tap0 with IPv4 and IPv6 support:

    sudo ip tuntap add name tap0 mode tap user $USER
    sudo ip link set tap0 up
    sudo ip addr add 192.168.69.100/24 dev tap0
    sudo ip -6 addr add fe80::100/64 dev tap0
    sudo ip -6 addr add fdaa::100/64 dev tap0
    sudo ip -6 route add fe80::/64 dev tap0
    sudo ip -6 route add fdaa::/64 dev tap0
    sudo ip tuntap add name tap0 mode tap user $USER
    sudo ip link set tap0 up
    sudo ip addr add 192.168.69.100/24 dev tap0
    sudo ip -6 addr add fe80::100/64 dev tap0
    sudo ip -6 addr add fdaa::100/64 dev tap0
    sudo ip -6 route add fe80::/64 dev tap0
    sudo ip -6 route add fdaa::/64 dev tap0
  3. Install smoltcp via Cargo

    main

    To use smoltcp in your Rust project, add it to your Cargo.toml dependencies.

    By default, smoltcp assumes a hosted environment. For bare-metal or resource-constrained systems, it is recommended to disable default features and enable only the specific ones you need.

    # Standard installation
    [dependencies]
    smoltcp = "0.10.0"
    
    # Recommended for bare-metal: disable default features and pick specific ones
    [dependencies]
    smoltcp = { version = "0.10.0", default-features = false, features = ["log"] }
  4. Enable Internet access for tap interface via routing

    main

    To allow smoltcp to access the Internet through the tap0 interface, enable IP forwarding and set up MASQUERADE rules using iptables and ip6tables:

    sudo iptables -t nat -A POSTROUTING -s 192.168.69.0/24 -j MASQUERADE
    sudo sysctl net.ipv4.ip_forward=1
    sudo ip6tables -t nat -A POSTROUTING -s fdaa::/64 -j MASQUERADE
    sudo sysctl -w net.ipv6.conf.all.forwarding=1
    
    # Allow traffic through the forward chain
    sudo iptables -A FORWARD -i tap0 -s 192.168.69.0/24 -j ACCEPT
    sudo iptables -A FORWARD -o tap0 -d 192.168.69.0/24 -j ACCEPT
    sudo iptables -t nat -A POSTROUTING -s 192.168.69.0/24 -j MASQUERADE
    sudo sysctl net.ipv4.ip_forward=1
    sudo ip6tables -t nat -A POSTROUTING -s fdaa::/64 -j MASQUERADE
    sudo sysctl -w net.ipv6.conf.all.forwarding=1
    
    # Some distros have a default policy of DROP. This allows the traffic.
    sudo iptables -A FORWARD -i tap0 -s 192.168.69.0/24 -j ACCEPT
    sudo iptables -A FORWARD -o tap0 -d 192.168.69.0/24 -j ACCEPT
  5. Understand the smoltcp layered architecture

    main

    smoltcp is organized into several layers of abstraction. While typical applications only interact with the highest layers, all layers are exposed for use as networking primitives:

    • Socket Layer (socket): Provides buffering, packet construction/validation, and state machines for raw, ICMP, TCP, and UDP sockets. It is interface-agnostic.
    • Interface Layer (iface): Handles control messages, physical addressing, and neighbor discovery. It routes packets between sockets and the physical layer.
    • Physical Layer (phy): Handles interaction with platform-specific network devices (e.g., TAP interfaces). Includes middleware like tracer (for packet printing) and fault injector (for error simulation).
    • Wire Layers (wire): The bedrock of the stack. Consists of:
      • Representation Layer: Reduces the state space of raw packets by shedding invalid or unsupported features.
      • Packet Layer: Provides structured access to packet fields without making judgments about content.
  6. Configure smoltcp compile-time settings

    main

    Certain configuration settings affecting buffer sizes and counts are set at compile time. You can configure these using two methods:

    1. Cargo Features: Enable a feature following the pattern <name>-<value>. Note that names must be lowercase and use dashes instead of underscores (e.g., iface-max-addr-count-3).
    2. Environment Variables: Set a variable named SMOLTCP_<VALUE> during build (e.g., SMOLTCP_IFACE_MAX_ADDR_COUNT=3 cargo build). You can also set these in the [env] section of .cargo/config.toml.

    Precedence: Environment variables take precedence over Cargo features. If two different Cargo features attempt to set the same configuration to different values, compilation will fail.

  7. Configure smoltcp features for IP and Sockets

    main

    smoltcp requires specific feature flags to be enabled to function. Depending on your requirements, you must satisfy the following constraints:

    IP Layer Requirements

    You must enable at least one of these IP protocol features:

    • proto-ipv4
    • proto-ipv6
    • proto-sixlowpan

    Socket Layer Requirements

    If you enable the socket feature, you must also enable at least one specific socket type:

    • socket-raw
    • socket-udp
    • socket-tcp
    • socket-icmp
    • socket-dhcpv4
    • socket-dns

    Medium/Interface Requirements

    If you enable the socket feature, you must also enable a compatible medium:

    • medium-ip
    • medium-ethernet
    • medium-ieee802154

    Logging Constraints

    You can use either defmt or log for logging, but not both. Enabling both will cause a compilation error.

  8. Run the server example

    main

    The server example emulates a network host that responds to various requests (Ping, UDP, TCP) on specific ports. It is useful for testing resource exhaustion due to its small buffer sizes (64 bytes for most ports).

    Usage: cargo run --example server -- --tap <INTERFACE>

    Example:

    cargo run --example server -- --tap tap0

    Supported Services:

    • ICMP: Responds to pings.
    • UDP Port 6969: Responds with reversed chunks of input.
    • TCP Port 6969: Responds "hello" and closes.
    • TCP Port 6970: Responds with reversed chunks of input.
    • TCP Port 6971: Sinks data; has keep-alive and user timeouts enabled.
    • TCP Port 6972: Sources data.
    cargo run --example server -- --tap tap0
  9. Run the client example

    main

    The client example emulates a host that initiates basic requests and responds with reversed chunks of input.

    Usage: cargo run --example client -- --tap <INTERFACE> <ADDRESS> <PORT>

    Example:

    cargo run --example client -- --tap tap0 192.168.69.1 1234
  10. Run the benchmark example

    main

    The benchmark example implements a simple throughput benchmark by establishing a connection to itself and reading or writing large amounts of data.

    Usage: cargo run --release --example benchmark -- --tap <INTERFACE> [reader|writer]

    Example (Reader):

    cargo run -q --release --example benchmark -- --tap tap0 reader

    Example (Writer):

    cargo run -q --release --example benchmark -- --tap tap0 writer
    cargo run -q --release --example benchmark -- --tap tap0 reader
  11. Run the ping example

    main

    The ping example implements a minimal version of the ping utility using raw sockets. It sends 4 ICMP ECHO_REQUEST packets at one-second intervals.

    Usage: cargo run --example ping -- --tap <INTERFACE> <ADDRESS>

    Example:

    cargo run --example ping -- --tap tap0 192.168.69.100
  12. Run the tcpdump example

    main

    The tcpdump example is a clone of the tcpdump utility. Unlike other examples, it uses raw sockets and can be used on regular interfaces (e.g., eth0) or the tap0 interface.

    cargo build --example tcpdump
    sudo ./target/debug/examples/tcpdump eth0
    cargo build --example tcpdump
    sudo ./target/debug/examples/tcpdump eth0