The driver framework
A driver is a vendor personality. It owns the full interactive loop for one device:
reading input, parsing commands, and writing responses. rcfg-sim ships two —
cisco_ios and ciena_tl1 — and adding more
is deliberately a one-file job.
The Driver interface
Section titled “The Driver interface”Every driver implements four methods:
type Driver interface { Name() string // manifest `template` id, e.g. "cisco_ios" Commands() []string // metric label values this driver can emit RequiresSSHAuth() bool // does it authenticate at the SSH transport? Serve(ctx *sessionCtx) // the full interactive loop}Name()is the id used in the manifesttemplatecolumn and the registry key.Commands()is the closed set of command labels the driver may emit onrcfgsim_command_duration_seconds. The server unions these across all drivers and pre-registers them, so the metric’s cardinality is assembled from drivers rather than hardcoded — and stays bounded.RequiresSSHAuth()is consulted only under--ssh-auth=driver.Serve()runs the session.
How a driver is selected
Section titled “How a driver is selected”At session start the server looks up the device’s manifest template value in the driver
registry (driverFor). Unknown or empty values fall back to cisco_ios, so older manifests
keep working unchanged.
new SSH session │ ▼manifest row ── template column ──▶ driver registry │ ┌───────────────────┼───────────────────┐ cisco_ios ciena_tl1 unknown / empty │ │ │ ▼ ▼ ▼ ciscoIOS.Serve cienaTL1.Serve ciscoIOS.Serve (fallback)Shared machinery
Section titled “Shared machinery”Drivers don’t reimplement timing, faults, or metrics. They route every response through two shared helpers on the session context:
applyResponseDelay()— the single place a response sleep happens (base jitter plus theslow_responsefault multiplier). See timing.emit()— writes the response, appliesdisconnect_mid/malformedfaults to streamed config bytes, preserves the zero-copy path for the un-faulted case, and records the command-duration metric.
This is what guarantees that fault and metric behaviour is identical across vendors — a driver author gets all of it for free.
Registration
Section titled “Registration”Each driver registers itself from an init() in its own file
(driver_<vendor>.go), so nothing else in the hot path needs to know it exists:
func init() { registerDriver(ciscoIOS{}) }The shipped drivers
Section titled “The shipped drivers”- Cisco IOS (
cisco_ios) —showcommands, enable mode, prefix matching - Ciena 6500 TL1 (
ciena_tl1) —ACT-USERlogin,RTRV-*verbs
Want to add your own? See Writing a new driver.