Skip to content

Netvyn BNG — CLI User Guide

The operator command reference for the Netvyn carrier-grade broadband network gateway.

Version CLI

The Netvyn CLI is a Huawei-style two-view command line, launched with the bng-cli process. You start in an operational user view (<Netvyn-BNG>) for show, ping, and traceroute, and enter system-view ([Netvyn-BNG]) to configure the box. Configuration is staged in a candidate and applied atomically with commit, with rollback, save, and load completing a Cisco/Juniper-style transaction model. TAB completion and keyword abbreviation are available at every prompt.


Table of Contents

  1. Configuration Modes
  2. Command Syntax
  3. Context Help
  4. Interface Commands
  5. PPPoE Commands
  6. IPoE Commands
  7. Routing Commands
  8. Firewall Commands
  9. NAT / CGNAT Commands
  10. QoS Commands
  11. RADIUS Commands
  12. Monitoring Commands
  13. Debug Commands
  14. Show Commands Reference
  15. Configuration Examples
  16. Best Practices
  17. show interface detail

1. Configuration Modes

1.1 User view vs. system-view

The Netvyn CLI has two operating contexts, and the prompt always tells you where you are.

Prompt Context What you can do
<Netvyn-BNG> User view (operational) show / display, ping, traceroute, and the transaction verbs
[Netvyn-BNG] System-view (configuration) Everything above, plus config edits

The view is where you are; your role governs what you may run (see §12.5). A read operator can enter system-view but is still refused config edits; system … CPU/topology commands need the full role.

Enter configuration mode with system-view and leave it with return (or quit from the config root):

<Netvyn-BNG> system-view
[Netvyn-BNG]
[Netvyn-BNG] return
<Netvyn-BNG>

Global verbs — show, display, the transaction verbs (commit / rollback / save / load), and the diagnostics ping / traceroute — resolve from any context, including the user view. You do not need system-view to run a ping or a show.

1.2 Configuration views

Within system-view, related configuration is grouped into views. Entering a view changes the prompt and lets you drop the leading keyword:

[Netvyn-BNG] nat                 → [Netvyn-BNG-nat]
[Netvyn-BNG-nat] enable          (interpreted as: nat enable)
[Netvyn-BNG-nat] quit            → [Netvyn-BNG]

There are two kinds of view:

  • Keyword viewssystem, ppp, dhcp, nat, firewall, radius, routing, arp.
  • Object (name-keyed) viewsinterface <name>, pool <name>. The name may be new (which creates the object) or existing (which edits it); the prompt carries the name, e.g. [Netvyn-BNG-pool-default].

quit steps up one level. Every command can also be typed in full from the config root without entering its view — nat enable works directly at [Netvyn-BNG].

1.3 The candidate / running / startup model

Configuration edits stage into a candidate. Nothing applies to the live system until you commit. This mirrors the Cisco/Juniper transaction model and is the same contract used by the GUI and monitoring API.

There are three configuration stores:

  • Candidate — your staged, not-yet-applied edits.
  • Running — the configuration currently applied and forwarding traffic.
  • Startup — the saved configuration that survives a reboot.

1.4 Transaction verbs

Command Effect Timing
commit Validate the candidate and apply it to running Immediate
commit confirmed [<minutes>] Apply now, auto-revert in <minutes> (default 10) unless confirmed Immediate
confirm Keep a pending commit confirmed (cancel the auto-revert) Immediate
rollback Discard candidate edits Immediate
save Write running → startup (survives reboot) Immediate
load Read startup into the candidate Immediate

commit confirmed is the safety net for risky changes: if a change cuts off your own management access, doing nothing restores the previous running config automatically after the timer expires. If the change is good, run confirm to make it permanent.

1.5 Apply timing

Most configuration takes effect at commit. Many high-value knobs apply live on commit without dropping subscriber sessions — for example nat policy, firewall enable / urpf, pool add/remove, ip / ipv6 address add/remove, ppp interface and dhcp interface add/remove, qos subscriber-profile / qos assign, arp tuning, and ip route / ipv6 route (including the default-gateway row). A smaller set of changes — firewall mangle/filter rules, radius settings, ipv6 pool reshapes — take effect on restart (nat pool edits apply live for NEW sessions). Each section below notes its own apply timing, and Section 16 summarizes the rules.

1.6 Pending changes on exit

The CLI guards against walking away from unpersisted configuration:

  • Leaving system-view (return / exit / end, or quit at the config root) with uncommitted edits prompts commit them before exiting? [Y/N/C]Y commits, N discards (rollback), C stays in the view.
  • Leaving the CLI (quit from the user view) re-checks both halves: any uncommitted edits prompt to commit, then a committed-but-unsaved running config prompts Save to startup before exiting? [Y/N] so the change survives a reboot.

One-shot invocations (bng-cli <command>) never prompt.


2. Command Syntax

2.1 Notation conventions

This guide uses the following conventions in command descriptions:

Notation Meaning
<value> A required parameter you supply (e.g. <name>, <ip>)
[value] An optional parameter or keyword
a\|b\|c A choice — pick exactly one of the listed keywords
[<name>...] The parameter may be repeated (a list)
plain text A literal keyword you type verbatim

For example:

ping <dst> [source <ip>] [count <n>] [df] [fast]

<dst> is required; source, count, df, and fast are all optional.

2.2 Keyword abbreviation

Any unambiguous keyword prefix is accepted. Typing time udp 30 in the NAT view is expanded to timeout udp 30. Ambiguous prefixes are rejected with the list of candidates — at the config root, co is ambiguous between commit and confirm, so use com or con.

2.3 TAB completion

Press TAB to complete a unique keyword prefix. If the prefix is not unique, nothing is completed and you can use ? (Section 3) to see the candidates.


3. Context Help

3.1 The ? key

Press ? at any point on the command line to list what is valid at the cursor — matching keywords, plus a <hint> describing any expected variable. ? is context-sensitive: the choices reflect your current view.

Listings are alphabetical at every level — keywords A→Z with <variable> hints last, and live values (interface, pool, and account names) sorted the same way. TAB candidate lists follow the same order.

3.2 TAB

TAB completes a unique prefix (Section 2.3). Used together with ?, it lets you build a command interactively without memorizing the full grammar.

3.3 Per-view help

Because the prompt reflects your view, ? inside a view shows only the commands valid there. Enter the nat view and ? lists NAT knobs; enter qos and it lists QoS objects. quit returns to the parent context and its help set.

3.4 Reviewing configuration

Three commands let you inspect configuration state at any time:

show pending                 uncommitted candidate changes (drives the * prompt marker)
show running                 the applied configuration
show candidate               running with the candidate overlay

display current-configuration is an alias that normalizes to show running.

show running / show candidate print a tree: modules and keys alphabetical, one nesting level per path component, ordered lists (filter:, policy:, server: …) shown as numbered rows in their configured order (rule position is semantic, so rows are never re-sorted). In the candidate view, staged lines carry a trailing *. Details worth knowing:

pool
  default = 100.64.0.2 100.64.0.254 100.64.0.1     # <name> = <range>; a successor
  temp = 10.10.10.2 10.10.12.250 10.10.10.1  next Disabled   # rides inline; 'next
  dns = 103.102.59.2 8.8.4.4                       # = none' is not shown

service                       # both on-box services group here (matches the CLI)
  api                         # live-managed (api.conf, no commit) — still shown
    enable = on
    listen = 0.0.0.0:8090
    allow:
      (empty)
  telnet                      # staged config (commit applies, save persists)
    allow:
      [1] 192.10.10.0/30
    listen = 0.0.0.0:2008

Unset scalar values print as (not set), empty lists as (empty).


4. Interface Commands

VLAN / QinQ sub-interfaces and trunks (bonds) are created under the physical port they belong to — the port you run add on is the parent (for a VLAN) or the member (for a trunk). This mirrors MikroTik/Huawei/Cisco: you add sub-objects to an interface.

# VLAN / QinQ sub-interfaces (parent = the <port> you run 'add' on)
interface <port> add vlan <name> <svlan>           single-tag 802.1Q sub-interface
interface <port> add vlan <name> <svlan> <cvlan>   QinQ 802.1ad sub-interface
interface <port> del vlan <name>                   delete a VLAN/QinQ sub-interface

# Trunks / 802.3ad bonding (see §4.2)
interface add trunk <name> [mode 8023ad|active-backup|balance-xor]   create a trunk
interface <port> add trunk <name>                  attach this port as a member
interface <port> del trunk <name>                  detach this port
interface del trunk <name>                         destroy the trunk

# Port attributes
interface <port> description <text> | mtu <68..9600>
interface <port> shutdown | no shutdown            admin down / up (live)
interface identify <name> [duration <s>]           blink the port LED to locate it
                                                   (omit duration = blink until 'identify stop')
interface identify stop <name>                     stop an active blink

VLAN and trunk edits stage into the candidatecommit then save (VLAN applies live on commit; a trunk is built on the next restart, see §4.2).

4.1 Local IP addressing

Local IP addresses are a separate top-level command set. An interface may carry multiple addresses — one primary plus secondaries:

ip address add <if> <ip/prefix>              add a local address (e.g. 103.102.59.6/30)
ip address add <if> <ip/prefix> secondary    add a secondary address
ip address remove <if> <ip/prefix>           remove an address
show ip address [<if>]                        list local addresses (role: primary/secondary)
show ipv6 address [<if>]                       list local IPv6 addresses

The first non-secondary address on an interface is its primary — the source for self-originated traffic and the box's WAN ARP/ICMP identity. Removing the primary promotes the next remaining address on that interface. ip address add / remove stage into the candidate and apply live on commit (no restart), and save persists them. These are L3 host addresses, not routed subnets.

The show interface family:

show interface                physical DPDK ports only (MAC/admin/oper/speed/type)
show interfaces               EVERYTHING in ONE table — one row per interface:
                              Name Type(ether|vlan|trunk) PCI Parent VLAN MAC Port State Speed Desc
show interface <name>         full detail page for one port
show interface stats          live per-port NIC counters (link/mtu/rx/tx/err/drop)
show vlan                     VLAN/QinQ sub-interfaces only (also 'show interface vlan')
show vlan stats               per-VLAN rx/tx packets + bytes (its OWN traffic, not the parent port's)
show interface bonding        802.3ad/LACP bonds + live member state (§4.2)

show interface vlan stats reports each sub-interface's dedicated counters — the fast path attributes a subscriber's packets to the VLAN it arrived on, so this is real per-VLAN traffic rather than a share of the parent port. link / speed / mtu are the parent physical port's, since a VLAN shares the wire.

Upstream worker spread (show interface <name>). The per-port detail page reports three RSS rows that explain how upstream traffic is distributed across workers:

Row Meaning
RSS Supported Hash types the NIC advertises (a bitmask of RTE_ETH_RSS_*)
RSS Active Hash types actually programmed on this port
PPPoE RSS Whether the inner-IP-over-PPPoE rte_flow rule is installed

This matters because plain RSS cannot see inside PPPoE (ethertype 0x8864) — without inner-IP steering every upstream PPPoE packet lands on one queue, and therefore one worker. rule installed is not a promise of spreading: the Intel 82599 / X520 (ixgbe) accepts the rule but does not steer on it (the silicon can't parse past PPPoE), so upstream stays on worker 0. Confirm the real spread with show health under load. When the NIC can't spread PPPoE in hardware, the software dispatcher (§4.3) does it.

Aggregate two or more physical ports into one logical link. Standards-based 802.3ad (LACP) interoperates with any conformant switch — Huawei Eth-Trunk, Cisco port-channel, Juniper LAG, etc. — plus static modes for switches without LACP.

A trunk is built up one port at a time, under the interface command: create the trunk, then attach each physical port to it by name.

interface add trunk <name> [mode 8023ad|active-backup|balance-xor]   create the trunk
interface <port> add trunk <name>                                    attach a member
interface <port> del trunk <name>                                    detach a member
interface del trunk <name>                                           destroy the trunk
show interface bonding                                               show bonds + live LACP state

Members are interface names (e.g. ether1) — the daemon resolves each to the stable PCI address stored in bond.conf. Modes:

Mode Use
8023ad 802.3ad LACP (default) — needs LACP on the switch; active-active load share
active-backup one active member, others standby — no switch config needed
balance-xor static L3+L4-hash load share — no LACP

Trunk edits follow the normal candidate/commit/save model: they stage into the candidate (review with show pending), commit records the change, and save writes bond.conf. The one difference from most config is the apply timing: a bond must be built before the ports are queued, so commit does not build it live — the bond is created on the next restart (the same apply-on-restart contract as the CPU plan). Once built, the bond appears as a single port everywhere (show interfaces, RSS, workers, access/WAN role). Example:

[Netvyn-BNG] interface add trunk bond0 mode 8023ad
staged: trunk bond0 mode 8023ad created (no members yet) — attach ports with 'interface <port> add trunk bond0', then 'commit' + 'save' and RESTART bng
[Netvyn-BNG] interface ether1 add trunk bond0
staged: add ether1 (0000:03:00.0) to trunk bond0  ('commit' + 'save', then RESTART bng to (re)build the bond)
[Netvyn-BNG] interface ether2 add trunk bond0
staged: add ether2 (0000:03:00.1) to trunk bond0  ('commit' + 'save', then RESTART bng to (re)build the bond)
[Netvyn-BNG] commit
[Netvyn-BNG] save
[Netvyn-BNG] show interface bonding
bond bond0      port 3  mode 802.3ad (LACP)  policy l34
  members 2, active 2
    member 0000:03:00.0    port 1  link up 10000Mbps  lacp collecting/distributing
    member 0000:03:00.1    port 2  link up 10000Mbps  lacp collecting/distributing

Optional bond.conf tuning (edit the file): lacp-rate slow|fast (partner timeout, slow = 30 s, the interop default), xmit-policy l2|l23|l34 (TX hash, default l34).

4.3 Software PPPoE RSS (dispatch)

On a NIC that can't RSS inside PPPoE (the X520 — see the PPPoE RSS row above), all upstream PPPoE lands on worker 0. The software dispatcher makes worker 0 hash each upstream PPPoE frame by subscriber IP and fan it out to the other workers — a software stand-in for hardware PPPoE RSS. Opt-in, OFF by default (baseline is byte-identical).

system dispatch enable|disable    turn the software fan-out on/off
dispatch                   show the live state
show health                per-worker busy-cycle (confirm the spread)

Staged like the power toggle: commit applies live, save persists to system.conf. Worker 0 still parses every upstream packet (a single-core cost), so it evens the load but does not scale past one dispatcher core.

Hardware PPPoE RSS by NIC

show interface <name> reports a PPPoE RSS row. What it can say, and why:

NIC Result Why
Intel X520 (ixgbe) not installed (PMD rejected) The parser has no concept of PPPoE. Nothing to configure.
Intel X710 / XL710 (i40e) not installed (PMD rejected) See below — not currently reachable.
Intel E810 (ice) rule installed Supports the inner-IP RSS rule directly.

On the 700 series this is a dead end today, and the reason is worth recording so it is not re-investigated. The daemon installs an rte_flow rule matching ETH / [VLAN] / PPPOES / IP with an RSS action on the inner IP. On i40e that is refused at rte_flow_validate with Pattern not supported — the flow parser does not accept a PPPOES item in an RSS rule, even with Intel's PPPoE DDP profile loaded. (An earlier form of the rule that also carried a queue list was refused first with RSS Queues not supported when pattern specified; removing the queue list moved the error on but did not fix it.) The profile itself loads correctly on firmware new enough to take it — it is the rule mechanism, not the profile, that i40e rejects.

The only route on this hardware is Intel's PCTYPE mapping API (rte_pmd_i40e_flow_type_mapping_update plus an rss_hf change, seeded from the profile's own packet types), which is a different mechanism and is not implemented. Until it is, system dispatch enable is the answer on 700-series ports.

A ddp-profile <path> key exists in system.conf (file only — there is no CLI command) that loads an Intel DDP profile at port init. It is unset by default and, given the above, currently buys nothing on its own. It applies on restart, only touches net_i40e ports, and is never fatal: a missing, unreadable or rejected profile leaves PPPoE RSS off and logs the reason.

Whatever the outcome, the reason appears once per port in the diagnostic log:

show log
port 1: PPPoE RSS not installed -- validate rejected (type=13): Pattern not supported


5. PPPoE Commands

PPPoE / LCP configuration lives in the ppp view.

ppp interface add|remove <name> [<name>...]   PPPoE access interface(s)
ppp mru <bytes>                               max receive unit (PPPoE max 1492)
ppp auth-protocol pap,chap,mschap,mschap2     allowed auth method set (comma list; default pap)
ppp secret add <user> <pass> [<local-ip> [<remote-ip>]]   local credential (checked before RADIUS)
ppp secret remove <user>                      remove a local credential
ppp aaa on|off                                local-store miss policy: on = RADIUS (default), off = strict reject
ppp lcp-echo interval <secs> failure <count>  dead-peer keepalive (interval 0 = off)
ppp setup-timeout <secs>                      half-open reap timeout (default 60)
ppp session-timeout <secs>                    hard session lifetime (0 = unlimited)
ppp pool <name>                               IPv4 framed-address pool (pool.conf) — RADIUS-less fallback
ppp ipv6 enable|disable                       negotiate IPv6CP (default enable; disable = v4-only)
ppp ipv6 pool <name>                          NA /64 framed-prefix pool — RADIUS-less fallback
ppp ipv6 pd-pool <name>                       PD delegated-prefix pool — RADIUS-less fallback
ppp undo <mru|auth-protocol|aaa|lcp-echo|setup-timeout|session-timeout|pool|ipv6|ipv6-pool|ipv6-pd-pool>

IPv4 pool. ppp pool <name> selects which pool.conf pool a PPPoE session draws its framed IPv4 address from when RADIUS supplies no Framed-IP-Address and no Framed-Pool. Precedence: RADIUS Framed-Poolppp pool <name> → the pool named default. Empty name or ppp undo pool clears it (back to default). Shown in show ppp as pool.

Access interfaces are a list: add / remove stage into the candidate, commit applies live, and save persists. Multiple names may be given per command.

Authentication. ppp auth-protocol takes a comma-separated set of allowed methods. The BNG proposes the strongest listed method and downgrades on NAK to any other listed method, refusing the rest.

Local credentials (chap-secrets). ppp secret add stores a username/password checked before RADIUS for PAP and CHAP-MD5 (the MS-CHAP variants stay RADIUS-relayed). A listed user is authoritative: a wrong password rejects rather than falling through to RADIUS. The optional <local-ip> pins our gateway address on the link and <remote-ip> pins the peer's framed IP (otherwise the pool/RADIUS supplies them). ppp aaa picks what happens on a local-store miss: on (default) forwards to RADIUS as before, off is local-only strict mode — unknown users are rejected, so a RADIUS-less box authenticates exactly its listed users. Rows persist as secret lines in ppp.conf (staged — commit applies live, save persists); show ppp lists the store (passwords masked).

MS-CHAP / MS-CHAPv2 and encryption. The MS-CHAP methods authenticate via RADIUS (the server needs its mschap module); the NAS relays the challenge/response and never sees the password. Because the BNG does not negotiate MPPE encryption, clients using MS-CHAP must be configured for optional, not required, encryption — a client that requires MPPE will bring the session up, find no encryption, and drop into a re-dial loop. PAP is unaffected.

5.1 IPv6 pool fallback

ppp ipv6 pool and pd-pool name an IPv6 prefix pool (see Section 6.4) used only when RADIUS returns no v6 prefix. Precedence is RADIUS-first: a RADIUS Framed-IPv6-Prefix (NA /64) or Delegated-IPv6-Prefix (PD) always wins, and the pool is drawn only when RADIUS returns none. RADIUS may also select which pool by name, in order: (1) the Netvyn IPv6 pool VSAs; (2) the unified Framed-Pool (attribute 88) name, so one policy name walls off both stacks (e.g. Framed-Pool=Expired places the user in the v4 and v6 Expired pool — the classic walled-garden with no separate v6 attribute); (3) the ppp ipv6 pool / pd-pool config name. An empty name or undo falls back to the pool named default. These knobs apply live on commit to new sessions; existing sessions keep their prefixes. ppp ipv6 disable skips IPv6CP entirely (v4-only). Pool utilization is show ipv6 pool.


6. IPoE Commands

IPoE / DHCP configuration lives in the dhcp view.

dhcp mode off|dhcp|ipoe|both             off = PPPoE only [default]
dhcp interface add <name> [<name>...]    add IPoE access interface(s) to the serve-set
dhcp interface remove <name> [<name>...] remove access interface(s) from the serve-set
dhcp auth mac|ip|option82|none           RADIUS identity (default mac → User-Name = MAC)
dhcp auth-password <secret>              MAC-auth password
dhcp mac-format colon|hyphen|bare        MAC string form (default colon)
dhcp pool <name>                         fallback address pool
dhcp lease-time <secs>                   DHCP lease (default 600)
dhcp undo <mode|auth|mac-format|pool|lease-time>

The IPoE access serve-set is an explicit list. Names are physical interfaces or VLAN sub-interfaces and are VLAN-aware. With no interface listed, IPoE/DHCP is served on nothing. add / remove stage into the candidate, commit applies live, and save persists. Multiple names may be given per command (space- or comma-separated).

6.1 Framed-IP pools

Framed-IP address pools live in the pool <name> view:

pool <name> range <start> <end> gateway <gw> [prefix <len>]       define range r0 (creates the pool)
pool <name> range add <start> <end> gateway <gw> [prefix <len>]   add a parallel range (live)
pool <name> range delete <start>                                  delete a range by its start address
pool <name> next <successor-pool>        overflow into another pool when full (or 'none')
pool <name> remove                       delete the pool (in-use pools retire then drain)
pool <name> undo next

A pool holds up to 16 ranges, used in parallel. Ranges are drawn round-robin — consecutive subscribers land in r0, r1, r2, r0, … rather than filling r0 first — and each range keeps its own gateway and prefix, so one pool may span several subnets. DHCP and IPCP answer with the gateway/netmask of the range the address actually came from, not the pool's first range. A full or retired range is skipped; the pool is "full" only when every range is exhausted, which is the point at which next takes over. The two mechanisms are independent:

        ipoe_pool                         ipoe_pool2
   r0 ── r1 ── r2   ──all full──>    r0 ── r1 ── ...
   \___ parallel ___/                 \___ parallel ___/

show pool prints one row per range (r0, r1, …) plus a pool total.

Live-grow. Adding a range applies live on commit: the new addresses join the round-robin immediately, with no restart and no disturbance to bound subscribers (each range owns its own slice of the pool bitmap, so existing allocations are untouched). This is the supported way to grow a pool under load. Redefining r0 on an existing pool still applies on restart — a live reshape of a range that is already serving addresses would orphan them — so pool <name> range <start> … on a live pool commits successfully but changes nothing until the daemon restarts. Use range add when you mean "more capacity now".

Deleting a range is by start address, not index — indexes shift when a range is removed, start addresses do not. A range with subscribers still bound is retired rather than dropped: no new allocations, existing addresses keep working, and it disappears once drained ([range retired] in show pool). A pool's last live range cannot be deleted; remove the pool instead.

Validation. A range is rejected at commit if it overlaps any other range in any pool, if it spans more than one subnet of its prefix (e.g. 10.0.0.2-10.0.0.8 prefix 29, which straddles the .0/29 and .8/29 boundary), if its gateway falls outside its own subnet, or if it would push the pool past 16 ranges or 65536 addresses. Overlap is rejected because the allocator locates an address by range when freeing it — two ranges covering one address would make ownership ambiguous.

Rejections at staging time (bad prefix, gateway outside the subnet) print at the prompt. Rejections at apply time (overlap with a range the allocator already holds) are reported as commit failed: 0 applied, 1 failed with the reason in the daemon log — journalctl -u bng | grep "config: pool".

6.2 Subscriber DNS

DNS is shared by every framed-IP pool, so it is configured globally, not per pool:

ip dns <primary> [secondary]      IPv4 subscriber DNS (IPCP + DHCP option 6)
ip dns none                       clear IPv4 DNS
ipv6 dns <primary> [secondary]    IPv6 subscriber DNS (RA RDNSS + DHCPv6)
ipv6 dns none                     clear IPv6 DNS
show ip dns                       show the live IPv4 subscriber DNS
show ipv6 dns                     show the live IPv6 subscriber DNS

Both apply live on commit and are persisted by save. IPv4 DNS is handed out in IPCP and DHCP option 6. IPv6 DNS is delivered both as the RA RDNSS option (for SLAAC clients) and via DHCPv6, so any CPE learns it.

6.3 DHCP mode

DHCP mode both serves both DHCP and IPoE-authenticated subscribers; dhcp and ipoe restrict to one; off disables IPoE entirely (PPPoE only).

6.4 IPv6 prefix pools

Named IPv6 prefix blocks the box carves per-subscriber prefixes from when RADIUS returns no v6 prefix. A pool is role-neutral — the reference site decides how a drawn prefix is used (ppp ipv6 pool / dhcpv6 pool → framed /64 NA/SLAAC; ppp ipv6 pd-pool / dhcpv6 pd-pool → delegated PD prefix), so the same pool can be referenced either way. Distinct pools must not overlap.

ipv6 pool <name> <base>/<plen> assign <plen>   create/replace a named IPv6 prefix pool
ipv6 pool <name> remove                         delete the pool
show ipv6 pool                                  pool utilization (base/assign, in-use, free)

assign must be longer than the base prefix length; the number of assignable prefixes is 2^(assign − base), capped at 65536. A pool named default (else the first pool defined) is the one an empty pool reference draws from. ipv6 pool stages into the candidate and commit applies it live — a new pool is drawable immediately. Removing or reshaping a pool that still has live allocations keeps the old shape until restart so no subscriber's prefix is orphaned. save persists the pool set.

6.5 DHCPv6-PD knobs

IPoE IPv6 prefix-delegation parameters live in the dhcpv6 view — the IPoE twin of §5.1's ppp ipv6 pool / pd-pool:

dhcpv6 mode off|on|pd                serve IA_PD (default off; 'pd' is an alias of 'on')
dhcpv6 t1 <secs>                     IA_PD T1 renew timer (default 3600)
dhcpv6 t2 <secs>                     IA_PD T2 rebind timer (default 5400)
dhcpv6 preferred-lifetime <secs>     prefix preferred lifetime (default 604800)
dhcpv6 valid-lifetime <secs>         prefix valid lifetime (default 2592000)
dhcpv6 pool <name>                   IPoE NA /64 pool — RADIUS-less fallback (§6.4)
dhcpv6 pd-pool <name>                IPoE PD delegated-prefix pool — RADIUS-less fallback (§6.4)
dhcpv6 undo <mode|t1|t2|preferred-lifetime|valid-lifetime|pool|pd-pool>

The delegated prefix is the subscriber's RADIUS Delegated-IPv6-Prefix; dhcpv6 pool / pd-pool are drawn only when RADIUS returns none. All apply live on commit to new/renewing bindings; save persists them to dhcpv6.conf. Inspect with show dhcpv6.


7. Routing Commands

Routing is one command family per address family. The default gateway is simply the 0.0.0.0/0 route (IPv6: ::/0) — there is no separate WAN/LAN concept. ip route is IPv4-only and ipv6 route is IPv6-only; the ipv6 keyword is compulsory.

ip   route add <a.b.c.d/p> gateway <ip> [interface <name>] [distance <n>] [metric <n>] [weight <n>]
ip   route add <a.b.c.d/p> interface <name> [distance <n>] [metric <n>] [weight <n>]
ip   route add <a.b.c.d/p> <ip> [distance <n>] [metric <n>] [weight <n>]      (bare-gateway shorthand)
ip   route delete <a.b.c.d/p> [gateway <ip>]
ipv6 route add <x::y/p> gateway <ip6> [interface <name>] [distance <n>] [metric <n>] [weight <n>]
ipv6 route add <x::y/p> interface <name> [distance <n>] [metric <n>] [weight <n>]
ipv6 route add <x::y/p> <ip6> [distance <n>] [metric <n>] [weight <n>]         (bare-gateway shorthand)
ipv6 route delete <x::y/p> [gateway <ip6>]
  • Default gatewayip route add 0.0.0.0/0 <gw> (IPv6: ipv6 route add ::/0 <gw6>).
  • Bare gateway — the next-hop may be given with no gateway keyword: ip route add 10.4.4.0/29 10.20.50.1.
  • distance — administrative distance; the lowest live distance wins across sources (connected 0, RADIUS 5, static 10, DHCP 15, BGP 20, OSPF 110). 0 = the source's own default (static = 10).
  • metric — tie-break within one distance (lower wins).
  • weight — ECMP share among equal-distance routes to the same prefix (default 1).
  • Egress is derived from the gateway — the next-hop lives in exactly one connected subnet, so you never state the egress interface for a gateway route. interface <name> with no gateway makes a connected/link route out that interface.

ip route add / delete stage into the candidate and apply live on commit: the RIB reconciles without dropping sessions (the default row re-points the gateway), and save persists the routing table.

7.1 Inspecting the RIB / FIB

show ip route [detail]     the IPv4 RIB — prefix, gateway, source, distance, metric,
                           weight, selection flags (S selected, R resolved, r recursive, i inactive)
show ip fib                the selected route per prefix: prefix, nexthop, egress,
                           configured-nh, resolved-nh, state
show ip nexthop            the nexthop table (egress port + resolved gateway MAC)
show ipv6 route [detail] | show ipv6 fib | show ipv6 nexthop     the IPv6 twins
routing                    show routing knobs (recursive-via-default state)

7.2 Recursive resolution

A static route whose gateway is not on a connected subnet resolves recursively through the covering route (flagged r in show ip route). show ip fib exposes both the configured-nh (the route's own gateway) and the resolved-nh (the terminal on-link gateway the recursion reached); they differ exactly when the route is recursive.

routing recursive-via-default <enable|disable>   allow/deny recursion via the default route

Recursion through the default route is allowed by default (loop-guarded, capped at 8 hops). disable makes an off-net static gateway resolve to blackhole instead — a live toggle that re-resolves the RIB immediately.

7.3 Live default-gateway re-point

The default gateway is simply the 0.0.0.0/0 route, so it is set with the normal ip route command — there is no separate default-gw verb:

ip route add 0.0.0.0/0 gateway <ip>      set / change the default gateway
ip route delete 0.0.0.0/0                remove the default gateway
show ip route                            (the 0.0.0.0/0 row is the default gw)

The edit stages into the candidate; on commit the daemon ARPs the new gateway and swaps forwarding only once the new gateway answers (resolve-then-swap), so live sessions are preserved. save persists it to routing.conf.


8. Firewall Commands

The IPv4 firewall is a stateful ACL, configured in the firewall view.

firewall enable | disable                disable = default policy ACCEPT (enable is live)
firewall urpf strict | disable           BCP38 reverse-path source verify / anti-spoof (live on commit)
firewall undo enable

8.0a Mangle — packet rewriting (runs first)

The firewall is two ordered lists. mangle runs first and every matching rule runs (no verdict, no first-match), then filter decides accept/drop. That ordering is what makes a rewrite reliable regardless of what filter later does with the packet.

firewall mangle add <rule>
firewall mangle insert <N> <rule>
firewall mangle delete <N>
firewall mangle move <N> <M>

<rule> = <change-mss <mtu> | mark <n> | passthrough | return | accept>
         [chain prerouting|forward|input|output|postrouting]
         [<the same matches the filter list takes>]
Action Effect
change-mss <mtu> Clamp the TCP MSS on SYN to mtu-40. This is TCP MSS clamping — PPPoE access needs change-mss 1492.
mark <n> Set the conntrack mark. No consumer reads it yet, so today it is observable but inert.
passthrough Do nothing but count the match — a pure counter/probe rule.
return / accept Stop the mangle pass here (the filter list still runs).

⚠️ firewall mss-clamp was removed. MSS clamping used to be a scalar that silently synthesized two hidden rules. It is now an explicit rule you can see, count, and reorder. A firewall.conf carrying mss-clamp <mtu> will log an error at boot and will NOT clamp — migrate before upgrading:

firewall mangle add change-mss 1492 chain forward proto tcp
commit
save

show firewall lists the mangle rules with their own hit counters, and clear counters mangle [<n>] resets them.


8.1 Filter — the verdict

Ordered filter list, spread over three chains (chain forward|input|output). The FORWARD chain is evaluated once per direction (subscriber→network and network→subscriber), so a forward rule with no dir applies to both:

firewall filter add <rule>
firewall filter insert <N> <rule>        insert at 1-based index N
firewall filter delete <N>
firewall filter move <N> <M>             move rule N to index M
<rule> = <accept|drop|reject|return>
         [chain forward|input|output]        forward = transit (default)
         [dir up|down]                       forward chain only
         [proto tcp|udp|icmp]
         [src-address <a.b.c.d[/len]>] [dst-address <a.b.c.d[/len]>]
         [sport <ports>] [dport <ports>]     80 | 80,443 | 8000-8100 |
                                             53,80,8000-8100  (max 8 ranges)
         [state new|established]
         [src-list <name>] [dst-list <name>]
         [limit <rate> [burst <n>] [per-src]]

Match keywords are freely composable — write as many as the rule needs, in any order; the commit-time validator is the authority. Host bits in an address are masked off on commit, so src-address 10.1.2.3/24 canonicalizes to 10.1.2.0/24.

8.0 Chains, direction, and connection state

Chain What traverses it
forward (default) Transit traffic: subscriber ↔ network. Evaluated in both directions.
input Packets addressed to the BNG itself — management, API, CLI-over-IP, ping. The lock-down chain for the box's own services.
output IP traffic the BNG originates — its own UDP (RADIUS and friends) and the management TCP stack. Link protocols (ARP/ND/PPPoE/DHCP) are not IP-filterable and never traverse it, same as iptables.
Action Meaning
accept Permit; stop matching.
drop Discard silently; stop matching.
reject Discard with an ICMP/RST; stop matching.
return Stop matching and apply the default policy (accept) — the escape hatch that skips the rest of the list.
Match Meaning
(no dir) Both directions — the rule is evaluated on upstream and downstream packets
dir up Subscriber → network only
dir down Network → subscriber only
state <list> Connection state — a comma list of the five values below
src-address / dst-address Address or prefix; host bits masked off on commit
sport / dport One port, a comma list, and/or lo-hi ranges — up to 8 ranges in a single rule (needs proto tcp or proto udp)
State Matches
new No tracked flow yet (the first packet of a connection)
established The flow's reply has been seen (shared NAT conntrack, incl. the UDP EIM mapping)
related An ICMP error whose embedded datagram belongs to a tracked flow (RFC 5508) — unreachable / time-exceeded / PMTUD about a connection you already allowed
invalid Cannot belong to any known flow: a mid-stream TCP segment (no SYN) with no conntrack entry, or an ICMP error matching nothing
untracked Conntrack does not apply — NAT is off for this subscriber (routed public / bypass) or globally. These are not new; match them with untracked.

States combine: state established,related is the standard "allow the replies and the ICMP errors about them" rule.

The inbound lockdown — allow anything the subscriber starts, block the rest:

firewall filter add accept dir up               # anything the subscriber initiates
firewall filter add accept state established    # replies to it
firewall filter add drop dir down               # unsolicited inbound
commit

Multi-port and address examples — one rule where several used to be needed:

# lock management down to the NOC prefix (INPUT chain)
firewall filter add accept chain input proto tcp dport 22,8090 src-address 10.10.0.0/16
firewall filter add drop   chain input proto tcp dport 22,8090

# block a set of outbound ports for one subscriber range
firewall filter add drop dir up proto tcp dport 25,135,139,445,3389 src-address 100.64.0.0/10

# the BNG's own RADIUS traffic may only reach the AAA server (OUTPUT chain)
firewall filter add accept chain output proto udp dport 1812,1813 dst-address 10.20.0.5/32

⚠️ State needs conntrack. It resolves through the NAT flow table, so it works for CGNAT/SNAT subscribers. A subscriber on a routed public IP with NAT bypassed has no conntrack entry: those packets match untracked (not new), so gate them with untracked, dir, or an address/port match. Upstream the ACL runs pre-NAT and probes the flow read-only, so a drop never consumes a CGNAT port.

Apply timing: everything here is live on commitfirewall enable, firewall urpf, and the mangle + filter rule lists (the compiled rule set is rebuilt and published atomically; per-rule hit counters restart at zero when the list changes). save persists to firewall.conf. show firewall lists per-rule hit counters; show firewall drops shows the ACL verdict total and the uRPF anti-spoof discard total. clear counters firewall [<n>] zeroes per-rule counters (immediate).

8.2 Rate limiting (anti-scan / SYN-flood / brute-force)

A filter rule can carry a token-bucket rate limit, appended after the match keywords:

firewall filter add <accept|drop|reject> [...matches...] limit <rate> [burst <n>] [per-src]
  • limit <rate> — packets per second the rule is allowed to match (1..1000000000).
  • burst <n> — bucket depth (max tokens); the size of a momentary burst before metering bites. Default = rate.
  • per-src — meter each source IP independently (a per-worker direct-mapped cache). Without it, limit is a per-rule aggregate across all sources.

The rule matches only while a token is available; over the limit it falls through to the next rule. So the idiom is an accept ... limit immediately followed by a drop — accept up to the rate, drop the excess. This is the anti-scan / SYN-flood / brute-force control the routed public ranges need (a port scanner opens many new connections from one source → per-src on state new caps them):

# cap new inbound TCP to 20/s per source, drop the overflow
firewall filter add accept proto tcp state new limit 20 burst 40 per-src
firewall filter add drop   proto tcp state new
# throttle SSH brute-force to 3 new conns/s per source
firewall filter add accept proto tcp dport 22 state new limit 3 burst 5 per-src
firewall filter add drop   proto tcp dport 22 state new

⚠️ The bucket is per-worker. RSS spreads a source's flows across all workers, so for spread traffic the effective aggregate is ≈ n_workers × rate; for a single-flow flood (one 5-tuple → one worker) it is exact. Size <rate> with that in mind. Like all filter-rule edits, a limit change applies live on commit (save persists). show firewall prints the limit next to the rule.

8.3 Address lists

A named address list is a set of addresses that rules match against with src-list / dst-list — the same idea as a RouterOS address-list. One rule can then cover thousands of addresses, and the membership changes without touching the rule.

firewall address-list add <name> <ip|cidr> [timeout <secs>]
firewall address-list remove <name> <ip|cidr>
show firewall address-list [<name>]      entries (host + subnet); no name = every list

Three things populate a list:

Source Behaviour
RADIUS The Netvyn-Firewall-Address-List VSA (attr 33) tags the subscriber's framed IP into the named list for the life of the session — added at session-up, removed on teardown. Works for PPPoE and IPoE.
Operator firewall address-list add|remove above.
Rules A rule action can add the packet's source/destination to a list.

A bare address is a host entry (/32); a.b.c.d/len is a subnet entry matched by longest prefix. timeout gives a host entry a TTL — without it the entry is permanent (that is how RADIUS session tags and static entries are stored, removed explicitly rather than aged out). Subnets are always permanent. The list is created automatically on first use.

These edits are LIVE and IMMEDIATE — unlike filter rules, they do not stage into the candidate and need no commit. That is deliberate: they are the same code path RADIUS uses to tag a subscriber mid-session. For entries that must survive a restart, put address-list <name> <ip|cidr> lines in firewall.conf.

Example — drop everything sourced from a quarantine set that RADIUS populates:

[Netvyn-BNG] firewall filter add drop src-list quarantine
[Netvyn-BNG] commit
<Netvyn-BNG> show firewall address-list quarantine

8.3 IPv6 firewall

The IPv6 firewall is a completely separate, stateless engine — its own rule table, per-rule counters, enable gate, and uRPF flag. A v4 rule never sees a v6 packet and vice-versa. Because IPv6 is never NAT'd, there is no state match and no mangle list.

firewall enable6 | disable6                arm / bypass the v6 ACL (live on commit; default disabled = ACCEPT)
firewall urpf6 strict | disable            v6 reverse-path anti-spoof, separate from v4 (live on commit; default disable)

Ordered v6 filter list, where <rule> = accept|drop|reject [proto tcp|udp|icmp6|<n>] [src <pfx>/<plen>] [dst <pfx>/<plen>] [dport <n>] [sport <n>] [icmp6-type <n>]:

firewall filter6 add <rule>
firewall filter6 insert <N> <rule>
firewall filter6 delete <N>
firewall filter6 move <N> <M>

Apply timing: everything here is live on commitenable6, urpf6, and filter6 rule changes (rule set rebuilt + published atomically; per-rule counters restart at zero when the list changes). show firewall6 lists the v6 rules with per-rule hit counters and uRPF state; show firewall6 drops shows the v6 drop/reject totals. clear counters firewall6 [<n>] zeroes the v6 per-rule counters (immediate).

v6 uRPF defaults OFF. Leave urpf6 disable until subscriber v6 reverse-routes are installed in the RIB; a strict v6 check otherwise drops a legitimate static v6 host on a subscriber's circuit. This is why v6 anti-spoof is a separate toggle from v4.


9. NAT / CGNAT Commands

NAT / CGNAT configuration lives in the nat view.

nat enable | disable                     disable = fast path is plain forwarding
nat conntrack-max <count>                LIVE admission ceiling (default 1048576)
nat conntrack-capacity <count>           flow-table ALLOCATION; applies on restart
nat timeout <type> <seconds>             type ∈ tcp-established|tcp-closing|tcp-close|
                                         tcp-syn|udp|udp-stream|udp-eim-reserve|icmp
nat udp-mapping endpoint-independent|symmetric   RFC 4787 (default EIM/EIF)
nat pool add <name> <ip-lo>-<ip-hi> ports <lo>-<hi> block <size> [deterministic|dynamic]
nat pool remove <name>                   CGNAT public pool (name-keyed)
nat undo <enable|conntrack-max|conntrack-capacity|udp-mapping|timeout <type>>

conntrack-max and conntrack-capacity are two different things. capacity is what gets allocated at startup — the conntrack arena, its hash and the free-id ring — and cannot change without a restart, because the workers index those structures lock-free on every packet. conntrack-max is only the admission ceiling: a comparison against the in-use count, so commit applies it immediately with no reallocation and no restart.

Size capacity generously from the hugepages you provisioned (headroom costs only memory) and tune conntrack-max live. Raising the ceiling past capacity clamps it and says so. A nat.conf that sets only conntrack-max still behaves exactly as before — it sets both.

nat conntrack-capacity 2000000    # allocate for 2M flows  (restart)
nat conntrack-max        800000   # admit at most 800k     (live)

show nat statistics reports both, and counts admission refusals (limit refusals) separately from arena and hash-insert failures — three different causes that used to be reported identically as "conntrack table full".

CGNAT public pools (nat pool add / remove) are keyed by name (order is irrelevant). block must be a power of two; deterministic emits one compliance log per block (RFC 7422). Pools stage into the candidate and apply live on commit for NEW sessions — existing sessions keep the block they hold until re-login, and a pool's index is boot-stable and embedded in every outstanding CGNAT block, so the table is rebuilt at boot rather than mutated live. commit records the running set, save persists it, and the new pool loads at the next restart. Referencing a brand-new pool from a nat policy rule requires the pool to be live first (restart).

9.1 NAT policy list

An ordered, first-match policy list that applies live:

nat policy add nat-rule <cidr> pool <name>|bypass
nat policy add snat <cidr> to <target>
nat policy insert <N> nat-rule …|snat …      insert at 1-based index N
nat policy delete <N>                        delete rule at index N
nat policy move <N> <M>                      move rule N to index M

9.2 Destination NAT (port forward)

nat policy handles inside → outside (SNAT/CGNAT). DSTNAT is its mirror — outside → inside — so a service behind CGNAT can be reached from the Internet. It is an ordered, first-match list with the same editor shape, and it applies live:

nat dstnat add <rule>
nat dstnat insert <N> <rule>             insert at 1-based index N
nat dstnat delete <N>
nat dstnat move <N> <M>
show nat dstnat                          rules + per-rule forwards and up/down pkts/bytes

where <rule> = <public-ip> [proto tcp|udp|any] [dport <port>] to <inside-ip> [to-port <port>] [disable]

Form Meaning
Port-baseddport given public-ip:portinside-ip:port. to-port defaults to the matched dport.
Address-baseddport omitted The whole public IP (all ports) → the inside host. Only valid when that subscriber is the sole owner of the IP.
[Netvyn-BNG] nat dstnat add 203.0.113.5 proto tcp dport 8080 to 100.64.0.9 to-port 80
[Netvyn-BNG] commit

Return traffic needs no rule. The first inbound packet creates a conntrack entry whose reply key is the inside→peer tuple, so the subscriber's replies are automatically translated back to the public ip:port on the way out.

Ownership is enforced. The BNG verifies that the inside subscriber genuinely owns the public ip[:port] from its deterministic CGNAT block. A rule pointing at another subscriber's public IP simply never forwards — one customer can never hijack another's public address. The forward is also inactive while the subscriber is offline.

Choose a port outside the dynamic range. The forwarded public port is not reserved in the CGNAT port allocator, so pick a service port that the same subscriber's outbound flows will not be assigned.

9.3 Source / Destination NAT (unified view)

Source NAT (snat) and destination NAT (dstnat) are two existing engines — there is no separate "nat rule" command. The WebUI presents them as one merged "Source / Dest NAT" list (action = srcnat/dstnat) for convenience, routing each edit back to the underlying engine; on the CLI you use the two commands directly:

nat policy add snat <inside-cidr> to <target>     # srcnat: rewrite source (see §9.1)
nat dstnat add <rule>                             # dstnat: rewrite destination (see §9.2)

nat policy is otherwise CGNAT-only (nat-rule <cidr> pool|bypass); its snat rows are the source-NAT half of the merged view. Both apply live on commit and save to nat.conf.

Per-rule counters: dstnat rules now carry live up/down packet+byte counters (bumped on every packet via the conntrack entry's recorded rule index) — see them in show nat dstnat and the WebUI's Traffic column. Still planned (Phase 2b): the same counters for snat rules, and richer 5-tuple matching — letting snat also match dst/dst-port and dstnat also match src (extending the two commands, not a new engine). The merged WebUI list already shows the Src/Dst IP:port columns; the extra match fields activate once that extension lands.

9.4 IPv4 fragment handling

cgnat fragments mode <drop|cache|reassembly>     IPv4 fragment handling (default cache; live)
cgnat fragments timeout <secs>                   fragment-cache entry lifetime (default 30s)
cgnat fragments rss <enable|disable>             ⟳ hash UDP on the IP 2-tuple so a datagram's
                                                   fragments co-locate on one worker (default
                                                   disable; APPLIES ON RESTART — RSS is set at
                                                   port init). Persist with 'save'.
show cgnat fragments                             fragment counters + rss-colocate state

Large-UDP applications (e.g. RDP-UDP). Non-first fragments carry no L4 header, so plain NAPT drops them and the datagram never reassembles — large-UDP apps freeze. cache mode (the default) records the first fragment's translation and applies the same IP rewrite to the trailing fragments (virtual reassembly, RFC 6888 REQ-11), with no physical reassembly cost. drop is the old behavior; reassembly is an accepted alias of cache.

rss enable — the fragment cache is per-lcore, so all fragments of a datagram must reach the same worker. By default the NIC hashes a datagram's first fragment on the UDP 4-tuple (it has the L4 header) but the trailing fragments on the IPv4 2-tuple — splitting them across workers, so the trailing fragment misses the cache and the datagram is lost (seen as ~13–40% loss on >MTU UDP; TCP and sub-MTU UDP are unaffected). rss enable drops UDP to the 2-tuple so first + trailing co-locate. Trade-off: UDP between one IP pair no longer spreads across workers (TCP keeps its 4-tuple spread). Because the RSS hash is fixed when the ports come up, this applies on restartcommit + save, then restart the daemon. show cgnat fragments shows the current rss-colocate state.

9.5 Diagnosing a one-way UDP freeze

When a subscriber's TX drops to 0 while RX stays high (client sending, replies not arriving), show nat statistics splits the reason at the point a WAN reply is reverse-translated:

  • translation misses — reply hit a public ip:port with no mapping (outside port released/reallocated).
  • stale-mapping drops — mapping belongs to a dead session.
  • expired-mapping hits — mapping idle past its timeout (GC lag).
  • fragment-miss drops — out-of-order fragment with no first fragment cached.
  • translation hits — delivered. If this climbs while TX is still 0, the loss is downstream of NAT.

show nat session [<ip>] and show nat flow [<ip>] dump the live conntrack per flow — subscriber, private ip:port, public ip:port, peer, mapping state, and timeout remaining — and <ip> filters to one subscriber (by private or public IP). show nat statistics detail additionally lists recent misses (the exact public ip:port WAN replies hit with no mapping) and fragment counters.

Procedure: run clear counters nat at the start of a freeze, let it run ~30 s, then show nat statistics detail and note which counter climbs before applying a fix.

9.6 Port-block occupancy (show nat block[s]) — sizing the pool

How full is a subscriber's port block, and how full is the pool? The per-block free bitmap is the ground truth (1 bit = 1 outside port in use), so this is exact and cheap:

show nat block <private-ip>    one subscriber's block: public IP, port range,
                               ports used/free, utilization %, quarantined EIM
                               ports, and the pool math (subs per public IP,
                               total blocks). Warns at >=90% full.
show nat blocks                per-pool summary (blocks allocated vs capacity,
                               average + busiest ports/block) and the 10 busiest
                               blocks — the "who is about to exhaust" view.

Example — a subscriber on a ports 1024-65535 block 8192 pool:

<Netvyn-BNG> show nat block 100.64.0.2
  private-ip      user                 public-ip       ports       used        util quar  pool
  100.64.0.2      krishna@pppoe        103.x.x.10      1024-9215    611/8192     7%    0  cgnat1
  (pool 'cgnat1': ports 1024-65535 block 8192 -> 7 subscribers/public-IP x 8 IP(s) = 56 blocks total)

Reading it for sizing: util near 100% on individual subscribers → raise the pool's block size (fewer subs per IP, more ports each); blocks allocated in show nat blocks near the pool's capacity → add public IPs to the range (or shrink the block size). Exhaustion events (drops) are the "no free outside port" counter in show nat statistics / nat-alloc-fail in show drops. Pool changes stage with nat pool add|remove and apply live on commit for new sessions (existing sessions keep their block; reshaping an in-use pool's IP/port range still needs a restart). Freed blocks are reclaimed for the next login, so session churn no longer leaks pool slices.


10. QoS Commands

QoS is built from three objects, configured in the qos view:

  • A queue profile is the scheduler discipline only (pfifo / tb / fq_codel / fq_pie / cake + tuning). It carries no rate. (fq_pie is the native rte_sched PIE discipline; fq_codel and cake approximate their namesakes on the same PIE core, so the fq-family tuning keys are identical.)
  • A subscriber profile owns the rate (down/up) plus an optional local priority, and points at a queue profile.
  • An assignment binds a prefix to a subscriber profile.

A subscriber's effective QoS resolves as: a matching assignment (longest prefix) → its subscriber profile's rate + priority + queue profile; else the RADIUS rate on the per-service default queue profile (PPPoE vs. IPoE); else the service default at the port rate.

All four collections are index-addressable lists, and rows can equally be addressed by name (queue/subscriber profiles) or by CIDR (assignments) wherever an index is expected — modify fq ..., delete testip, move 10.20.50.4/32 1. Edits stage into the candidate; commit applies live (re-binding and re-queuing matching live subscribers); save normalizes the QoS configuration to canonical form.

Completion is discipline-aware. After a discipline (add x fq_pie ?) the CLI offers only that discipline's keys; after a profile name (qos queue-profile fq ? or modify fq ?) it asks the daemon for the profile's actual discipline and scopes the key list to it (falls back to the full set for an index selector).

10.1 Live queue-profile changes — applied on commit

A queue profile's own discipline / qsize / AQM layout is fixed when a port is built, so the daemon keeps parallel scheduler generations. Editing a queue profile and running commit builds a new generation from the committed config alongside the running one — live, no restart, and no separate qos retune step (that command has been removed; commit does the work, and it applies the in-memory candidate rather than re-reading qos.conf):

show qos generations         which generation is current + how many subscribers ride each
  • New sessions bind to the new generation immediately.
  • Existing sessions keep forwarding on the old generation and migrate gradually — on reauth/reconnect and via a controlled background rebind (~64 subscribers / 20 ms).
  • The old generation is freed once no subscriber references it (show qos generations shows it drain to 0, then (free)).
  • Only one rebuild in flight: if a committed change can't get a free generation slot (the predecessor is still draining), the profile re-point applies but the qsize/AQM rebuild is deferred — retire the draining generation and re-commit.
  • Scope: tuning existing profiles in place. Structural changes (adding/removing/ reordering profiles, port rate, max-pipes) still need a restart.

10.2 Queue profiles

qos queue-profile add    <name> <tb|pfifo|fq_codel|fq_pie|cake> [tuning...]
                                                  (fq_pie = flow queues + the native PIE AQM;
                                                   same tuning keys as fq_codel)
qos queue-profile <name> <key> <val> [...]        (EDIT BY NAME: merge keys onto the profile,
                                                   e.g. `qos queue-profile fq target 8000`;
                                                   a discipline after the name redefines the row)
qos queue-profile modify <N|name> <key> <val> [...]           (merge just those keys)
qos queue-profile modify <N|name> <disc> [tuning...]          (redefine, name kept)
qos queue-profile modify <N|name> <name> <disc> [tuning...]   (full row; renames if the name differs)
qos queue-profile insert <N> <name> <disc> [tuning...]
qos queue-profile delete <N|name>     (refused if referenced by a sub-profile / service default)
qos queue-profile move <N|name> <M>

qos subscriber-profile <name> <key> <val> [...]   (same merge-edit, e.g.
                                                   `qos subscriber-profile testip rate-down 100M rate-up 100M`)

Queueing (qsize/AQM/discipline) takes effect on commit (Section 10.1) — no restart. commit stages the model and activates it (builds a new scheduler generation from the committed config); save persists it to qos.conf. The shaper is a token-bucket with optional WRED/PIE AQM, so some Linux tc-style knobs are advisory — stored, shown in show qos with (advisory), and round-tripped, but not enforced by the data plane. AQM knobs (target / interval / rtt / ecn) run only when AQM is enabled in the build and aqm enable is set; otherwise the discipline is tail-drop and those knobs are inert.

Fields by discipline — only the keys valid for a discipline are accepted:

Discipline Key Value Effect
all qsize packets (pow2) ✅ Best-effort buffer depth. Keep generous — a too-small qsize starves a single TCP flow below its rate.
tb burst bytes (k/M) ✅ Micro-burst allowed before shaping bites
tb limit <ms>ms ✅ Max queue latency when the bucket empties
fq_codel / fq_pie / cake flows count ⚠️ Advisory
fq_codel / fq_pie / cake target <us> / <ms>ms ✅ (AQM) PIE latency target
fq_codel / fq_pie / cake interval <us> / <ms>ms ✅ (AQM) PIE update interval
fq_codel / fq_pie / cake ecn on/off ✅ (AQM) ECN-mark vs. drop
fq_codel / fq_pie / cake quantum bytes ⚠️ Advisory
fq_codel / fq_pie / cake memory bytes ⚠️ Advisory
fq_codel / fq_pie / cake ce-threshold <us> ⚠️ Advisory
cake overhead bytes ✅ Per-packet link-overhead compensation
cake rtt <ms> ✅ Feeds the PIE target when target is unset
cake diffserv besteffort|diffserv3|diffserv4|diffserv8 ✅ Tin count
cake flow-mode triple-isolate|flows|hosts|src-host|dst-host|dual-src-host|dual-dst-host ⚠️ Advisory
cake ack-filter / wash / nat / autorate on/off ⚠️ Advisory

Examples:

qos queue-profile fq target 8000                  # merge-edit by name: change one key
qos queue-profile modify fq qsize 512 burst 16k   # merge several keys
qos queue-profile fq cake qsize 4096 rtt 100      # redefine fq as cake (name kept)
qos queue-profile add fqpie fq_pie qsize 4096 target 15ms interval 15ms ecn on
qos queue-profile add cake0 cake qsize 4096 target 5ms interval 100ms overhead 18 rtt 100 diffserv diffserv4 flow-mode triple-isolate ack-filter on wash on
qos subscriber-profile testip queue-profile fqpie # move a plan onto the new queue type
commit ; save

10.3 Pipe budget

qos max-pipes <n>                        subscriber pipe budget (power of two)

Every subscriber that is shaped holds one scheduler pipe, and pipes are pre-allocated. If max-pipes is below your peak concurrent session count, the subscribers past it get no shaper at all — full port rate, rate plans unenforced. Set it above your licensed session count.

commit applies it live: a new scheduler generation is built from the updated config, new sessions bind to it, and existing subscribers drain across in bursts of 64 every 20 ms until the old generation empties and is reclaimed. No restart, no session loss. If the new generation cannot be allocated — not enough hugepage memory, or the previous generation is still draining — the value is rolled back and the box keeps shaping at the old budget.

Must be a power of two (rte_sched): 256, 512, 1024, 2048, 4096, 8192, 16384.

Memory scales linearly, and the multiplier is not obvious:

subports x max_pipes x 16 queues x qsize x 8 bytes

Each queue profile gets its own subport, and every subport enables the full max-pipes — including profiles no subscriber uses. Deleting unused queue profiles from qos.conf cuts pipe memory proportionally, and qsize is the other large factor. Five profiles at qsize 4096 costs roughly 15x what two profiles at qsize 512 costs for the same pipe count.

show qos reports the budget, the static-binding reserve and the active session count, warns within 10% of the cap, and reports loudly if any session ever installs without a pipe.

10.4 Overhead compensation

qos overhead-compensation <pct>          shape each pipe <pct> above plan so goodput ≈ plan (0..100)

A shaper counts the full L1/L2 (+PPPoE) frame, but a speed test measures TCP payload — so a 300M pipe reads ~268M. qos overhead-compensation shapes each pipe that percentage above its plan so goodput matches the plan (~8–12%; PPPoE nearer 12, IPoE nearer 8; 0 = exact plan). It stages into the candidate: commit applies it live — sets the global and rebinds every installed subscriber's pipes at their current rate so the new margin takes effect immediately — and save persists the overhead-compensation line to qos.conf. show qos shows the active value. (The overhead-compensation <pct> line in qos.conf is still read at boot; the CLI verb is the live equivalent.)

10.5 Subscriber profiles

qos subscriber-profile add <name> rate-down <r> rate-up <r> [queue-profile <qp>] [priority <1-8>]
qos subscriber-profile <name> <key> <val> [...]      (EDIT BY NAME: merge keys, e.g.
                                                      `qos subscriber-profile testip rate-down 100M rate-up 100M`
                                                      or `... testip queue-profile fqpie`)
qos subscriber-profile modify <N|name> <key> <val> [...]   (same merge; full row also accepted)
qos subscriber-profile insert <N> <name> rate-down <r> rate-up <r> [queue-profile <qp>] [priority <1-8>]
qos subscriber-profile delete <N|name>
qos subscriber-profile move <N|name> <M>
  • <r> accepts k/M/G (100M, 2G, 512k); rate <tx>/<rx> is also accepted.
  • queue-profile <qp> must name an existing queue profile; omitted or - inherits the per-service default.
  • priority <1-8> is a local priority (1 = served first under congestion, 8 = last) applied when this profile backs a static assignment — the configured equivalent of RADIUS Netvyn-Priority. A static assignment and its priority resolve first, overriding any RADIUS rate/priority. Omitted = unset (default weight).

10.6 Assignments

qos assign add <cidr> subscriber-profile <name>
qos assign insert <N> <cidr> subscriber-profile <name>
qos assign delete <N|cidr>              (e.g. `qos assign delete 10.20.50.4/32`)
qos assign move <N|cidr> <M>
  • <cidr> is IPv4 or IPv6: a host (10.20.50.3/32, 2001:db8::1/128) or a prefix (100.64.10.0/24, 2001:db8:100::/40).
  • <name> must reference an existing subscriber profile.
  • Resolution is v4-first: a dual-stack subscriber matches through its framed IPv4; the v6 assignments are consulted only when no v4 assignment matched. A v6 assignment matches the subscriber's framed v6 or its delegated (PD) prefix.
  • Both families share the subscriber's one shaper pipe per direction — the plan rate is the combined v4+v6 throughput.

10.7 Service default queue type

Which queue profile PPPoE / IPoE subscribers run on by default:

qos service ppp  <queue-profile>
qos service ipoe <queue-profile>

These stage into the candidate; commit applies live — the service default switches and every installed subscriber whose resolved queue profile changed is re-queued on the spot at its current rate (RADIUS rates untouched). Subscribers pinned to a queue profile through an assignment keep that pin (assignment > service default).

Referential integrity. References resolve against the running config, so a referenced object must be committed first: a subscriber profile's queue-profile must exist, an assignment's subscriber-profile must exist, and a subscriber profile still referenced by an assignment cannot be deleted. To add a new subscriber profile and an assignment that references it, commit the subscriber profile first. State is show qos (all three objects + service defaults) and show qos bindings (resolved effective QoS per live subscriber, with source: RADIUS / static / default). All rates display auto-scaled (512k / 50M / 52.4M / 2G) — non-round values (e.g. a RADIUS rate delivered in kbps) get one decimal instead of a raw kbps figure.


11. RADIUS Commands

RADIUS client configuration lives in the radius view and applies live on commit (the client rebuilds in place — servers re-resolved, scalars updated). The one exception is coa-port, whose listener re-binds only at boot.

radius server add <host> secret <s> [auth-port <n>] [acct-port <n>]   (default ports 1812/1813)
radius server insert <N> <host> secret <s> [auth-port <n>] [acct-port <n>]
radius server delete <N>
radius server move <N> <M>
radius nas-ip <ip>                       NAS-IP-Address (or 'none')
radius nas-id <id>                       NAS-Identifier (or 'none')
radius timeout <secs>                    per-try timeout (default 2)
radius retries <n>                       retransmits before failover (default 3)
radius coa-port <port>                   CoA/Disconnect port (default 3799; re-binds at boot)
radius interim-interval <secs>           interim acct interval (0 = off)
radius dict-path <path>                  dictionary tree path
radius message-authenticator off|on|require    RFC 2869 attr 80 (default on)
radius undo <nas-ip|nas-id|timeout|retries|coa-port|interim-interval|dict-path|
             message-authenticator>

The server list is index-addressable; insert / delete / move reorder failover priority. Live RADIUS state and counters are shown with show radius [statistics].

11.1 Message-Authenticator

Message-Authenticator (RFC 2869, attribute 80) is an HMAC-MD5 signature over the whole packet keyed with the shared secret. It provides integrity and authenticity — it is not encryption, and the digest itself travels in cleartext.

Mode Behaviour
off Never sent, never checked (legacy)
on (default) Sign every Access-Request; verify any reply that carries a signature
require As on, and additionally drop any Access-* reply that lacks or fails one

Keep this on. RADIUS/UDP's Response Authenticator is raw MD5, which is chosen-prefix collidable — an attacker positioned between the BNG and the RADIUS server can forge an Access-Accept out of an Access-Reject and authenticate a subscriber who should have been denied (CVE-2024-3596, "BlastRADIUS"). HMAC-MD5 is unaffected, so attribute 80 is the mitigation. There is a second, more mundane reason: modern RADIUS servers (FreeRADIUS 3.2.5+) increasingly require attribute 80 on requests, and with this off such a server silently drops every request the BNG sends — which presents as a total authentication outage rather than a protocol error.

show radius reports the mode; show radius statistics adds a bad-msg-authent. counter — replies dropped because the signature was missing or wrong (a forgery, or simply a shared-secret mismatch). Watch it after enabling, and only move to require once it stays at zero.

Only User-Password, Tunnel-Password and the MS-MPPE keys are obfuscated in RADIUS. Everything else — User-Name, NAS-IP, Framed-IP, Class, and all Netvyn VSAs — is plaintext on the wire. Attribute 80 does not change that; it only makes tampering detectable.


12. Monitoring Commands

12.1 Vendor monitoring API

A read-only framed-TCP API served by the daemon itself, for a billing portal or NOC dashboard to poll session, interface, resource and health statistics over one persistent TCP connection (not HTTP — see docs/vendor-tcp-api.md for the published wire protocol, message types and a reference client).

service api enable | disable                     start / stop the API (live)
service api listen <host:port>                   set the listen address (live rebind), e.g. 0.0.0.0:8090
service api allow <cidr>                         add a source prefix to the ACL
service api no allow <cidr>                      remove a source prefix from the ACL
show api                                 state, listen address, auth mode, allowed sources

api applies immediately (it is not staged behind commit). Clients must authenticate with an operator account (the AUTH command carries username + password — the same RBAC user store as the CLI/GUI; any role may read, so create a dedicated read-role account for the portal with system user add monitor read <pw>). Client connects, AUTH attempts and failures appear in show log api and the audit trail. Access is additionally restricted by the allowed-source ACL — an empty ACL means "any source", so add prefixes before exposing the port. Commands: SESSION_STATS (counts), SESSION_INFO (one session's tx/rx by username — the table is never dumpable), INTERFACE_LIST, INTERFACE_STATS, RESOURCES, HEALTH — all strictly read-only; there are no configuration or control operations.

12.2 Telnet CLI service

A native Telnet server on the BNG's own (DPDK) IPs: telnet <bng-ip> gives the operator a real bng-cli shell — each session spawns bng-cli on a pseudo-terminal, so login, RBAC, audit, idle logout, the Huawei-style views, TAB/? completion and history are all the genuine article (no second command parser, no second credential store).

service telnet enable                        start the service (DISABLED by default)
service telnet disable
service telnet listen <ip[:port] | port>     bind (default 0.0.0.0:23 = any router IP)
                                     forms: `0.0.0.0:2008` · `2008` (port only) · `10.0.0.1 2008`
service telnet allow <cidr>                  ACL a management prefix — checked BEFORE the login prompt
service telnet no allow <cidr>
service telnet max-sessions <1-16>           concurrent session cap
show telnet                          status, listen, shell, sessions, idle, ACL

All telnet settings stage into the candidate: commit applies them live (the listener rebinds on the spot) and save persists them to telnet.conf — the standard model, same as the rest of the configuration.

Requires the bng-cli binary installed at /usr/local/bin/bng-cli (the normal install location; PATH fallback). Ending the shell (quit from user view, or bng-cli's idle logout) closes the telnet connection.

⚠️ Telnet is plaintext — operator passwords travel unencrypted. The service is disabled by default; enable it only with an allow ACL restricting it to the management network, and never expose it toward subscribers or the Internet. A denied source is dropped before any banner is sent.

12.3 Compliance / IPDR logging

Compliance and per-flow CGNAT logging is configured in the system view:

system ipdr enable|disable           compliance (session/block) log
system ipdr file <path>              session/block log file
system ipdr flow enable|disable      per-flow CGNAT translation log (v4 CGNAT flows + v6 TCP connection-starts)
system ipdr flow prefix <tag>        collector line tag
system ipdr flow dir <dir>           daily per-flow file dir
system ipdr flow disk enable|disable local disk sink on/off (keeps dir; disable = remote-only)
system ipdr flow skip-dns            omit UDP/53 from the per-flow log
system ipdr flow log-dns             include UDP/53 (undo skip-dns)
system ipdr flow remote <host:port>  UDP collector for the per-flow log
show ipdr                            compliance + per-flow CGNAT log config and drop counters

ipdr enable / disable, ipdr file, and the per-flow prefix / dir / disk / remote / skip-dns / log-dns knobs apply live on commit — a collector can be re-pointed without dropping traffic. Only ipdr flow enable / disable takes effect on restart. save persists in every case. When the per-flow log is enabled it also captures IPv6 subscriber-initiated TCP connection starts (IPv6 has no CGNAT/conntrack). show ipdr prints the disk state, the IPv6 capture state, and separate v4 / v6 drop counters.

12.4 System and platform state

show version                 build version + DPDK version + uptime
show topology                lcore / worker / port plan (the live CPU plan)
show system                  CPU-plan knobs (control-cores, workers, ht-policy)
show health                  node vitals: uptime, per-core CPU %, memory, power + dispatch state
show power                   adaptive-polling state: adaptive on/off, nap-us, per-worker nap counts
show interface bonding       802.3ad/LACP + static bonds + live member state (§4.2)
dispatch                     software PPPoE RSS on/off state (§4.3)
show drops [<interface>]     fast-path forward + drop counters (optionally one interface)
show statistics [<interface>]  alias for show drops

12.5 Power management (adaptive polling)

The forwarding workers poll their NICs continuously, so each worker core reads 100 % in the OS regardless of traffic — and burns the matching power even at idle. Adaptive polling lets an idle worker nap briefly instead of hot-spinning, so an idle core draws power proportional to load. It is opt-in and OFF by default — with it off the data plane is byte-identical to the validated hot-poll baseline.

Set it from the system view (staged like any other config change):

system power adaptive enable|disable    turn adaptive polling on/off
system power nap <1-5000>               idle nap length in microseconds (default 50)
power                            show the live runtime state
show power                       dedicated read-only view (adaptive, nap-us, nap counts)

These stage into the candidate: run commit to apply live, then save to persist to system.conf so the setting survives a restart. Example:

[Netvyn-BNG] system power adaptive enable
staged: system power adaptive enable  ('commit' to apply, 'save' to persist)
[Netvyn-BNG] commit
[Netvyn-BNG] save

Both show version and show health print uptime as raw seconds plus a human-readable formuptime 3661 (1hr 1min 1sec) — so it stays script-parseable (the seconds come first) while an operator reads it at a glance (45sec, 1min 1sec, 1hr 1min 1sec, 2d 3hr 4min 5sec; leading zero units are dropped).

show health reports the live state on one line; show power gives the dedicated view with per-worker nap counts:

[Netvyn-BNG] show health
...
power-adaptive on nap-us 50 naps 1843201

[Netvyn-BNG] show power
adaptive       enable
nap-us         50
naps           1843201
state          idle workers nap (power proportional to load)
  worker 0     naps 921605
  worker 1     naps 921596

Trade-off: the nap is timer-based, so after an idle gap the first packet sees a wake latency ≈ the nap length (no cost under load — the nap never fires when traffic is flowing). For latency-strict deployments leave it off, or use a small nap value. Available on every platform; the deeper power backends (RX-interrupt sleep, CPU frequency scaling) are Linux-bare-metal roadmap items.

12.6 Operator accounts

Operator (CLI / GUI / API) accounts are separate from subscribers. The three assignable roles are:

  • read — view-only: show / display, ping, traceroute, whoami, and changing your own password.
  • write — adds configuration edits (nat, firewall, interface, pool, qos, radius, routing, …) plus subscriber actions (disconnect, coa) and the transaction verbs (commit / save / rollback).
  • full — the top assignable role (the effective "superadmin"). Required additionally for system … CPU/topology configuration (control-cores, max-workers, ht-policy), operator-account management (system user add / system user delete, disconnect user-session, aaa enable|disable), and license / reboot / shutdown / factory-reset / maintenance. Bare system and show system … stay read.

(A fourth role, engineering, is internal-only and can never be assigned.)

whoami                                   your own username + role                  (any role)
system user change <name> <new-password>    set an account's password (own: any role; other: full)
system user add <name> <role> <password> [<description>]   create an account             (full)
system user delete <name>                       remove an account                          (full)
disconnect user-session <id>             revoke a login (id from 'show user-sessions')  (full)
show users                               local operator accounts                    (read)
show user-sessions                       active operator logins                     (read)

Password rules. At least 8 characters, drawn from at least 3 of the 4 classes (lower-case, upper-case, digit, other), and no spaces. The password may not contain the username. Hashing is Argon2id, and repeated failures lock the account for a period, so a short password is not as exposed as the length alone suggests — but 8 is a floor, not a recommendation.

Whose password. system user change takes the account name first, and TAB completes it from the existing accounts:

system user change alice N3wPa55!

Changing your own password is allowed in any role. Changing someone else's requires full. The account name is required — system user change alice on its own is rejected rather than treated as a password, so a forgotten second argument cannot silently reset your own password to the other operator's name.

The historical single-argument form still works for self-service and is what passwd maps to:

passwd N3wPa55!

These are operational commands — they apply immediately and are not staged behind commit. The account-changing actions (system user add, system user delete, system user change, disconnect user-session) are recorded in the auth log (show auth log) alongside login and logout events — not the config audit trail. whoami and the show variants are not audited. Changing your own password drops your live sessions and forces a re-login.

First login. An account still on its initial password is in a forced first-login state: until you change it, the only commands accepted are system user change / passwd, whoami, config status, help, and logout — any other configuration or show is rejected with "default password in use — run 'system user change' before configuring." whoami flags the state, and the login banner returns first-login.

Either spelling clears it — your own name with the two-argument form, or passwd:

system user change admin N3wPa55!
passwd N3wPa55!

Delegated login (RADIUS). Operators that are not in the local store can be authenticated against a RADIUS realm instead:

aaa enable | disable                     delegate unknown-user login to RADIUS (default disable)  (full)
show aaa                                 delegated-login state                                    (read)

The realm's server and secret live in aaa.conf. On acceptance the server must return a Netvyn-Admin-Role VSA naming the role — an Access-Accept with no recognised role is denied, so a misconfigured realm can never silently grant access. Local accounts are always tried first, so aaa enable cannot lock you out of an existing local login.


13. Debug Commands

13.1 Diagnostic log

The diagnostic log is captured into an always-on in-memory ring, so you read recent history straight from memory with no file to tail:

show logging                 diagnostic log config: global level, sink, per-module levels
show log                     last 200 lines from every module
show log <module>            filter by module (radius, nat, pppoe, smgr, …)
show log <module> last <n>   tail <n> lines for one module
show log last <n>            tail <n> lines across all modules
clear log                    empty the ring
log level <module> <lvl>     set one module's level LIVE (immediate) and persist it
log level all <lvl>          set every module live (transient global sweep)

log level … is operational/immediate (no commit): a named module's level applies at once and is persisted; all is a live-only global sweep. Levels are off | critical | error | warning | notice | info | debug. To persist the global level, use system logging level <lvl> + commit.

The global diagnostic level and sink are set in the system view:

system logging level <off|critical|error|warning|notice|info|debug>   (default info)
system logging output memory|stdout|stderr|file <path>                (default memory)

memory (the default) keeps everything in the ring for show log; a stream sink is an optional passthrough. These apply live on commit.

13.2 Packet flow trace

The flow trace follows a packet through the fast path so you can see exactly where a flow is classified, translated, shaped, or dropped. It works like tcpdump -G: one command filters, captures for a fixed window, prints the matching flow, and auto-cleans up — the operator never needs a separate show or off.

debug trace packet src <ip>              flow FROM this source
debug trace packet dst <ip>              flow TO this destination
debug trace packet src <ip> dst <ip>     a directional flow (src AND dst)
debug trace packet ip <ip>               <ip> as src OR dst (either direction)
debug trace packet ... drops             only DROPPED packets (append to any filter)
debug trace packet ... for <1-30>        capture window in seconds (default 5)
debug trace packet off                   abort a running capture early
show debug packets                       re-read the last capture (per-flow L4 detail: see below)
show debug trace                         re-read the per-stage pipeline path

Default window is 5 s (for omitted). Valid range 1–30 s; outside it returns invalid duration (1-30 seconds allowed). A src filter shows packets from that IP, a dst filter shows packets to it. Example:

[Netvyn-BNG] debug trace packet src 100.64.0.2 for 10
capturing packets from src=100.64.0.2 for 10 seconds..........

filter: src=100.64.0.2
src:port              dst:port              prot  len flags  ttl  tcp(win/mss/ws | s=seq a=ack)  in>out nat      result
100.64.0.2:51001      142.250.4.100:443     tcp    60 ....S. 63   w64240/mss1452/ws8            1>0   snat     forwarded
100.64.0.2:51001      142.250.4.100:443     tcp    52 .A.... 63   w2058 s3428... a119...        1>0   snat     forwarded
100.64.0.2:5000       1.1.1.1:53            udp    64 -      63   -                             1>0   snat     forwarded

3 packet(s) captured (len=on-wire IP bytes; flags=UAPRSF; SYN shows mss/window-scale)
flow trace completed.

Each captured packet now carries per-flow L4 detail, captured at RX so it reflects the real segment sizes and TCP behaviour a subscriber's flow negotiated (useful for comparing a phone's download against a laptop's, or spotting a black-hole, without a span port):

  • src:port / dst:port — L4 ports for TCP/UDP.
  • len — on-wire IP total length (the number that matters for MTU/PMTUD).
  • flags — TCP flag field, tcpdump-style UAPRSF (. = clear).
  • tcp(...) — on a SYN, the receive window + mss/window-scale option (w64240/mss1452/ws8); on data/ACK packets, the window plus s=sequence and a=ack (repeated a= on ACKs = duplicate ACKs → downstream loss; repeated s= on data = retransmits).
  • in>out — ingress > egress port (- = egress not yet chosen at capture time).
  • natsnat / reverse / miss / none; resultforwarded or a drop:* reason.

Filter direction matters with NAT. Capture happens at RX, before NAT. Upstream packets carry the subscriber's inside IP (e.g. 100.64.0.3); downstream replies are addressed to the public pool IP and are only un-NAT'd after capture. So to see a subscriber's download, filter on their public IP (debug trace packet ip <pool-ip>), not the inside IP.

After printing, the trace auto-disarms and clears (back to idle). Use debug trace packet off only to abort a long capture before its window elapses.

The drops modifier finds a rare drop under load: without it, a high-volume forwarded flow floods the 1024-entry ring and overwrites the rare dropped packets; with it only dropped packets are captured (their real src → dst + reason), so debug trace packet drops surfaces exactly which flows hit ttl-expired / nat-fail / no-route. Narrow it with a src/dst filter (debug trace packet src 100.64.0.3 drops for 15) on a busy box — an unfiltered drops still stage-traces every packet.

Use the trace to confirm a subscriber's packets take the expected path (classification → routing → NAT → QoS → egress). Combine it with show nat session <ip> (Section 9.3) when diagnosing a translation problem for one subscriber.


14. Show Commands Reference

A consolidated reference of the show command family. show is immediate — it reads running state and live tables and never touches the candidate.

Command Shows
show version Build version
show topology lcore / worker / port plan (live CPU plan)
show system CPU-plan knobs (control-cores, workers, ht-policy)
show sessions Active PPPoE/IPoE sessions in one unified table (ip, if, rx/tx)
show ppp Running PPP/PPPoE config
show dhcp Running IPoE/DHCP config
show pool Running framed-IP pools + DNS
show interface One-line summary of every physical DPDK port (admin/oper/speed/type/description)
show interfaces Everything: physical ports + VLAN/QinQ sub-interfaces + trunks/bonds
show interface <name> Full per-port page: state, hardware, DPDK, counters, hardware xstats, transceiver identity + live DDM (see §17)
show interface stats Live per-port NIC counters (rx/tx pkts+bytes, err, drop) — one row per physical port
show interface vlan Configured VLAN/QinQ sub-interfaces
show interface vlan stats Per-VLAN rx/tx packets + bytes (each sub-interface's own traffic)
show interface bonding 802.3ad/LACP + static bonds: mode, TX policy, members + live LACP state (§4.2)
show ip address [<if>] Local interface IPv4 addresses (primary + secondaries)
show ipv6 address [<if>] Local interface IPv6 addresses
show ip dns / show ipv6 dns Live subscriber DNS
show nat NAT/CGNAT state: conntrack, timeouts, pools, policy
show nat session [<ip>] Per-flow conntrack dump (filter by subscriber IP)
show nat flow [<ip>] Active per-peer connections (subset of nat session)
show nat statistics [detail] NAT counters + downstream translation counters + recent misses
show nat block <private-ip> One subscriber's port block: used/free vs block size
show nat blocks Per-pool block occupancy summary + busiest blocks
show nat dstnat Destination-NAT (port-forward) rules + per-rule forward counts
show cgnat fragments IPv4 fragment counters
show firewall [drops] v4 firewall state + per-rule counters (drops = discard totals)
show firewall address-list [<name>] Named address-list entries (host + subnet, with TTL)
show firewall6 [drops] v6 firewall state + per-rule counters (separate, stateless)
show radius [statistics] RADIUS servers + scalars (or counters + RTT)
show arp [config] ARP keepalive watch table (or config for tunables)
show ip route [detail] IPv4 RIB (gateway, source, distance, metric, weight, flags)
show ipv6 route [detail] IPv6 RIB
show ip fib / show ipv6 fib Selected route per prefix programmed into the data plane
show ip nexthop / show ipv6 nexthop Nexthop table (egress port + resolved gateway MAC)
show nexthops Default-gw + configured next-hop summary
show ipv6 pool IPv6 prefix pool utilization
show logging Diagnostic log config (global level, sink, per-module levels)
show log [<module>] [last <n>] In-memory diagnostic log buffer
show ipdr Compliance + per-flow CGNAT log config
show api Vendor monitoring API: state, listen address/port, auth mode, allowed-source ACL
show qos [bindings] Queue + subscriber profiles + assignments (bindings = resolved per-subscriber)
show qos sub <id> Per-subscriber QoS detail (rates, octets, shaper drops, queue depth)
show qos generations Live scheduler generations (commit-rebuild drain state)
show subscribers Alias of show qos bindings
show drops [<interface>] Fast-path forward + drop counters
show statistics [<interface>] Alias for show drops
show license [detail\|usage\|server] License state / caps / expiry
show history Recent state-changing commands with provenance: time, user, source-IP (the client device, local for an on-box CLI), channel (cli/gui/rest), command
show users Local operator accounts
show user-sessions Active operator logins
show audit log [<n>] Config-change audit trail (who/what/when/source/result)
show audit session <sid> Audit records for one operator session
show audit user <name> Audit records for one operator
show auth log [<n>] Auth events (login / logout / denied / timeout / user-mgmt)
show pending Uncommitted candidate changes
show running Applied configuration
show candidate Running + candidate overlay

14.1 Operational actions

These act on live state immediately, without the candidate/commit transaction:

clear counters firewall|firewall6|nat [<n>]   reset per-rule / per-pool traffic counters
clear log                                      empty the in-memory diagnostic log buffer
clear session ip <a.b.c.d>                     disconnect a subscriber by framed IPv4
clear session user <name>                      disconnect by username (PPPoE user / IPoE MAC)
clear session acct-session-id <id>             disconnect by Acct-Session-Id (PPPoE only)
clear session interface <name>                 disconnect every session on an access interface
clear session all                              disconnect every subscriber session (confirms first)

clear session tears down live subscriber session(s) and reuses the RADIUS Disconnect-Message path (Acct-Stop, session removal, IP/NAT release). Single selectors (user / ip / acct-session-id) are synchronous; all and interface tear down in bounded batches and return immediately — watch progress with show sessions. clear session all prompts for confirmation before it runs.

14.2 Diagnostics

ping <dst> [source <ip>] [count <n>] [interval <ms>] [size <bytes>] [ttl <n>] [timeout <ms>] [df] [fast]
traceroute <dst> [source <ip>] [max-hops <n>] [queries <n>] [timeout <ms>] [size <bytes>]

Both run straight from the user-view prompt. The source address is auto-selected by route (the egress interface's address) unless source overrides it. df sets the don't- fragment bit; fast uses a 100 ms ping interval and blocks until done.


15. Configuration Examples

Each example is a copy-pasteable sequence ending in commit (and save where the change should survive a reboot). Run them from system-view unless noted.

15.1 A PPPoE service

Bring up PPPoE on two access interfaces with CHAP authentication, IPv6 enabled, and a RADIUS-less IPv6 fallback pool:

system-view
ppp interface add access0 access1
ppp mru 1492
ppp auth-protocol chap,pap
ppp lcp-echo interval 30 failure 3
ppp ipv6 enable
ppp ipv6 pool default
commit
save

15.2 An IPoE service

Serve IPoE/DHCP with MAC-based RADIUS identity on one access interface, with a fallback pool and DNS:

system-view
dhcp mode ipoe
dhcp interface add access2
dhcp auth mac
dhcp auth-password s3cr3t-mac-pw
dhcp mac-format colon
dhcp lease-time 3600
dhcp pool default
quit
ip dns 1.1.1.1 8.8.8.8
commit
save

15.3 A framed-IP pool

Define a pool and its gateway, then commit:

system-view
pool default range 100.64.10.10 100.64.10.250 gateway 100.64.10.1 prefix 24
quit
commit
save

15.4 CGNAT

Enable CGNAT with a public pool, a policy that translates the private range, and the default fragment-cache mode. The public pool loads on the next restart:

system-view
nat enable
nat conntrack-max 2097152
nat udp-mapping endpoint-independent
nat pool add pub1 203.0.113.10-203.0.113.20 ports 1024-65535 block 512 deterministic
nat policy add nat-rule 100.64.0.0/10 pool pub1
cgnat fragments mode cache
commit
save

15.5 A QoS plan

Create a queue profile, a 100M residential subscriber profile, and bind it to a pool prefix. Because references resolve against the running config, commit the profiles before the assignment:

system-view
qos queue-profile add res-fq fq_codel qsize 4096 target 5ms interval 100ms ecn on
qos subscriber-profile add res-100 rate-down 100M rate-up 100M queue-profile res-fq
commit
qos assign add 100.64.10.0/24 subscriber-profile res-100
commit
save

15.6 A firewall rule

Enable the stateful firewall with uRPF anti-spoof, permit established traffic, and drop new inbound Telnet. Everything applies live on commit:

system-view
firewall enable
firewall urpf strict
firewall filter add accept state established
firewall filter add drop proto tcp dport 23 state new
commit
save

16. Best Practices

  • Use commit confirmed for risky changes. Any edit that could cut off your own management path — routing, default gateway, firewall enable/uRPF — should be applied with commit confirmed [<minutes>]. If you lose access, the box auto-reverts; if the change is good, run confirm.

  • Commit at the editing boundary, save at the box boundary. commit is what applies your candidate to running; save is what makes running survive a reboot. Commit when you finish editing a change, and save once you have verified it behaves. A committed- but-unsaved change is live but will be lost on reboot.

  • Verify before you save. After commit, confirm the change with the relevant show command (show sessions, show nat statistics, show qos bindings, show ip route) before running save.

  • Mind apply timing. Changes that apply on restart — reshaping an in-use nat pool's IP/port range, ipv6 pool reshapes, bonding/trunks, and the system CPU-plan knobs — will not affect live traffic on commit alone. Schedule the restart. (nat pool add/remove and block-size changes apply live for new sessions, and a nat policy rule can reference a pool committed in the same session.)

  • Commit referenced objects first. QoS and other references resolve against the running config. Commit a queue profile before a subscriber profile that names it, and a subscriber profile before an assignment that binds it.

  • Commit, don't restart, for QoS tuning. For in-place queue-profile changes (qsize, AQM, discipline tuning), commit applies them live (then save) — new sessions bind immediately and existing sessions migrate gradually with no forwarding interruption. Reserve restarts for structural QoS changes.

  • Roll back cleanly. If a candidate is wrong before you commit, rollback discards it entirely. There is no need to hand-undo staged edits.

  • Establish a diagnostic baseline. Before chasing an intermittent problem (a one-way UDP freeze, packet loss), run clear counters nat / clear counters firewall, let traffic run, then read the counters — a moving counter after a known start point is far easier to interpret than a lifetime total.

  • Keep uRPF scoped correctly. IPv4 urpf strict is safe once subscriber routes are in the RIB. IPv6 urpf6 defaults OFF and should stay off until subscriber v6 reverse- routes are installed, or it will drop legitimate static v6 hosts.


17. show interface detail

The interface commands form a small hierarchy, in the style of IOS / JunOS / VRP:

show interface                one line per physical port (the summary table)
show interface <name>         the full operational page for one port
show interface stats          live per-port NIC counters (rx/tx/err/drop table)

17.1 Summary

show interface
Interface  Admin Oper Speed  Type   Description
---------------------------------------------------------
ether1     up    up   10G    SFP+   Uplink-Core
ether2     up    up   10G    DAC    BNG-Blaster
ether3     up    up   100M   RJ45   Management

Type is EEPROM-backed when a module answers (SFP+, SFP, DAC, AOC) and falls back to a driver-family guess for copper ports. Admin reflects an operator interface <name> shutdown; Oper is the live PMD link state.

17.2 Per-interface page — show interface <name>

One command returns the complete health picture of a port, so an operator never has to stitch several commands together:

  • General — description, admin/oper state, port id, driver, PCI address, NUMA node, MAC, MTU, speed, duplex, autoneg, flow-control, media, any bound IPv4 address.
  • DPDK — rx/tx queue counts, descriptor ring sizes, socket, RSS, promiscuous and all-multicast state.
  • Total Counters — rx/tx packets + bytes, rx/tx errors, ring-missed and no-mbuf drops (the ethdev basic stats).
  • RX / TX Statistics (hardware) — curated per-PMD xstats (CRC, length, undersize/oversize, fragment, jabber, pause, broadcast/multicast). A counter the PMD does not provide shows -; any remaining non-zero hardware counter is listed under Other Non-Zero Hardware Counters so nothing is hidden.
  • Transceiver — for an SFP/SFP+ optic: module type, vendor + OUI, part number, serial, revision, date code, connector, wavelength, reach; then live DDM (temperature, voltage, TX bias, TX/RX optical power in dBm) with active alarm flags, followed by the full alarm/warning threshold table. A DAC is identified as Passive/Active DAC with vendor + length; a copper port shows no module.

The module EEPROM identity + thresholds are cached per port (1 h, warmed at boot) because the NIC reads them over slow I2C; only the small live-DDM block is read on each call, so the page returns in milliseconds. This makes the command a first-line optical-link diagnostic — a weak or dirty fibre shows immediately as a low RX-power reading and an rxpwr-low alarm, without leaving the CLI.

Reserved sections (traffic rates, link-since / last-up-down, QoS, LLDP, LACP) are stubbed in the layout and populate in later releases.

Appendix B — Commands that apply only on a daemon restart

Almost every command applies live on commit. The exceptions below change state that is fixed when the daemon boots (lcore layout, port RSS hash, CGNAT pool/port-block allocation, rte_sched disciplines), so they take effect only after a restart. For all of them: commit records the change and save persists it to the .conf; the running data path does not change until you restart.

CPU / lcore plan — re-plans the worker layout at boot:

system control-cores <n>
system control-cores <isolate|shadow>      (ht-policy)
system undo control-cores
system undo max-workers-per-10g
system undo ht-policy

CGNAT conntrack allocation & in-use pool reshapes — the flow table is allocated at init; nat pool add/remove and block-size changes apply live for NEW sessions, but reshaping the IP/port range of a pool that still holds live blocks waits for restart. (nat conntrack-max is NOT here — it is the live admission ceiling and applies on commit. Only the allocation needs a restart.)

nat conntrack-capacity <count>     (and: nat undo conntrack-capacity)
pool <name> range <start-ip> <end-ip> gateway <gw-ip> [prefix <len>]
pool <name> next <successor-pool>  (and: pool <name> undo next)
pool <name> remove

QoS queue profiles — the rte_sched discipline/qsize/AQM is built into the subports at boot. NOTE: a committed queue-profile edit rebuilds the scheduler live (a new generation, no restart), so no restart is needed:

qos queue-profile add|insert <N> <name> <pfifo|tb|fq_codel|fq_pie|cake> [tuning...]
qos queue-profile <name> <key> <val> [...]      (merge-edit by name)
qos queue-profile modify <N|name> ...           (keys merge | disc redefines | full row)
qos queue-profile delete <N|name>
qos queue-profile move <N|name> <M>

Fragment RSS co-location — the port RSS hash is set at port configure:

cgnat fragments rss <enable|disable>

Everything not listed here applies live on commit (interface/IP/route, PPPoE/IPoE, DHCP, firewall, nat policy/rule/snat/dstnat/timeouts/udp-mapping, RADIUS, qos subscriber-profiles/assignments/service, ARP, power, dispatch, logging, IPDR). show, debug, clear, ping, traceroute and account/session actions run immediately (no commit).

Appendix A — Complete Command Index

Every command in the grammar (generated from cli/cli_tree.c). Markers: = takes effect only after a daemon restart (Appendix B); = hidden (executable if typed in full, but never offered by ?/TAB — superadmin/advanced). Everything else applies live on commit (or immediately, for show/debug/actions). <...> = a value you supply.

Rule bodies (firewall filter [6] add|insert … <action>, nat dstnat add|insert … <rule>) are shown as the action/base only. firewall filter match keywords chain proto → dport → state (src-list/dst-list standalone); nat dstnat <rule> = <public-ip> [proto tcp|udp|any] [dport <n>] to <inside-ip> [to-port <n>] [disable] — both are TAB-completable step by step (see §8, §9.2).

show

  show aaa
  show api
  show arp
  show arp cache
  show arp config
  show audit log
  show audit log <n>
  show audit session <sid>
  show audit user <user>
  show auth log
  show auth log <n>
  show candidate
  show cgnat fragments
  show debug packets
  show debug trace
  show dhcp
  show dhcpv6
  show drops
  show drops <interface>
  show firewall
  show firewall address-list
  show firewall address-list <name>
  show firewall drops
  show firewall6
  show firewall6 drops
  show health
  show history
  show interface
  show interface <name>
  show interface bonding
  show interface statistics
  show interface stats
  show interface vlan
  show interface vlan statistics
  show interface vlan stats
  show interfaces
  show ip address
  show ip address <interface>
  show ip dns
  show ip fib
  show ip nexthop
  show ip route
  show ip route detail
  show ipdr
  show ipv6 address
  show ipv6 address <interface>
  show ipv6 dns
  show ipv6 fib
  show ipv6 neighbor
  show ipv6 nexthop
  show ipv6 pool
  show ipv6 route
  show ipv6 route detail
  show license
  show license detail
  show license server
  show license usage
  show log
  show log <module>
  show log <module> last <n>
  show log last <n>
  show logging
  show mempool
  show nat
  show nat block <ip>
  show nat blocks
  show nat dstnat
  show nat flow
  show nat flow <ip>
  show nat fragments
  show nat session
  show nat session <ip>
  show nat statistics
  show nat statistics detail
  show nexthops
  show pending
  show pool
  show power
  show ppp
  show qos
  show qos bindings
  show qos generations
  show qos sub <sub-id>
  show radius
  show radius statistics
  show running
  show sessions
  show statistics
  show statistics <interface>
  show system
  show topology
  show user-sessions
  show users
  show version
  show vlan
  show vlan statistics
  show vlan stats

interface

  interface <name> add trunk <name>
  interface <name> add vlan <name> <svlan>
  interface <name> add vlan <name> <svlan> <cvlan>
  interface <name> del trunk <name>
  interface <name> del vlan <name>
  interface <name> description <text>
  interface <name> mtu <n>
  interface <name> no shutdown
  interface <name> shutdown
  interface add trunk <name>
  interface add trunk <name> mode 8023ad
  interface add trunk <name> mode active-backup
  interface add trunk <name> mode balance-xor
  interface del trunk <name>
  interface identify <name>
  interface identify <name> duration <s>
  interface identify stop <name>

ip

  ip address add <interface> <a.b.c.d/p>
  ip address add <interface> <a.b.c.d/p> secondary
  ip address remove <interface> <a.b.c.d/p>
  ip dns <primary>
  ip dns <primary> <secondary>
  ip dns none
  ip route add <cidr> <gateway-ip>
  ip route add <cidr> <gateway-ip> distance <distance>
  ip route add <cidr> <gateway-ip> distance <distance> metric <metric>
  ip route add <cidr> <gateway-ip> distance <distance> metric <metric> weight <weight>
  ip route add <cidr> <gateway-ip> distance <distance> weight <weight>
  ip route add <cidr> <gateway-ip> metric <metric>
  ip route add <cidr> <gateway-ip> metric <metric> weight <weight>
  ip route add <cidr> <gateway-ip> weight <weight>
  ip route add <cidr> gateway <ip>
  ip route add <cidr> gateway <ip> distance <distance>
  ip route add <cidr> gateway <ip> distance <distance> metric <metric>
  ip route add <cidr> gateway <ip> distance <distance> metric <metric> weight <weight>
  ip route add <cidr> gateway <ip> distance <distance> weight <weight>
  ip route add <cidr> gateway <ip> interface <name>
  ip route add <cidr> gateway <ip> interface <name> distance <distance>
  ip route add <cidr> gateway <ip> interface <name> distance <distance> metric <metric>
  ip route add <cidr> gateway <ip> interface <name> distance <distance> metric <metric> weight <weight>
  ip route add <cidr> gateway <ip> interface <name> distance <distance> weight <weight>
  ip route add <cidr> gateway <ip> interface <name> metric <metric>
  ip route add <cidr> gateway <ip> interface <name> metric <metric> weight <weight>
  ip route add <cidr> gateway <ip> interface <name> weight <weight>
  ip route add <cidr> gateway <ip> metric <metric>
  ip route add <cidr> gateway <ip> metric <metric> weight <weight>
  ip route add <cidr> gateway <ip> weight <weight>
  ip route add <cidr> interface <name>
  ip route add <cidr> interface <name> distance <distance>
  ip route add <cidr> interface <name> distance <distance> metric <metric>
  ip route add <cidr> interface <name> distance <distance> metric <metric> weight <weight>
  ip route add <cidr> interface <name> distance <distance> weight <weight>
  ip route add <cidr> interface <name> metric <metric>
  ip route add <cidr> interface <name> metric <metric> weight <weight>
  ip route add <cidr> interface <name> weight <weight>
  ip route delete <cidr>
  ip route delete <cidr> gateway <ip>

ipv6

  ipv6 address add <interface> <addr/plen>
  ipv6 address add <interface> <addr/plen> secondary
  ipv6 address remove <interface> <addr/plen>
  ipv6 dns <primary>
  ipv6 dns <primary> <secondary>
  ipv6 dns none
  ipv6 pool <name> <base>/<plen> assign <assign-plen>
  ipv6 pool <name> remove
  ipv6 route add <cidr> <gateway-ip>
  ipv6 route add <cidr> <gateway-ip> distance <distance>
  ipv6 route add <cidr> <gateway-ip> distance <distance> metric <metric>
  ipv6 route add <cidr> <gateway-ip> distance <distance> metric <metric> weight <weight>
  ipv6 route add <cidr> <gateway-ip> distance <distance> weight <weight>
  ipv6 route add <cidr> <gateway-ip> metric <metric>
  ipv6 route add <cidr> <gateway-ip> metric <metric> weight <weight>
  ipv6 route add <cidr> <gateway-ip> weight <weight>
  ipv6 route add <cidr> gateway <ip>
  ipv6 route add <cidr> gateway <ip> distance <distance>
  ipv6 route add <cidr> gateway <ip> distance <distance> metric <metric>
  ipv6 route add <cidr> gateway <ip> distance <distance> metric <metric> weight <weight>
  ipv6 route add <cidr> gateway <ip> distance <distance> weight <weight>
  ipv6 route add <cidr> gateway <ip> interface <name>
  ipv6 route add <cidr> gateway <ip> interface <name> distance <distance>
  ipv6 route add <cidr> gateway <ip> interface <name> distance <distance> metric <metric>
  ipv6 route add <cidr> gateway <ip> interface <name> distance <distance> metric <metric> weight <weight>
  ipv6 route add <cidr> gateway <ip> interface <name> distance <distance> weight <weight>
  ipv6 route add <cidr> gateway <ip> interface <name> metric <metric>
  ipv6 route add <cidr> gateway <ip> interface <name> metric <metric> weight <weight>
  ipv6 route add <cidr> gateway <ip> interface <name> weight <weight>
  ipv6 route add <cidr> gateway <ip> metric <metric>
  ipv6 route add <cidr> gateway <ip> metric <metric> weight <weight>
  ipv6 route add <cidr> gateway <ip> weight <weight>
  ipv6 route add <cidr> interface <name>
  ipv6 route add <cidr> interface <name> distance <distance>
  ipv6 route add <cidr> interface <name> distance <distance> metric <metric>
  ipv6 route add <cidr> interface <name> distance <distance> metric <metric> weight <weight>
  ipv6 route add <cidr> interface <name> distance <distance> weight <weight>
  ipv6 route add <cidr> interface <name> metric <metric>
  ipv6 route add <cidr> interface <name> metric <metric> weight <weight>
  ipv6 route add <cidr> interface <name> weight <weight>
  ipv6 route delete <cidr>
  ipv6 route delete <cidr> gateway <ip>

routing

  routing
  routing recursive-via-default disable
  routing recursive-via-default enable

ppp

  ppp auth-protocol <methods>
  ppp interface add <name>
  ppp interface remove <name>
  ppp ipv6 disable
  ppp ipv6 enable
  ppp ipv6 pd-pool <name>
  ppp ipv6 pool <name>
  ppp lcp-echo interval <secs>
  ppp lcp-echo interval <secs> failure <count>
  ppp mru <bytes>
  ppp pool <name>
  ppp session-timeout <secs>
  ppp setup-timeout <secs>
  ppp undo auth-protocol
  ppp undo ipv6
  ppp undo ipv6-pd-pool
  ppp undo ipv6-pool
  ppp undo lcp-echo
  ppp undo mru
  ppp undo pool
  ppp undo session-timeout
  ppp undo setup-timeout

dhcp

  dhcp auth ip
  dhcp auth mac
  dhcp auth none
  dhcp auth option82
  dhcp auth-password <secret>
  dhcp interface add <name>
  dhcp interface remove <name>
  dhcp lease-time <secs>
  dhcp mac-format bare
  dhcp mac-format colon
  dhcp mac-format hyphen
  dhcp mode both
  dhcp mode dhcp
  dhcp mode ipoe
  dhcp mode off
  dhcp pool <name>
  dhcp undo auth
  dhcp undo lease-time
  dhcp undo mac-format
  dhcp undo mode
  dhcp undo pool

dhcpv6

  dhcpv6 mode off
  dhcpv6 mode on
  dhcpv6 mode pd
  dhcpv6 pd-pool <name>
  dhcpv6 pool <name>
  dhcpv6 preferred-lifetime <secs>
  dhcpv6 t1 <secs>
  dhcpv6 t2 <secs>
  dhcpv6 undo mode
  dhcpv6 undo pd-pool
  dhcpv6 undo pool
  dhcpv6 undo preferred-lifetime
  dhcpv6 undo t1
  dhcpv6 undo t2
  dhcpv6 undo valid-lifetime
  dhcpv6 valid-lifetime <secs>

arp

  arp interval <secs>
  arp retry <count>
  arp undo interval
  arp undo retry

pool

⟳ pool <name> next <successor-pool>
⟳ pool <name> range <start-ip> <end-ip> gateway <gw-ip>
⟳ pool <name> range <start-ip> <end-ip> gateway <gw-ip> prefix <len>
⟳ pool <name> remove
⟳ pool <name> undo next

firewall

  firewall address-list add <name> <ip|cidr>
  firewall address-list add <name> <ip|cidr> timeout <secs>
  firewall address-list remove <name> <ip|cidr>
  firewall address-list remove <name> <ip|cidr> timeout <secs>
  firewall disable
  firewall disable6
  firewall enable
  firewall enable6
  firewall filter add accept
  firewall filter add drop
  firewall filter add reject
  firewall filter delete <N>
  firewall filter insert <N> accept
  firewall filter insert <N> drop
  firewall filter insert <N> reject
  firewall filter move <N> <M>
  firewall filter6 add accept
  firewall filter6 add drop
  firewall filter6 add reject
  firewall filter6 delete <N>
  firewall filter6 insert <N> accept
  firewall filter6 insert <N> drop
  firewall filter6 insert <N> reject
  firewall filter6 move <N> <M>
  firewall mangle add <rule>
  firewall mangle delete <N>
  firewall mangle insert <N> <rule>
  firewall mangle move <N> <M>
  firewall undo enable
  firewall urpf disable
  firewall urpf strict
  firewall urpf6 disable
  firewall urpf6 strict

nat

⟳ nat conntrack-capacity <count>
  nat conntrack-max <count>
  nat disable
  nat dstnat add <rule>
  nat dstnat delete <N>
  nat dstnat insert <N> <rule>
  nat dstnat move <N> <M>
  nat enable
  nat policy add nat-rule <cidr> bypass
  nat policy add nat-rule <cidr> pool <name>
  nat policy add snat <cidr> to <target>
  nat policy delete <N>
  nat policy insert <N> nat-rule <cidr> bypass
  nat policy insert <N> nat-rule <cidr> pool <name>
  nat policy insert <N> snat <cidr> to <target>
  nat policy move <N> <M>
⟳ nat pool add <name> <ip-lo-hi> ports <lo-hi> block <size> deterministic
⟳ nat pool add <name> <ip-lo-hi> ports <lo-hi> block <size> dynamic
⟳ nat pool remove <name>
  nat rule <cidr> bypass
  nat rule <cidr> pool <name>
  nat snat <cidr> to <target>
  nat timeout icmp <seconds>
  nat timeout tcp-close <seconds>
  nat timeout tcp-closing <seconds>
  nat timeout tcp-established <seconds>
  nat timeout tcp-syn <seconds>
  nat timeout udp <seconds>
  nat timeout udp-eim-reserve <seconds>
  nat timeout udp-stream <seconds>
  nat udp-mapping endpoint-independent
  nat udp-mapping symmetric
⟳ nat undo conntrack-max
  nat undo enable
  nat undo timeout icmp
  nat undo timeout tcp-close
  nat undo timeout tcp-closing
  nat undo timeout tcp-established
  nat undo timeout tcp-syn
  nat undo timeout udp
  nat undo timeout udp-eim-reserve
  nat undo timeout udp-stream
  nat undo udp-mapping

cgnat

  cgnat fragments mode cache
  cgnat fragments mode drop
  cgnat fragments mode reassembly
⟳ cgnat fragments rss disable
⟳ cgnat fragments rss enable
  cgnat fragments timeout <seconds>

qos

  qos assign add <cidr> subscriber-profile <name>
  qos assign delete <N|cidr>
  qos assign insert <N> <cidr> subscriber-profile <name>
  qos assign move <N|cidr> <M>
⟳ qos queue-profile add <name> cake
⟳ qos queue-profile add <name> fq_codel
⟳ qos queue-profile add <name> fq_pie
⟳ qos queue-profile add <name> pfifo
⟳ qos queue-profile add <name> tb
  qos queue-profile <name> <key> <val> [...]        (merge-edit by name)
  qos queue-profile <name> <disc> [tuning...]       (redefine by name)
⟳ qos queue-profile delete <N|name>
⟳ qos queue-profile insert <N> <name> <disc> [tuning...]
  qos queue-profile modify <N|name> <key> <val> [...]
  qos queue-profile modify <N|name> <disc> [tuning...]
  qos queue-profile modify <N|name> <name> <disc> [tuning...]
⟳ qos queue-profile move <N|name> <M>
  qos max-pipes <n>
  qos overhead-compensation <pct>
  qos service ipoe <queue-profile>
  qos service ppp <queue-profile>
  qos subscriber-profile add <name> rate-down <r> rate-up <r>
  qos subscriber-profile add <name> rate-down <r> rate-up <r> queue-profile
  qos subscriber-profile add <name> rate-down <r> rate-up <r> queue-profile <qp>
  qos subscriber-profile add <name> rate-down <r> rate-up <r> queue-profile <qp> priority
  qos subscriber-profile add <name> rate-down <r> rate-up <r> queue-profile <qp> priority <1-8>
  qos subscriber-profile <name> <key> <val> [...]   (merge-edit by name: rate-down/rate-up/queue-profile/priority)
  qos subscriber-profile modify <N|name> <key> <val> [...]
  qos subscriber-profile delete <N|name>
  qos subscriber-profile insert <N> <name> rate-down <r> rate-up <r>
  qos subscriber-profile insert <N> <name> rate-down <r> rate-up <r> queue-profile
  qos subscriber-profile insert <N> <name> rate-down <r> rate-up <r> queue-profile <qp>
  qos subscriber-profile insert <N> <name> rate-down <r> rate-up <r> queue-profile <qp> priority
  qos subscriber-profile insert <N> <name> rate-down <r> rate-up <r> queue-profile <qp> priority <1-8>
  qos subscriber-profile move <N|name> <M>

radius

  radius coa-port <port>
  radius dict-path <path>
  radius interim-interval <secs>
  radius message-authenticator off
  radius message-authenticator on
  radius message-authenticator require
  radius nas-id <id>
  radius nas-ip <ip>
  radius retries <n>
  radius server add <host> secret <secret>
  radius server add <host> secret <secret> auth-port <port>
  radius server add <host> secret <secret> auth-port <port> acct-port <port>
  radius server delete <N>
  radius server insert <N> <host> secret <secret>
  radius server insert <N> <host> secret <secret> auth-port <port>
  radius server insert <N> <host> secret <secret> auth-port <port> acct-port <port>
  radius server move <N> <M>
  radius timeout <secs>
  radius undo coa-port
  radius undo dict-path
  radius undo interim-interval
  radius undo message-authenticator
  radius undo nas-id
  radius undo nas-ip
  radius undo retries
  radius undo timeout

system

⟳ system control-cores <n>
  system ht-policy isolate
  system ht-policy shadow
  system ipdr disable
  system ipdr enable
  system ipdr file <path>
  system ipdr flow dir <dir>
  system ipdr flow disable
  system ipdr flow disk disable
  system ipdr flow disk enable
  system ipdr flow enable
  system ipdr flow prefix <tag>
  system ipdr flow remote <host:port>
  system ipdr flow skip-dns
  system logging level critical
  system logging level debug
  system logging level error
  system logging level info
  system logging level notice
  system logging level off
  system logging level warning
  system logging output file <path>
  system logging output memory
  system logging output stderr
  system logging output stdout
  system max-workers-per-10g <n>
⟳ system undo control-cores
⟳ system undo ht-policy
  system undo ipdr enable
  system undo ipdr file
  system undo ipdr flow
  system undo ipdr flow dir
  system undo ipdr flow prefix
  system undo ipdr flow remote
  system undo ipdr flow skip-dns
  system undo logging level
  system undo logging output
⟳ system undo max-workers-per-10g

system dispatch

  dispatch
  system dispatch disable
  system dispatch enable

system power

  power
  system power adaptive disable
  system power adaptive enable
  system power nap <us>

license

⊘ license activate <key>
⊘ license install <file>
⊘ license reload
  license request
  license request export <file>

service api

  service api allow <cidr>
  service api disable
  service api enable
  service api listen <host:port>
  service api no allow <cidr>

service telnet

  service telnet allow <cidr>
  service telnet deny <cidr>
  service telnet disable
  service telnet enable
  service telnet listen <ip:port | port | ip>
  service telnet max-sessions <n>
  service telnet no allow <cidr>
  service telnet no deny <cidr>

aaa

  aaa disable
  aaa enable

log

  log level <module> <level>
  log level all <level>

system user

  system user add <name> full <password>
  system user add <name> full <password> <description>
  system user add <name> read <password>
  system user add <name> read <password> <description>
  system user add <name> write <password>
  system user add <name> write <password> <description>
  system user change <name> <new-password>
  system user delete <name>

disconnect

  disconnect user-session <id>

clear

  clear counters firewall
  clear counters firewall <number>
  clear counters firewall6
  clear counters firewall6 <number>
  clear counters nat
  clear counters nat <number>
  clear debug
  clear debug packets
  clear log
  clear session acct-session-id <id>
  clear session all
  clear session interface <name>
  clear session ip <a.b.c.d>
  clear session user <name>

debug

  debug trace packet drops
  debug trace packet drops for <seconds>
  debug trace packet dst <ip>
  debug trace packet dst <ip> drops
  debug trace packet dst <ip> drops for <seconds>
  debug trace packet dst <ip> for <seconds>
  debug trace packet ip <ip>
  debug trace packet ip <ip> drops
  debug trace packet ip <ip> drops for <seconds>
  debug trace packet ip <ip> for <seconds>
  debug trace packet off
  debug trace packet src <ip>
  debug trace packet src <ip> drops
  debug trace packet src <ip> drops for <seconds>
  debug trace packet src <ip> dst <ip>
  debug trace packet src <ip> dst <ip> drops
  debug trace packet src <ip> dst <ip> drops for <seconds>
  debug trace packet src <ip> dst <ip> for <seconds>
  debug trace packet src <ip> for <seconds>

ping

  ping <dst-ip>

traceroute

  traceroute <dst-ip>

commit

  commit
  commit confirmed
  commit confirmed <minutes>

confirm

  confirm

rollback

  rollback

save

  save

load

  load

display

  display current-configuration

whoami

  whoami

Related documentation: README · CLI Guide · Vendor API · Internal docs