Face transports
Catalogue of face transports shipped in ndn-rs, each row pointing at the
implementation crate, the [[face]] kind value, and the typical use. For the
Face = Transport + LinkService shape see Extend tier → Face;
for writing a new transport see Implementing a face.
Catalogue
| Kind | Crate | [[face]] kind | Typical use |
|---|---|---|---|
| UDP | crates/ndn-face/src/net/udp.rs | udp | NDN-over-UDP across hosts. |
| TCP | crates/ndn-face/src/net/tcp.rs | tcp | NDN-over-TCP across hosts (firewall-friendlier). |
| Multicast UDP | crates/ndn-face/src/net/multicast.rs | multicast | Link-local neighbour discovery (group 224.0.23.170); auto-created per interface via [face_system.udp] auto_multicast. |
| Unix socket | crates/ndn-face/src/local/unix.rs | unix | App-to-forwarder IPC. |
| In-process | crates/ndn-face/src/local/in_proc.rs | (programmatic) | Embedded engine, tests. |
| Shared memory | crates/ndn-face-shm/src/spsc.rs | shm | High-throughput per-host IPC (feature spsc-shm). |
| Ethernet unicast | crates/ndn-face/src/l2/ether.rs | ether (TOML) or faces/create ether://[<mac>]/<iface> | Point-to-point link to a known peer MAC. EtherType 0x8624; requires CAP_NET_RAW/root. |
| Ethernet multicast | crates/ndn-face/src/l2/multicast_ether.rs | ether-multicast | Group 01:00:5e:00:17:aa; auto-created per interface via [face_system.ether] auto_multicast (Linux). |
| 802.11 monitor-mode | crates/ndn-face-monitor-wifi/ | wfb | Connectionless raw 802.11 injection (named-radio): MonitorWifiFace over a FrameIo backend (ndn-frame-io). |
| Bluetooth LE — central | crates/ndn-face-bluetooth/src/central/ | ble://<name-or-addr> (via faces/create) | Dial a peripheral as GATT client (Linux/macOS/Windows). |
| Bluetooth LE — peripheral | crates/ndn-face-bluetooth/src/lib.rs | [listeners.ble] | GATT server; advertises the NDN service (Linux/macOS). |
| Serial (UART) | crates/ndn-face-serial/src/lib.rs | serial | Embedded / microcontroller. |
| WebSocket | crates/ndn-face-websocket/ | ws | Browser-to-forwarder over WebSocket. |
| WebTransport | crates/ndn-face-webtransport/; wasm: crates/ndn-face-webtransport-wasm/ | [listeners.webtransport]; dial via [[face]] kind = "web-transport" or faces/create wts://… | Browser↔forwarder and forwarder↔forwarder (NAT-traversing) over QUIC datagrams; oversized packets are NDNLPv2-fragmented to maxDatagramSize (interoperates with NDNts H3Transport). |
| QUIC | crates/ndn-face-quic/ | [listeners.quic]; dial via [[face]] kind = "quic" or faces/create quic://… | Forwarder-to-forwarder backbone over raw QUIC (TLS 1.3, connection migration, 0-RTT); one reliable bidi stream of NDN TLV. No HTTP/3 layer (does not reach browsers). |
| WebRTC datachannel | crates/ndn-face-webrtc/ | webrtc | Browser ↔ browser, browser ↔ relay. |
| SharedWorker | crates/ndn-face-shared-worker/ | (programmatic) | Per-origin engine sharing across tabs. |
| Callback / Tap | crates/ndn-face/src/callback.rs | (Instrument tier) | Researcher: virtual face whose send-path is a closure. |
| BoltFFI | crates/ndn-boltffi/ | (programmatic) | FFI bridge for non-Rust hosts. |
Configuration shape
UDP unicast face listener:
[[face]]
kind = "udp"
bind = "0.0.0.0:6363"
# remote = "10.0.0.1:6363" # optional: point-to-point only
TLS faces — WebTransport (browser↔forwarder and NAT-traversing
forwarder↔forwarder over QUIC datagrams) and QUIC (native router-to-router
backbone, TLS 1.3 with connection migration) — share one listener cert_source
shape (self_signed_dev / pem / acme, resolved by ndn-acme) and one
dialer trust policy (cert_sha256 leaf-pin or webpki):
[listeners.webtransport] # or [listeners.quic]
enabled = true
listen = "0.0.0.0:4443"
cert_source = { type = "self_signed_dev", hostnames = ["localhost"] }
[[face]] # outbound dial
kind = "web-transport" # or "quic"
remote = "wts://peer.example:4443"
cert_sha256 = "ab12…64hex" # pin the peer's logged leaf hash; or webpki = true
A self-signed WebTransport cert is capped at 13 days (Chrome’s
serverCertificateHashes limit); a self-signed QUIC cert is long-lived (a
pinned dialer trusts the leaf hash, not the expiry). Listener cert status
(notAfter, renewal state) is readable via
/localhost/nfd/webtransport/cert-status. The WebTransport face interoperates
with ndnd’s HTTP/3 face (witness testbed/tests/audit/wt02_ndnd_interop.sh);
QUIC does not reach browsers — that is WebTransport’s role.
A shared-memory face (kind = "shm", path, capacity_mb) gives per-host IPC.
The full per-kind option set is in examples/ndn-fwd.example.toml.
Ethernet faces (EtherType 0x8624, CAP_NET_RAW/root) come in three forms — a
unicast link to a known peer MAC, a multicast group face, and per-interface
auto-creation:
[[face]] # unicast point-to-point
kind = "ether"
interface = "eth0"
peer-mac = "aa:bb:cc:dd:ee:ff"
[[face]] # multicast group face (Linux)
kind = "ether-multicast"
interface = "eth0"
[face_system.ether] # auto-create a multicast face per matching NIC
auto_multicast = true # + add/remove on hotplug with watch_interfaces
A unicast Ethernet face can also be created at runtime:
nfdc face create ether://[aa:bb:cc:dd:ee:ff]/eth0. The peer MAC is explicit —
neighbour discovery is a separate path. As with every wire face, NDNLPv2
framing and fragmentation are owned by the paired LpLinkService: the face is
payload-only and reports a 1500-byte send-MTU, so the link service fragments
once at the Ethernet boundary (it does not re-frame at the transport).
Bluetooth LE
BLE has two roles, modelled as distinct faces (central and peripheral are
distinct GATT roles, not a flag): a central dials a peripheral as GATT
client, a peripheral runs the GATT server. Both use the NDNts
web-bluetooth-transport GATT profile, so they interoperate with browser Web
Bluetooth and esp8266ndn. Requires ndn-fwd --features bluetooth. The wire
rules — UUIDs, the NDNLPv2-vs-NDNts framing split, and its automatic
disambiguation — are normative in
NDN over BLE — GATT profile.
A central is an outgoing face created at runtime via faces/create with a
ble:// URI (ble://ndn-rs-esp32c3, ble://AA:BB:CC:DD:EE:FF); ?framing=
and ?adapter= ride the query string, other per-face knobs go through the
faces module. A peripheral is a listener ([listeners.ble] → enabled = true) whose accept loop yields one face per connected central. Because the
peripheral carries controller state it gets a small management module
/localhost/nfd/ble/<verb>: list (status: advertising, adapter, central
count), start and stop (toggle advertising at runtime). The module returns
404 without --features bluetooth.
Programmatic faces (not in ndn-fwd.toml)
Some faces are constructed by application code rather than by listener config:
InProcFace— created in the same process, paired between two engines. The pattern is in Develop tier → embedded engine.CallbackFace/TapFace— Instrument tier. See Instrument tier.- SharedWorker face —
crates/ndn-face-shared-worker/. Mounted via the dashboard’s browser-engine profile.
Connectionless named-radio faces — extension
These are ndn-rs extensions with no NDN community-spec basis; the wire is ordinary NDNLPv2 over the radio’s native broadcast primitive.
A node — especially a phone — can carry NDN over connectionless broadcast
radios with no AP, no pairing, and no host addresses (the NDN name is the
only addressing). Each is link_type() == AdHoc with a small MTU, so the
LpLinkService fragments NDN across the radio’s frames automatically.
| Face | Crate | Radio primitive | Notes |
|---|---|---|---|
| Wi-Fi Aware (NAN) | crates/ndn-face-wifi-aware/ | NAN follow-up messages (255 B) | AP-less peer Wi-Fi; service pub/sub discovery; bulk over NDP (request_ndp → UdpFace). |
| BLE advertising | crates/ndn-face-ble-adv/ | BLE 5 extended advertisement (~245 B) | Near-universal; pairless broadcast; presence + small Interest/Data (bulk wants a connection face). |
| 802.11 monitor | crates/ndn-face-monitor-wifi/ | raw-injected 802.11 frames | Per-frame MCS, no association/ARQ. |
The physical radio sits behind a backend trait (NanBackend, AdvBackend)
with a hardware-free Loopback*Bus for tests, so the face is exercised without
hardware; a platform supplies the radio by implementing the trait (Android JNI,
BlueZ, an MCU). These faces are not mutually exclusive — a node holds a set
of them at once and a mesh strategy fans Interests over all (see the
Face system section of ARCHITECTURE.md in the repo root). On mobile they’re
attached at runtime via ndn-mobile (attach_wifi_aware / attach_ble) or the
ndn-boltffi FFI seam (NdnNanBackend / NdnBleBackend + the engine’s
*_deliver_* methods); nearby peers surface at the localhost dataset
/localhost/discovery/peers.
Tap-to-share over these faces (extension). To send a file to a tapped peer,
an app serves an offer board (NdnEngine/NdnClient::start_offer_board): a
certificate at /ndn/node/<id>/cert (the TOFU pin target) and a signed manifest
at /ndn/node/<id>/offers, both reached over the per-peer route with no hint.
Each offered file (add_offer) is a signed RDR object under the offerer’s own
identity, fetched by a peer with fetch_object_verified_hinted(name, "/ndn/node/<peerId>") — the ForwardingHint steers it to the peer, whose node
strips the hint via its NetworkRegionTable (declared at discovery start) and
serves it by name. See the Connectionless named-radio faces section of
ARCHITECTURE.md for the full flow.
Wi-Fi Direct bulk upgrade — extension
The connectionless radios above are great for discovery and small control but
are duty-cycled or small-MTU, so bulk transfer wants a real Wi-Fi link. The
pattern (the same one Quick Share / AirDrop use) is discover over Wi-Fi Aware
/ BLE, then upgrade to Wi-Fi Direct for bulk. Crucially this stays
data-centric: once a Wi-Fi P2P group forms it is just a multi-access IP subnet
(the group owner runs DHCP on 192.168.49.0/24), so the host-centric
group-owner election and DHCP live entirely below the Face. Above it there is
no host — only FaceKind::WifiDirect faces carrying names:
| Use | Face | Notes |
|---|---|---|
| 1:1 bulk | UdpFace::with_kind(WifiDirect) (unicast) | Full Wi-Fi MCS rate (5 GHz); LinkProfile cost 8 so cost-aware forwarding prefers it over NDP/LAN UDP (10), Wi-Fi Aware (20), BLE (50). |
| One-to-many | MulticastUdpFace::with_kind(WifiDirect) | Join 224.0.23.170:56363 on the group interface; MulticastStrategy + PIT aggregation give one-Interest-to-many, one-Data-to-many — the “seed a file to the room” path. Wi-Fi multicast is basic-rate/un-ACKed, so it is for coordination + Interests (and FEC-coded bulk), not raw 1:1 throughput. |
No new crate or Cargo feature — these are the existing UDP faces re-tagged to
the real radio. On mobile they attach via ndn-mobile
(attach_wifi_direct_face / attach_wifi_direct_multicast_face) or the
ndn-boltffi FFI (attachWifiDirectFace / attachWifiDirectMulticastFace),
mirroring the Wi-Fi Aware NDP bulk path (attach_ndp_face). The same shape maps
to a Wi-Fi SoftAP “portable router” (one node provides the medium; peers
join and multicast by name) and to Apple’s Wi-Fi Aware framework on iOS (the
same NAN standard behind NanBackend).
Link service per face
The default LinkService is LpLinkService (NDNLPv2 framing); the
high-throughput exceptions use PassthroughLinkService — InProcFace always,
and ShmFace by default (switch it to LpLinkService for cross-host wire
compatibility). See crates/ndn-transport/src/link_service.rs for the trait.
Per-face NDNLPv2 local fields
IncomingFaceId and NextHopFaceId are NDNLPv2 local fields, gated per-face by
the LocalFields flag (off by default). If IncomingFaceId always reads
0/absent, the face hasn’t enabled LocalFields — enable it first via
faces/update (Flags+Mask bit 0 = LocalFields, 1 = LpReliability, 2 =
CongestionMarking):
ndn-ctl faces update face-id 263 flags 0x1 mask 0x1 # LocalFields on
With it enabled: IncomingFaceId (0x032C) is attached to packets sent out that
face — the face the packet arrived on (or the reserved Content-Store id 254 on
a cache hit), readable from LpInfo (Consumer::fetch_with_meta); and
NextHopFaceId (0x0330) is honoured on Interests arriving on it, pinning an
Interest to an egress face past the FIB (Consumer::fetch_on). A face without
LocalFields ignores NextHopFaceId, so an untrusted peer cannot steer
forwarding. Local-scope only; the bundled routing protocol enables it on its
own faces.
Compile-time gates
| Feature | Carrier crate | Effect |
|---|---|---|
spsc-shm | ndn-face-shm | Enable the shared-memory transport. |
ether-linux | ndn-face | Linux raw-Ethernet face. |
ether-macos | ndn-face | macOS BPF face. |
ether-windows | ndn-face | Windows packet-driver face. |
bluetooth | ndn-face-bluetooth | BLE GATT central (ble://) + peripheral ([listeners.ble]). |
serial | ndn-face-serial | Serial face. |
wasm32 | ndn-face (auto) | WebTransport-wasm + WebRTC + SharedWorker. |
See also
- Implementing a face — author guide.
- Config reference — every
[[face]]listener key. crates/ndn-transport/— the trait surface.