Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Routing Protocols

ndn-rs separates the Routing Information Base (RIB) from the Forwarding Information Base (FIB). Routing protocols compute paths and write them into the RIB; the engine’s FIB is derived automatically.

Architecture

  ┌──────────────┐   ┌──────────────┐   ┌──────────────┐
  │  Static      │   │  DVR         │   │  (future)    │
  │  Protocol    │   │  Protocol    │   │  NLSR / …    │
  └──────┬───────┘   └──────┬───────┘   └──────┬───────┘
         │ origin=255        │ origin=127        │ origin=128
         └──────────────────┴──────────────────►│
                                                 ▼
                                          ┌──────────────┐
                                          │     RIB      │  per-prefix,
                                          │  (ndn-engine)│  per-face, best-cost
                                          └──────┬───────┘
                                                 │ apply_to_fib()
                                                 ▼
                                          ┌──────────────┐
                                          │     FIB      │  longest-prefix match
                                          └──────────────┘

Multiple protocols run concurrently. Each owns routes under a unique origin value. The RIB arbitrates: for each prefix, per face_id, it picks the route with the lowest cost (ties broken by lowest origin value) and writes the result to the FIB atomically.

Route Origins

OriginConstantProtocol
0origin::APPApp-registered via management API
64origin::AUTOREGAuto-registration
65origin::CLIENTClient auto-registration
66origin::AUTOCONFAuto-configuration
127origin::DVRDistance Vector Routing (ndn-routing)
128origin::NLSRNLSR-compatible routing
129origin::PREFIX_ANNPrefix announcements
255origin::STATICStatic routes

Built-in Protocols (ndn-routing)

StaticProtocol

Installs a fixed set of routes at startup and holds them until stopped. Suitable for single-hop links, testing, and hybrid deployments.

#![allow(unused)]
fn main() {
use ndn_routing::{StaticProtocol, StaticRoute};
use ndn_transport::FaceId;

let proto = StaticProtocol::new(vec![
    StaticRoute {
        prefix: "/ndn/edu/ucla".parse()?,
        face_id: FaceId(3),
        cost: 10,
    },
]);
// register with EngineBuilder::routing_protocol(proto)
}

Routes use origin::STATIC (255) and CHILD_INHERIT flags, so /ndn/edu/ucla/cs is also reachable without explicit registration.

DvrProtocol

Distributed Bellman-Ford over NDN link-local multicast. Routes are learned from neighbors and expire if not refreshed (default TTL: 90 s). Features:

  • Split horizon: routes learned via face F are not re-advertised on face F, preventing two-node loops.
  • Periodic updates every 30 s.
  • Face-down cleanup: all routes learned via a downed face are withdrawn immediately.

DVR needs both packet I/O (via discovery context) and RIB write access (via routing handle). It implements both DiscoveryProtocol and RoutingProtocol — register it with both systems:

#![allow(unused)]
fn main() {
use ndn_routing::DvrProtocol;
use ndn_discovery::DiscoveryProtocol;
use std::sync::Arc;

let dvr = DvrProtocol::new(my_node_name.clone());

let engine = EngineBuilder::new()
    .discovery(Arc::clone(&dvr) as Arc<dyn DiscoveryProtocol>)
    .routing_protocol(Arc::clone(&dvr))
    .build()
    .await?;
}

DVR Wire Format

Advertisements are sent as NDN Interest packets with AppParams:

Interest name:  /ndn/local/dvr/adv
AppParams TLV:
  DVR-UPDATE  (0xD0)
    NODE-NAME (0xD1)  — sender's NDN node name
    ROUTE*    (0xD2)  — zero or more routes
      PREFIX  (0xD3)  — Name TLV
      DVR-COST(0xD4)  — big-endian u32

Packets with this name are consumed by on_inbound and never reach the forwarding pipeline.

Compatibility with ndnd DVR

The ndn-rs DVR is not interoperable with ndnd’s dv module. ndnd uses a fundamentally different architecture:

ndn-rs DVRndnd DV
Sync mechanismPeriodic broadcast InterestSVS v3 state-vector sync
Name prefix/ndn/local/dvr/adv/localhop/<network>/32=DV/32=ADS/ACT
Advertisement unit(prefix, cost)(router, nexthop, cost)
Route tableprefix → costrouter → cost, then prefix → router
Cost infinityu32::MAX16
ECMPNoTwo-best-path
Loop preventionSplit horizonPoison reverse + split horizon
SecurityNoneLightVerSec (Ed25519)

For testbed interoperability, a future NLSR-compatible protocol (origin 128) is required. The ndn-rs DVR is designed for private, trust-homogeneous networks only.

RoutingManager

The engine owns a RoutingManager that controls all running protocols:

#![allow(unused)]
fn main() {
// Start a protocol
engine.routing().enable(Arc::new(my_protocol));

// Stop and flush its routes
engine.routing().disable(origin_value);

// Inspect running protocols
let origins: Vec<u64> = engine.routing().running_origins();
}

Disabling a protocol cancels its background task and synchronously flushes all its RIB routes, recomputing the FIB for affected prefixes. Any routes registered by other protocols for the same prefixes are immediately promoted.

RIB Details

The RIB stores RibRoute { face_id, origin, cost, flags, expires_at } per (prefix, face_id, origin) triple. Key invariants:

  • Expiry: routes with expires_at are drained every second by a background task.
  • Face teardown: rib.handle_face_down(face_id, fib) is called automatically when a face goes down, flushing routes via that face and recomputing affected FIB entries.
  • FIB derivation: for each unique face_id, the lowest-cost route across all origins wins. Equal-cost ties break by lowest origin value.

Runtime Configuration

DvrProtocol exposes two parameters that can be changed while the router is running without a restart:

ParameterDefaultDescription
update_interval30 sHow often DVR broadcasts its distance vector
route_ttl90 sExpiry time for DVR-learned routes if not refreshed

Both are stored in an Arc<RwLock<DvrConfig>> shared between the running protocol and the management handler. The management socket exposes them via:

# Read current values
/localhost/nfd/routing/dvr-status   (status dataset)

# Apply new values (URL query string in ControlParameters.Uri)
/localhost/nfd/routing/dvr-config   (command)
# e.g. Uri = "update_interval_ms=15000&route_ttl_ms=45000"

The ndn-dashboard Routing panel provides a GUI for these controls.

See Also