Running the Forwarder
This page explains how to configure and run ndn-fwd as a standalone NDN forwarder, connect applications and tools to it, and monitor its state.
Architecture overview
The forwarder is the central forwarding engine. Applications, remote peers, and management tools connect to it through various face types:
%%{init: {"layout": "elk"}}%%
graph TB
subgraph "ndn-fwd"
E[Forwarding Engine]
PIT[PIT]
FIB[FIB]
CS[Content Store]
E --- PIT
E --- FIB
E --- CS
end
subgraph "Local Applications"
App1["ndn-ping<br/>(SHM + Unix socket)"]
App2["Custom App<br/>(SHM + Unix socket)"]
end
subgraph "Remote Peers"
R1["Router B<br/>(UDP 6363)"]
R2["Router C<br/>(TCP 6363)"]
end
subgraph "Link-Local"
MC["Multicast Peers<br/>(224.0.23.170:56363)"]
end
subgraph "Browser / Remote"
WS["Web Client<br/>(WebSocket 9696)"]
end
subgraph "Management"
CTL["ndn-ctl"]
DASH["ndn-dashboard"]
end
App1 <-->|face socket| E
App2 <-->|face socket| E
R1 <-->|UDP| E
R2 <-->|TCP| E
MC <-->|UDP multicast| E
WS <-->|WebSocket| E
CTL -->|face socket| E
DASH -->|WebSocket / NDN| E
Configuration file
ndn-fwd reads a TOML configuration file. Start from the provided example:
cp ndn-fwd.example.toml ndn-fwd.toml
The file is loaded via --config (or -c) or the NDN_CONFIG environment variable.
Minimal configuration
๐ฏ Tip: The three most impactful config options are
cs_capacity_mb(how much RAM to dedicate to caching), the[[face]]entries (which transports to enable), and the[[route]]entries (where to forward Interests). Start with the minimal config below and add complexity as needed.
A minimal config to get started with UDP and multicast:
[engine]
cs_capacity_mb = 64
# UDP unicast face -- listen for incoming packets
[[face]]
kind = "udp"
bind = "0.0.0.0:6363"
# IPv4 multicast face -- link-local neighbor discovery
[[face]]
kind = "multicast"
group = "224.0.23.170"
port = 56363
# Static route: forward all /ndn Interests out the UDP face
[[route]]
prefix = "/ndn"
face = 0
cost = 10
[management]
transport = "ndn"
face_socket = "/run/nfd/nfd.sock"
[logging]
level = "info"
Full face type reference
UDP unicast
Point-to-point or open UDP face on port 6363 (the NDN default):
[[face]]
kind = "udp"
bind = "0.0.0.0:6363"
# Optional: restrict to a single remote peer
# remote = "10.0.0.1:6363"
TCP
Outbound connection to a remote router:
[[face]]
kind = "tcp"
remote = "192.168.1.1:6363"
# Optional: local bind address
# bind = "0.0.0.0:6363"
Multicast
Link-local neighbor discovery using the IANA-assigned NDN multicast group:
[[face]]
kind = "multicast"
group = "224.0.23.170"
port = 56363
# Optional: bind to a specific interface
# interface = "eth0"
Raw Ethernet multicast
Uses EtherType 0x8624 (IANA-assigned for NDN). Requires CAP_NET_RAW on Linux or root on macOS:
[[face]]
kind = "ether-multicast"
interface = "eth0"
Unix domain socket
Local app connectivity on Linux/macOS:
[[face]]
kind = "unix"
path = "/tmp/ndn-app.sock"
WebSocket
For browser clients or remote NDN-WS connections. Requires the websocket feature (enabled by default):
# Listen mode
[[face]]
kind = "web-socket"
bind = "0.0.0.0:9696"
# Or connect mode (mutually exclusive with bind)
# [[face]]
# kind = "web-socket"
# url = "ws://remote:9696"
Serial
Point-to-point over RS-232 / USB-serial. Requires the serial feature (enabled by default):
[[face]]
kind = "serial"
path = "/dev/ttyUSB0"
baud = 115200
Content store configuration
[cs]
variant = "lru" # "lru", "sharded-lru", or "null"
capacity_mb = 64
# shards = 4 # only for "sharded-lru"
admission_policy = "default" # "default" or "admit-all"
Static routes
Routes pre-load the FIB at startup. The face field is a zero-based index into the [[face]] list:
[[route]]
prefix = "/ndn"
face = 0
cost = 10
[[route]]
prefix = "/localhop"
face = 1
cost = 5
Routes can also be added at runtime via ndn-ctl.
Discovery
Enable neighbor discovery and service announcement:
[discovery]
node_name = "/ndn/site/router1"
profile = "lan" # "static", "lan", "campus", "mobile", etc.
served_prefixes = ["/ndn/site/sensors"]
Starting the forwarder
โ ๏ธ Important:
sudois required when the forwarder uses raw sockets (Ethernet faces), privileged ports (UDP/TCP on port 6363 < 1024 on some systems), or multicast group membership. If you only use Unix socket faces and high-numbered ports,sudois not needed. On Linux, you can alternatively grantCAP_NET_RAWandCAP_NET_BIND_SERVICEcapabilities instead of running as root.
# Build in release mode for production
cargo build -p ndn-fwd --release
# Start (sudo required for raw sockets and privileged ports)
sudo ./target/release/ndn-fwd --config ndn-fwd.toml
Override the log level at runtime:
sudo ./target/release/ndn-fwd --config ndn-fwd.toml --log-level debug
# Or with RUST_LOG for per-crate control
sudo RUST_LOG="info,ndn_engine=debug,ndn_discovery=trace" \
./target/release/ndn-fwd --config ndn-fwd.toml
Connecting tools
ndn-ctl
ndn-ctl is the management CLI, similar to NFDโs nfdc. It connects to the forwarderโs face socket and sends management commands as NDN Interest/Data:
# Check forwarder status
ndn-ctl status
# List active faces
ndn-ctl face list
# Create a new UDP face at runtime
ndn-ctl face create udp4://192.168.1.1:6363
# Add a route
ndn-ctl route add /ndn --face 1 --cost 10
# List routes
ndn-ctl route list
# View content store info
ndn-ctl cs info
# List discovered neighbors
ndn-ctl neighbors list
# Announce / withdraw service prefixes
ndn-ctl service announce /ndn/myapp
ndn-ctl service withdraw /ndn/myapp
# Browse discovered services
ndn-ctl service browse
# Set forwarding strategy for a prefix
ndn-ctl strategy set /ndn --strategy /localhost/nfd/strategy/best-route
# Graceful shutdown
ndn-ctl shutdown
ndn-ping
Measure round-trip time to a named prefix. Run the server on one machine and the client on another (or the same machine):
# Server: register /ping and respond to ping Interests
sudo ndn-ping server --prefix /ping
# Client: send ping Interests and measure RTT
ndn-ping client --prefix /ping --count 10 --interval 1000
ndn-peek and ndn-put
Fetch or publish a single named Data packet:
# Fetch a packet by name
ndn-peek /ndn/example/data --timeout-ms 4000
# Publish a packet (another terminal)
ndn-put /ndn/example/data --content "hello"
ndn-iperf
Throughput measurement between two NDN endpoints:
# Server
sudo ndn-iperf server --prefix /iperf
# Client
ndn-iperf client --prefix /iperf --duration 10
Monitoring with ndn-dashboard
ndn-dashboard is a native desktop application (built with Dioxus) for managing and monitoring NDN forwarders. It communicates with the forwarder via the NDN management protocol over the face socket.
cargo build -p ndn-dashboard --release
./target/release/ndn-dashboard
The dashboard provides:
- Start Forwarder โ launch
ndn-fwdas a managed subprocess with one of:- Quick Start (built-in defaults)
- Build Config โ interactive config builder with startup faces, startup routes, CS settings, and log level
- Load Config File โ point to an existing TOML file
- Saved Presets โ one-click relaunch of saved configurations
- Overview โ engine status, packet counters, throughput graphs
- Faces โ active faces with per-face traffic statistics
- Routes โ FIB entries and nexthop costs
- Content Store โ cache occupancy and hit/miss rates
- Strategy โ per-prefix forwarding strategy assignments
- Config โ view and edit forwarder configuration; edit startup faces and routes; restart the managed forwarder with an updated config via โบ Restart with Config
- Logs โ real-time log viewer with filter and split-pane modes
- Tools โ embedded
ndn-ping,ndn-iperf,ndn-peek, andndn-put - Light/Dark mode โ toggle via the โ/๐ button in the toolbar
The dashboard connects to the forwarderโs face socket (default /run/nfd/nfd.sock). If the forwarder is started through the dashboard, log output is captured in the Logs view automatically.
Typical deployment
A common LAN deployment with two forwarders and local apps:
# Router A (10.0.0.1) -- ndn-fwd.toml:
# UDP face on :6363
# Multicast face on 224.0.23.170:56363
# Route /ndn -> UDP face
# Discovery enabled with node_name = "/ndn/site/routerA"
# Router B (10.0.0.2) -- same config with:
# remote = "10.0.0.1:6363" on the UDP face for a static tunnel
# node_name = "/ndn/site/routerB"
# On Router A, start a ping server:
sudo ndn-ping server --prefix /ndn/site/routerA/ping
# From Router B, ping across the link:
ndn-ping client --prefix /ndn/site/routerA/ping --count 5
Next steps
- Installation โ build options and feature flags
- Hello World โ embedded engine tutorial
- Discovery Protocols โ how neighbor and service discovery work
- Performance Tuning โ optimize
pipeline_threads, CS sharding, and SHM