sb_demo.mp4
Switchboard manages Cisco switches from a web browser via netbird-wasm. There is no backend, Switchboard is able to communicate via SSH/gNMI/RESTCONF/HTTPS through a remote netbird peer.
- Node.js 20.19 or later, or 22.12 or later (Vite 7 needs one of these)
- Go 1.25 or later, to build the protocol module
- A NetBird setup key
- A NetBird peer that routes to the switch
- Install the dependencies:
npm install
- Start the development server:
npm run dev
- Open
https://localhost:5173in the browser.
- Open
/v2. - Enter the NetBird setup key and the management URL. Then connect.
- Add a device. Give it a name and an IP address.
- Open the device.
Switchboard keeps the setup key and the device list in localStorage. It sends this data to no server.
The main screen provides a high-level overview of the switch and interfaces.
The terminal opens an SSH session to the switch.
The endpoint tab joins the MAC table, the ARP table, and the LLDP neighbors.
The diagnostics tab runs three tools on the switch. Cable diagnostics (TDR) tests each pair. Reachability runs ping and traceroute. Packet capture creates a downloadable pcap.
| Command | What it does |
|---|---|
npm run dev |
Start the development server on port 5173 |
npm run build |
Build the production files into build/ |
npm run preview |
Serve the production build |
npm run check |
Run svelte-check |
npm run build:protocol |
Rebuild the Go protocol module |
| Path | Contents |
|---|---|
src/routes/v2/ |
The current user interface |
src/routes/switch/ |
The first prototype interface |
src/lib/netbird/ |
The NetBird worker and its main-thread client |
src/lib/protocol/ |
The protocol worker and its main-thread client |
wasm-protocol/ |
Go source for the protocol module |
scripts/build-protocol.sh |
Builds the protocol module to wasm-protocol/build/ |
Switchboard runs two WebAssembly modules, each in its own web worker.
Worker 1 runs the netbird-wasm SDK. It makes the browser tab a WireGuard peer on the overlay network, and it opens raw TCP and UDP sockets to the switch through remote NetBird peers.
Worker 2 runs switchboard's protocol module, under wasm-protocol/. This Go program speaks HTTPS for RESTCONF, SSH for the terminal, and gRPC for gNMI. It receives sockets from worker 1 through the SDK bridge, and treats each one as an ordinary net.Conn.
Each module is a separate program with its own Go runtime, and each runtime owns the thread that it runs on. Two workers therefore let the tunnel and the protocol work run at the same time, clear of the thread that draws the user interface.
flowchart LR
subgraph tab["Browser tab"]
direction TB
main["Main thread<br/>user interface<br/>control plane"]
subgraph w1["Worker 1"]
nb["netbird-wasm SDK<br/>WireGuard peer<br/>raw TCP and UDP"]
end
subgraph w2["Worker 2"]
proto["switchboard protocol module<br/>Go: HTTPS · SSH · gNMI"]
end
end
relay(["NetBird relay"])
peer["Remote NetBird peer"]
sw["Cisco switch"]
main -- "connect · status · ping" --> nb
main -- "http · ssh · gnmi calls" --> proto
proto == "dial request" ==> nb
nb == "socket, as a MessagePort" ==> proto
nb -- "WireGuard over WebSocket" --> relay
relay --> peer
peer --> sw
When the protocol module needs a socket, it calls switchboardDial(). Worker 1 dials the socket, bridges it, and sends back one end of a MessagePort. Worker 2 then treats that port as an ordinary network connection.
sequenceDiagram
autonumber
participant P as Page
participant PW as Worker 2 · protocol
participant NW as Worker 1 · netbird
participant SW as Switch
P->>PW: http.get(url)
PW->>NW: switchboardDial(host, 443)
NW->>NW: dialTcp, then connectionToPort
NW-->>PW: MessagePort
Note over PW,SW: The TLS handshake and the HTTP<br/>request travel on this socket.
PW->>SW: GET /restconf/data/...
SW-->>PW: 200, and the JSON body
PW-->>P: status, headers, body




