Skip to content

CLI reference (dtvsol)

dtvsol is the command line of the DTVSOL Super Router. You run it on the router itself, as root or with sudo. Most commands are answered by the router daemon dtvsold, the same daemon that serves the HTTP API. The rest (configuration versions, network configuration, licence, NTP, OLT monitor users) run as root on the box, so they keep working even when the API is down.

Terminal window
dtvsol <group> <command> [arguments]
dtvsol help # the full help
dtvsol ? <group> # one group's detailed help (same as: dtvsol help <group>)

The groups with detailed help are clients, iface, networks, net6, routes, nat, protect, firewall, antispoof, olt, service and api.

Tab completion. Press <TAB><TAB> to complete commands, then interfaces, VLANs and MACs. It is installed once by dtvsol init.

In the tables below, Changes marks the commands that change the router, an OLT, or the stored configuration. Commands without the mark only read.

Clients are the older model: one MAC address with a fixed IP. For subscribers provisioned together with their ONT, see Services. API: Clients.

Command Purpose Changes
clients list List all registered clients
clients list-net <network> List the clients in one network (CIDR)
clients search <keyword> Search by MAC, IP, hostname, comment or interface
clients get <mac|ip|hostname> Look up one client
clients add <mac> <ip> [hostname] [comment] [--ipv6 <addr>] Register a client with a fixed IP. The network, interface and gateway are detected from the IP. The hostname is generated from the MAC when you leave it out. --ipv6 also creates a DHCPv6 host entry yes
clients delete <mac> Remove a client from DHCP and the firewall yes
clients plan <mac> <plan|none> Assign a bandwidth plan (none = unlimited) yes
clients suspend <mac> / clients resume <mac> Cut off a client, or restore it (also dtvsol suspend <mac> / dtvsol resume <mac>) yes
clients expires <mac> <YYYY-MM-DD|never> Set the service end date. The client is suspended automatically on that date yes
clients active [online|recent|offline] Client activity from ARP/NDP and the DHCP leases (also dtvsol active)
clients6 [iface] [--routers] IPv6 view: each MAC with the address it holds and its delegated prefix
ips [network] Static IP usage per network: used, free, next free, and devices on the network that are not registered
graph <mac|iface> [hour|day|week|month|year] [outfile.png] Save a traffic graph as a PNG (default period: day)
Terminal window
dtvsol clients add AA:BB:CC:DD:EE:FF 10.110.0.5 client-1 "Client 1 - 50 Mbps"
dtvsol clients add AA:BB:CC:DD:EE:FF 10.110.0.5 client-1 "Client 1" --ipv6 XXXX:XXXX::5
dtvsol clients list-net 10.110.0.0/21
dtvsol clients search 10.110.0
dtvsol clients plan AA:BB:CC:DD:EE:FF plan_50_10
dtvsol clients expires AA:BB:CC:DD:EE:FF 2026-12-31
dtvsol clients suspend AA:BB:CC:DD:EE:FF
dtvsol clients6 vlan100 --routers
dtvsol ips 10.110.0.0/21
dtvsol graph AA:BB:CC:DD:EE:FF week /tmp/client.png

A service is the unit the billing system works with: one customer, one ONT, one speed, one address, and a permanent id. The subscribers on a PON port share that port’s VLAN (v<svlan>.<cvlan>, one /24 and one /64). Each ONT gets a fixed address, which is handed out only to the DHCP request whose Option 82 (inserted by the OLT) names that port and ONT, so no MAC is needed. One command registers the ONT on the OLT and sets up the router side. API: Services.

Command Purpose Changes
service unregistered [--olt n] The technician’s list: unregistered ONTs on every registered OLT (serial, PON, vendor)
service add <sn> --name "..." (--plan p | --down d --up u) [--olt n] [--pon f/s/p] [--user-vlan v] [--ref r] [--contract c] [--expires YYYY-MM-DD|never] [--comment ...] [--iptv] [--no-ipv6] Provide a subscriber in one call: ONT, VLAN, address and speed. Prints the VLAN to set on the ONU. --pon is looked up in autofind when you leave it out. --down/--up create the plan plan_<down>_<up> if it does not exist. --ref is idempotent: the same ref returns the same service yes
service add none --svlan s --pon f/s/p --ont-id n --name ... --plan ... Add a subscriber whose ONT was provisioned by hand yes
service list [--state active|suspended|error] [--olt n] [-q text] [--fast] [--json] List services
service get <id> Show one service. You can also look it up by ref, serial, contract, address or interface
service set <id> [--plan p | --down d --up u] [--name] [--contract] [--expires] [--comment] [--retry] Change a service. A plan change also changes the ONT’s rate limit on the OLT yes
service suspend <id> / service resume <id> Deactivate the ONT on the OLT and block the address on the router, or undo it. End dates do this automatically yes
service migrate <id> Move a service onto its PON port’s VLAN and /24 without touching the ONU. The OLT translates the VLAN that the ONU already sends yes
service del <id> [--keep-ont] Delete the service on the router, and the ONT on the OLT unless --keep-ont yes
service graph <id> [hour|day|week|month|year] [out.png] [--olt|--errors] Traffic graph from the router’s counters. --olt shows the ONT’s traffic as counted by the OLT, --errors shows its fiber errors (BIP, FEC)

Numbering: svlan is this router’s S-VLAN on the OLT (dtvsol olt set <olt> --svlan n) and cvlan is 100 + card*16 + pon. The port’s /24 is svc_ipv4_pool + (cvlan-100)*256 (VLAN 100 gets 100.64.0.0/24), and the ONT’s address is .2 + ONT id. For IPv6, each port gets a /64 from svc_ipv6_pool and 256 delegated /64s from svc_pd_pool. The OLT enforces the speed limit.

Terminal window
dtvsol service unregistered --olt olt-1
dtvsol service add 48575443A1B2C3D4 --name "Customer 1" --plan plan_200_200 --olt olt-1 --pon 0/0/3 --ref 1001
dtvsol service add 48575443A1B2C3D4 --name "Customer 2" --down 100 --up 50 --contract C-2002 --expires 2026-12-31
dtvsol service list --state suspended --olt olt-1
dtvsol service get 1001
dtvsol service set svc_1 --plan plan_300_300
dtvsol service suspend svc_1
dtvsol service del svc_1 --keep-ont
dtvsol service graph svc_1 week --errors

Bandwidth plans are named download and upload rates. A client with no plan is unlimited. API: Plans.

Command Purpose Changes
plans list List the plans, with the number of clients on each
plans add <name> <down_mbps> <up_mbps> [comment] Create a plan yes
plans del <name> Delete a plan yes
Terminal window
dtvsol plans add plan_50_10 50 10 "Home 50"
dtvsol plans del plan_50_10

API: VLANs, IPs and routes.

Command Purpose Changes
iface List all interfaces grouped by type (physical, VLAN, QinQ), with their state, IPs, VLAN IDs and parent
vlan list Show the managed VLANs. Disabled ones are dimmed
vlan add Interactive: pick the parent, then enter the VLAN ID, protocol, IP and label. By default the VLAN serves DHCPv4, DHCPv6 and prefix delegation. It persists across reboots yes
vlan disable <name> [reason] Switch a VLAN off and keep every setting. The link goes down, and its DHCPv4/v6, router advertisements, NAT rules, port forwards and routes stop. The delegation range stays reserved. Allowed even with clients on the VLAN yes
vlan enable <name> Restore a disabled VLAN exactly as it was, with the same prefixes yes
vlan del [name] Delete a VLAN (interactive without a name). Refused while clients are registered on it. Cannot be undone yes
ip add [iface] [ip/cidr] Add an IP address to an interface (interactive without arguments) yes
ip del <iface> <ip/cidr> Remove an IP address. Refused while registered clients use it as their gateway yes
Terminal window
dtvsol vlan disable vlan100 "OLT maintenance"
dtvsol vlan enable vlan100
dtvsol ip add vlan100 10.110.96.1/21
dtvsol ip del vlan100 10.110.96.1/21

API: Networks and DHCP.

Command Purpose Changes
networks Show the detected interfaces, networks and gateways
net list List the interfaces with their DHCP status (green = served, red = not configured)
net add Interactive: add an interface to DHCP. Writes the subnet with its pool, adds the interface to the DHCP listen list, tests the configuration (rolled back on failure) and restarts DHCP yes
net del Interactive: remove an interface from DHCP. Refused while clients are registered on it yes
net6 list The interfaces with their DHCPv6 status
net6 add / net6 del Interactive: add an interface to DHCPv6, or remove it yes
net6 pool <iface> [start end] Fill in the DHCPv6 range (and DNS) for the interface’s IPv6 subnet yes
net6 lease <valid> [preferred] Set the DHCPv6 address and prefix lifetimes, in seconds yes
Terminal window
dtvsol net6 pool vlan100
dtvsol net6 lease 86400 43200

The resolvers that DHCP hands to subscribers. API: Networks and DHCP.

Command Purpose Changes
dns Show the resolvers each VLAN serves, and which VLANs serve none
dns set [iface] v4=<a,b> [v6=<c,d>] [domain=<name>] [apply=all|missing] Set the global resolvers, or one VLAN’s override when you give an interface. With apply=all, existing VLANs follow the new default too yes
dns del <iface> Drop a VLAN’s override so it inherits the global resolvers yes
dns del global <v4|v6|domain|all> Clear a global setting (serve nothing again) yes
Terminal window
dtvsol dns set v4=XXX.XXX.XXX.53,XXX.XXX.XXX.53 v6=XXXX:XXXX::53 domain=example.net apply=all
dtvsol dns set vlan100 v4=10.0.0.53
dtvsol dns del vlan100

API: VLANs, IPs and routes and Networks and DHCP (prefix delegation).

Command Purpose Changes
route list List the managed routes and the live routes (IPv4 and IPv6)
route add <prefix|default> [via <gw>] [dev <iface>] [comment] Add a persistent route yes
route del <prefix> [via <gw>] [dev <iface>] Remove a route yes
pd list DHCPv6 prefix delegation: pools, capacity, pinned prefixes, routes
pd add <iface> [size] Delegate LAN prefixes to every CPE on a VLAN yes
pd resize <iface> <size> Change how many subscribers the VLAN’s slice holds yes
pd del <iface> Stop delegating on a VLAN yes
pd assign <mac> [prefix] Pin a subscriber’s prefix. One is picked automatically when you leave it out yes
pd unassign <mac> Release a pinned prefix yes
pd sync [--dry-run] Reconcile the delegated-prefix routes now yes (not with --dry-run)
nat list List the dynamic NAT pools and the live NAT rules
nat add <iface> <pool_start> [pool_end] [exempt <cidr,cidr>] [comment] Add a NAT pool to an interface yes
nat del <iface> Remove the NAT pool from an interface yes
Terminal window
dtvsol route add default via XXX.XXX.XXX.1 dev vlan100
dtvsol route add 10.20.0.0/16 via 10.0.0.2 "to olt-1 management"
dtvsol pd add vlan100 256
dtvsol pd assign AA:BB:CC:DD:EE:FF XXXX:XXXX:b:5::/64
dtvsol pd sync --dry-run
dtvsol nat add vlan100 XXX.XXX.XXX.10 XXX.XXX.XXX.20 exempt 10.0.0.0/30

The router’s own network (ports, bonds, their addresses, default route and DNS) is stored in the configuration database and written to netplan. netcfg needs the daemon binary. An apply is undone unless you confirm it within 120 seconds, and an apply that would cut your own SSH session is refused. API: Network configuration.

Command Purpose Changes
netcfg show Show the stored network configuration, plus VLANs and static routes
netcfg import [--save [--force]] Read the running network (kernel and netplan) and show the change key by key. --save stores it, but refuses anything that would lose a netplan setting unless you add --force yes (with --save)
netcfg render [--proposed] Print the netplan file it would write (--proposed: the file for what import would store)
netcfg diff Compare the stored configuration, the live kernel and /etc/netplan, and say whether an apply is allowed
netcfg apply [--try] [--force] Write the netplan file and apply it. Confirm within 120 s or it is put back. --try only checks it with netplan generate yes
netcfg confirm Keep the applied network yes
netcfg rollback Put the previous network back now yes
Terminal window
dtvsol netcfg import
dtvsol netcfg diff
dtvsol netcfg apply --try
dtvsol netcfg apply
dtvsol netcfg confirm

Deterministic CGNAT: each private address maps to a fixed public address and port block. API: CGNAT and anti-spoofing.

Command Purpose Changes
cgnat / cgnat status Status: interface, pool, port range, block size, capacity, assigned and free
cgnat set [enable|disable] [iface <if>] [pool <range>] [block <n>] [exempt <cidrs>] Configure CGNAT yes
cgnat lookup <public_ip> <port> Find which subscriber used a public IP and port
Terminal window
dtvsol cgnat set enable iface vlan200 pool XXX.XXX.XXX.0/28 block 2048 exempt 10.0.0.0/30
dtvsol cgnat lookup XXX.XXX.XXX.5 40123

Binds IP, MAC and VLAN: a packet from a VLAN is forwarded only when its source MAC and IP are a known pair, and the same applies to ARP. Everything else is dropped and logged with the sending MAC. For IPv6, a client’s reserved address, its DHCPv6 address and its delegated prefix are bound to its MAC. Link-local traffic always passes, and router advertisements or redirects from subscribers are dropped. API: CGNAT and anti-spoofing.

Command Purpose Changes
antispoof Status: the mode per VLAN, the bindings, and drops in the last hour
antispoof on / antispoof off Enforce on every VLAN that DHCP serves, or remove every rule (the settings are kept) yes
antispoof set [mode strict|dynamic] [log on|off] [exempt <cidr,...>|none] strict: only registered clients get service (unregistered devices still get DHCP, so they show in dtvsol ips). dynamic: also allows unregistered devices on the address DHCP leased them. log: a rate-limited kernel log of drops. exempt: addresses allowed from any MAC (for example an OLT’s relay address) yes
antispoof iface <vlan> <strict|dynamic|off|default> Set one VLAN’s mode. off excludes the VLAN. An override on a VLAN that DHCP does not serve adds it yes
antispoof log [since] [limit] Dropped packets grouped by device. since: 30m, 2h, 1d (default 1 hour)
antispoof sync Rebuild the rules now. Normally not needed, because every client or VLAN change and every lease change does it yes
Terminal window
dtvsol antispoof set mode strict exempt 10.0.0.0/30 && dtvsol antispoof on
dtvsol antispoof iface vlan100 dynamic
dtvsol antispoof log 2h 100

API: Protection.

Command Purpose Changes
protect list List the networks allowed to reach the API port (and the OLT monitor)
protect add <network> [comment] Allow a network yes
protect del <network> Remove a network yes
firewall list Show the MAC filtering rules
firewall vlan <svlan> Show the MAC rules of one VLAN interface
portforward list List the port forwards (also pf)
portforward add <tcp|udp> <pub_port> <client_ip> <client_port> [pub_ip] [comment] Forward a public port to a client yes
portforward del <tcp|udp> <pub_port> [pub_ip] Remove a port forward yes
fail2ban / fail2ban status Bans for failed API keys and SSH logins, per jail
fail2ban unban <ip> Lift a ban yes
option82 Show the DHCP relay circuit and remote IDs (OLT and port) seen in the current leases
option82 enable|disable Turn capture of Option 82 on or off yes
snmp / snmp status Status of the router’s SNMP agent
snmp set [community <c>] [location <l>] [contact <ct>] Configure the SNMP agent yes

After dtvsol init, protection is always on and only localhost may reach the API. Add your billing, middleware and office networks.

Terminal window
dtvsol protect add 10.10.10.0/24 "Office network"
dtvsol protect add XXX.XXX.XXX.7 "Billing server"
dtvsol portforward add tcp 8443 10.110.0.5 443 XXX.XXX.XXX.10 "Customer camera"
dtvsol portforward del tcp 8443 XXX.XXX.XXX.10
dtvsol fail2ban unban XXX.XXX.XXX.20
dtvsol snmp set location "POP 1" contact noc@example.net

A listener on port 8728 that speaks the MikroTik RouterOS API, so billing systems written for MikroTik can create, change, suspend and delete DHCP/IPoE clients and set their speed. PPPoE is refused. The billing server’s network must be on the allow-list (dtvsol protect add). API: MikroTik-compatible API.

Command Purpose Changes
mkapi / mkapi status Show the service state, port, user, whether a password is set, the reported identity and the number of mapped clients
mkapi set user <u> password <p> [port <n>] [identity <name>] [model <m>] [version <v>] Change the settings and restart the listener yes
Terminal window
dtvsol mkapi set user billing password 'CHOOSE-A-PASSWORD' identity router-1

Control of Huawei MA5600T-family OLTs (MA5608T, MA5680T, MA5683T). Pick the OLT with --olt <name>, which defaults to the only registered OLT, or make a one-off call with --host <ip> --user <u> --pass <p> (plus optional --ssh, --port <n> and --raw). For one-off calls you can also set the environment variables OLT_HOST, OLT_USER and OLT_PASS, or let the tool ask (the password is not echoed). Nothing about a one-off OLT is kept. API: OLT.

Registry and maintenance

Command Purpose Changes
olt list List the registered OLTs (never the password)
olt add <name> <host> [user] [--pass p] [--ssh] [--svlan n] [--iptv n] [--operator|--owner] Register an OLT. --svlan is this router’s S-VLAN on it, and --iptv its IPTV VLAN yes
olt set <name> ... Change a registered OLT (same options) yes
olt del <name> Remove an OLT from the registry yes
olt sync [--dry-run] [--olt n] Push this router’s plans to every registered OLT (profiles and rate tables) yes (not with --dry-run)
olt init [--olt n] [--svlan n] [--iptv n] [--operator] [--ntp ip] [--parent iface] [--apply] Baseline an OLT for this router. Dry-run unless --apply yes (with --apply)
olt backup Back up the OLT’s configuration into git now
olt backups The backup history, and whether the OLT’s changes are saved to flash
olt diff [c] [c2] What changed between backups
olt doctor Same as dtvsol doctor, which checks the OLT against the router’s records
olt vault status|bind|rebind ... Status of the store for the OLTs’ secrets, which are bound to this machine. rebind recovers them after the router hardware is replaced yes (bind, rebind)

Changes are saved to flash and backed up automatically by a maintenance timer.

Read

Command Purpose
olt info Product, version, uptime, boards, clock, NTP
olt autofind Unregistered ONTs (F/S/P, serial, vendor, when seen)
olt onus [f/s/p] Registered ONTs: id, serial, run, config and match state
olt vlans The VLAN table and the VLANs tagged on every uplink port
olt sp Service-ports (subscriber flows)
olt profiles DBA, line and service profiles
olt config [out.txt] The current configuration (a backup)
olt run "display ..." Any display command, with raw output

Write (nothing is saved to flash until olt save)

Command Purpose
olt vlan add <id> [uplinks 0/3/0,0/3/1] [desc "text"] [type smart|standard] Create a VLAN on the OLT
olt vlan del <id> [uplinks ...] Delete a VLAN
olt uplink add|del <vlan> <f/s/p> Tag a VLAN on an uplink port, or untag it
olt profile add <vlan> [dba <id>] [eth <ports>] Create a line and service profile dtvsol-v<vlan>
olt profile del <id> Delete a profile
olt ont add <f/s/p> <sn> <vlan> [desc] [--plan p] [--iptv-on] Register an ONT by serial, with a native VLAN on eth 1 and a service-port on <vlan>. --plan applies the plan’s profiles and rate tables, and --iptv-on adds IPTV on eth 2 with a second service-port
olt ont del <f/s/p> <id> [--force] Delete an ONT and its service-ports
olt ont reboot <f/s/p> <id> [--force] Reboot an ONT. Both del and reboot refuse an ONT whose service-ports are on another operator’s S-VLAN. --force works only for an ONT that has no service-ports
olt ont desc <f/s/p> <id> "text" Set an ONT’s description
olt ont optical <f/s/p> [id] Optical readings: rx/tx power, temperature, voltage (read only)
olt ntp <server> Point the OLT at an NTP server
olt sysname <name> Set the OLT’s system name
olt save Save the configuration to flash
olt exec "<cmd>" ["<cmd>" ...] Run configuration commands in order, in config mode. Stops at the first one the OLT refuses
Terminal window
# typical first subscriber on a bare OLT
dtvsol olt vlan add 100 uplinks 0/3/0
dtvsol olt profile add 100 dba 5
dtvsol olt autofind
dtvsol olt ont add 0/0/0 48575443A1B2C3D4 100 "Customer 1"
dtvsol olt save
dtvsol olt add olt-1 10.20.0.2 admin --ssh --svlan 400 --iptv 200
dtvsol olt sync --dry-run
dtvsol olt ont optical 0/0/3 --olt olt-1
dtvsol olt diff
Command Purpose Changes
ntp / ntp status Show the time service for the OLTs this router owns
ntp setup Serve time here (chrony) and point each owned OLT at the router yes

The OLT monitor is the router’s web page for the NOC. It is reachable only from the API allow-list (dtvsol protect list) and uses a self-signed certificate.

Command Purpose Changes
monitor / monitor status Where the monitor is (its URL), whether it runs, and how many users it has
monitor users List the users who may sign in
monitor user add <name> [admin|viewer] Add a user. The password is asked twice. A new user is a viewer unless you say admin yes
monitor user passwd <name> Change a user’s password yes
monitor user del <name> Remove a user yes
monitor user role <name> admin|viewer Change a user’s role. An admin may change settings from the page, and a viewer can only see them yes
monitor wall add <name> Add a display for the support room (the 24/7 wall). Prints the link to open on that screen yes
monitor wall del <name> Remove a wall display yes
monitor walls List the wall displays
Terminal window
dtvsol monitor user add alice admin
dtvsol monitor user add noc1
dtvsol monitor user role noc1 admin
dtvsol monitor wall add noc-room
dtvsol monitor walls

API: Alarms and health and System.

Command Purpose
doctor [--no-olt] A full audit of the configuration and of what survives a reboot. When an OLT is registered, it is checked against this router’s records (S-VLAN, uplinks, Option 82, every service’s ONT and service-port). --no-olt skips the OLT, which is faster (also dtvsol check)
alerts Current conditions worth attention
alarms The alarm register: what is wrong now and since when (checked every minute)
alarms all The same, plus the alarms cleared in the last 7 days
alarms history [n] The last n raises and clears (default 50)

The router’s configuration is kept in versions, like a switch’s flash, in the configuration database. These commands run as root on the box, so a restore works even when the API does not. API: System.

Command Purpose Changes
config / config status Status of the store and the running configuration
config save ["comment"] Save the running configuration as a new version yes
config versions [n] List the saved versions
config diff <a> [b|running] Compare two versions, or a version with the running configuration
config show <id> [path] Show a version, or one file in it
config restore <id> --yes Restore a version yes
config docs Where each configuration document lives (file or database)
config migrate <name>|all Move documents into the database yes
config export <name> Print a document
config edit <name> Edit a document safely: the JSON is checked and a version is kept first yes
Terminal window
dtvsol config save "before adding vlan100"
dtvsol config versions 10
dtvsol config diff 41 running
dtvsol config restore 41 --yes
dtvsol config edit plans

API: System.

Command Purpose Changes
backup [outfile.tar.gz] Download a one-off backup of the router’s configuration and data
backup now Run the daily backup now (a local copy plus an encrypted off-site copy)
backup list List the local backups
backup status Last local and off-site backup, errors, and the next scheduled run
restore <file.tar.gz> Restore from a backup archive yes
Terminal window
dtvsol backup /root/router-1-backup.tar.gz
dtvsol backup status
Command Purpose Changes
licence / licence status Show the router’s platform licence
licence refresh [-v] Fetch the licence now. A daily timer also does this yes
licence enrol <router-id> <token|-> Enrol the router with the ID and token from the management platform. - reads the token from standard input yes
Terminal window
echo "$TOKEN" | dtvsol licence enrol router-1 -

(The group was called service before v2.8. That name now means the subscriber service.)

Command Purpose Changes
daemon status API and DHCP status, and the client count per network
daemon reload Force a DHCP reload yes
daemon start / stop / restart Control the API service (systemd) yes
daemon log The last 50 lines of the API log
daemon logf Follow the API log live
Command Purpose Changes
init First-time setup: PATH, systemd units, protection, tab completion yes
version The router software version, commit and service states