Skip to content

Writing a new driver

Adding a vendor to rcfg-sim is intentionally small: one runtime file for the driver and one template plus a registry entry for the generator. Nothing in the hot path needs to know your vendor exists.

Create internal/sshsrv/driver_<vendor>.go and implement the four-method Driver interface. Register it from init():

package sshsrv
func init() { registerDriver(myVendor{}) }
type myVendor struct{}
func (myVendor) Name() string { return "myvendor_os" }
func (myVendor) RequiresSSHAuth() bool { return true }
func (myVendor) Commands() []string { return []string{ /* Cmd* label strings */ } }
func (myVendor) Serve(ctx *sessionCtx) { /* the interactive loop */ }

2. Route responses through the shared helpers

Section titled “2. Route responses through the shared helpers”

In Serve, never sleep or write to the channel directly for command responses. Use the session-context machinery so timing, faults, and metrics stay uniform:

  • Call ctx.applyResponseDelay() between resolving a command and dispatching it.
  • Build a Response and pass it to ctx.emit(cmd, cmdStart, resp); check its return value to know when to close the session.
  • Stream large payloads via Response.ConfigOutput (the mmap slice) to preserve the zero-copy hot path. Use Response.Trailer for any closing bytes (e.g. a terminator).

This is what gives your driver fault injection (disconnect_mid, malformed, slow_response) and the command-duration metric for free.

Add any new Cmd* constants and their String() cases, and return them from Commands(). The server unions every driver’s Commands() and pre-registers them, keeping the rcfgsim_command_duration_seconds cardinality bounded. Never use raw user input as a label value.

To produce devices for your driver, add one registry entry in internal/configs/generator.go (vendor string, the template id matching your driver’s Name(), the template file, and a data builder) and a templates/<name>.tmpl. The model name becomes a valid --distribution key.

  • Add unit tests for command resolution and response shape.
  • Add an integration test (build tag integration) that connects over real SSH.
  • If your output is meant to be byte-stable for a seed, add a determinism test like TestCienaDeterministic.

Run the gate before opening a PR:

Terminal window
make vet fmt test
make integration

See Contributing for the full PR checklist, and the shipped Ciena TL1 driver as a complete, self-contained worked example.