The virtual switch

The library ships working mock switches that speak SNMP, NSDP, HTTP and the FASTPATH CLI on real sockets. Point anything at one: this library, your own code, snmpwalk, curl, a monitoring agent, a configuration-management tool.

ngsw serve --model gsm7228ps
[gsm7228ps] host=127.0.0.1
    SNMP udp/36540
    HTTP tcp/42629
    community='public' http_password='password'
serving 1 mock switch(es); press Ctrl-C to stop

Then, from any tool:

snmpwalk -v2c -c public 127.0.0.1:36540 1.3.6.1.2.1.1

Why you can trust it

A mock is only useful if it behaves like the thing it stands in for. This one is built to a strict rule: where the fake differs from real hardware, the fake is what gets fixed. Never the test’s expectation, and never by making the real-hardware path more forgiving.

Three consequences follow, and they are what distinguish this from a stub:

It reproduces refusals, not just successes. A write the real firmware rejects is rejected here too — with the same SMI error status (commitFailed versus notWritable versus wrongValue), the same preconditions, the same side effects and the same ordering sensitivity. The S3300 mock auto-untags a port when its egress bit is set, and lets that side effect beat an untagged varbind in the same PDU, because that is what the real switch does.

Its values are measured, not computed. The mock is seeded from real device captures. Where a value could be derived, it is deliberately seeded instead — because a mock that derives a value with the same formula as the code under test can only ever agree with that code.

Warning

That is not hypothetical. A VLAN PortList-width defect went unnoticed for a long time because the mock emitted the bitmap using the same wrong formula as the buggy writer. Mock and library agreed with each other while both disagreed with every real switch — whose widths are 79, 131 and 45 bytes, none derivable from the port count. The round trip was green and meaningless. The widths are now seeded from measurement.

Every behaviour learned from hardware is encoded here and pinned by a test, with a comment naming the host and firmware version it was observed on. A finding that lives only in a report gets regressed by the next change.

Tools that know nothing about this library have cross-checked it too. The third-party ProSafeLinux NSDP implementation decodes both mock switches completely, every value matching the seed; the C tool ngadmin validated the packet header — and surfaced a real four-byte sequence-number bug in the process, since fixed. A mock validated only by the client that talks to it proves nothing.

What it is not

  • Not a simulator of forwarding behaviour. It models the management plane: the data a switch reports and the configuration it accepts. Frames do not traverse it.

  • Not a complete firmware. Pages, OIDs and tags that the library exercises are implemented; a model’s full web UI is not reproduced.

  • Not a security boundary. It accepts a configured community and password and models authentication faithfully enough to test against — including NSDP’s v1 XOR and v2 salted-token schemes — but it is a test double, not a hardened service. Bind it to loopback unless you have a reason not to.

How it is put together

 seed.py  ── seeds ──▶  VirtualSwitchState  ◀── read/written by ── faces/
(captured                (one in-memory                          snmp.py
 device                   device state)                          nsdp.py
 values)                                                         http.py
                                                                 cli.py

netgear_switch.virtual.state.VirtualSwitchState is the single authoritative device state: ports, VLANs, PVIDs, PoE, sensors, MAC table, LLDP neighbours, management configuration, firmware and serial, plus the NSDP-specific fields and the per-model protocol quirks.

Each face serves that one state over a real protocol. Because there is one state behind all of them, a change written over SNMP is visible over HTTP — the same cross-protocol consistency a real switch has, and what makes cross-backend equivalence testable at all.

netgear_switch.virtual.server.VirtualSwitch binds whichever faces the model’s registry entry declares, and hands out the ports it actually bound.

Which models are seeded

gsm7252ps, gsm7228ps, gs110emx, gs305ep, gs105pe, m4300-24x, m4300-16x and gs728tpp all have hand-authored seeds built from real captures. Any other registered model still constructs — every state field has a default — but answers from a blank device rather than a realistic one.

Next