Access NNIs and guest sessions#
An access NNI is a wholesale hand-off: one subscriber port and one outer VLAN (S-VLAN) on which an access network delivers many circuits, each on its own inner VLAN (C-VLAN). Declaring one lets the appliance identify a subscriber by where it is — the NNI and the C-VLAN — instead of by a username, a port number, or DHCP Option 82.
It is for the access network where:
- your provisioning system knows a line by its hand-off and VLAN, and should not have to know which appliance or port it lands on;
- circuits come up before anyone has entered them, and you want them to work anyway;
- customers' routers still present credentials from a previous provider.
This applies to the database auth driver, with subscribers read from a SQL view
(auth database connection-string). RADIUS deployments identify IPoE circuits through RADIUS as
before.
Declaring an access NNI#
Give the NNI the key your provisioning system uses for it, and say where it arrives:
set subscribers access-nni ms3-lon-1-a interface eno1
set subscribers access-nni ms3-lon-1-a s-vlan 200
commit
| Setting | |
|---|---|
| name | The key, exactly as the subscriber view publishes it: lowercase letters, digits and hyphens, at most 32 characters. |
interface |
A subscriber interface, by name or PCI address. |
port |
The data-plane port index, instead of interface, where interfaces are not named. |
s-vlan |
The outer VLAN, 1–4094. |
Every C-VLAN under that S-VLAN on that port belongs to the NNI. Two NNIs cannot claim the same port and S-VLAN. The change takes effect on commit; no restart.
An appliance uses the view's circuit rows only for NNIs it has declared. Rows for other NNIs
are ignored for circuit matching, and show subscribers source says how many.
What the subscriber view provides#
Five optional columns alongside the existing ones:
| Column | |
|---|---|
Nni |
The access NNI key. |
CVlan |
The circuit's inner VLAN. |
CircuitDefault |
1 on the NNI's default row: "accept circuits you have no line for". |
Realm |
A realm row, for PPPoE relay by realm (see below). |
SubscriberReference |
The reference the row's line is known by, e.g. FTTP152238. Text, up to 128 characters; empty on a default row and a realm row. |
How a subscriber is named#
A line with no PPP login has a system-made username such as
circuit:FTTP152238@ms3-lon-1-a.141. Where the view also gives the line's
SubscriberReference, the appliance shows that reference as the subscriber instead — in
show subscribers sessions, the sessions page and the mobile app — and you can search the
sessions list by it. A subscriber with a real PPP username is always shown by that username.
The session's detail shows both, as Subscriber reference and Username; the username is
still what identifies the session, and accounting records still carry it. Session events
(SESSION_UP, SESSION_DOWN, SESSION_ADOPTED) carry the reference as subscriber=.
To disconnect a subscriber by what the list shows, use
request subscribers disconnect reference <reference>. If more than one session has that
reference it lists them and does nothing; add all to disconnect them all, or disconnect one by
id. request subscribers disconnect username <username> takes a session's real username — the
one under Username in its detail — and never a reference.
A guest has no reference until a line adopts it. Subscribers authenticated by RADIUS have none.
A line on the NNI is one row with Nni and CVlan, its VRF, and usually address pools rather
than static addresses. If the line also has PPP credentials, the same row carries its username and
password. Adding circuit columns to a row never changes how its username logs in.
How a circuit is identified#
For IPoE (DHCP), in this order:
- DHCP Option 82, if a subscriber is configured by circuit-id.
- A subscriber configured on this appliance for the exact port and VLANs.
- The view's row for the NNI and C-VLAN: the line.
- The NNI's default row: a guest.
- Otherwise the walled garden, as for any unknown circuit.
A line whose status is disabled is refused. It is not served as a guest instead.
Guest sessions#
A circuit admitted by the default row is a guest. A guest:
- gets full service in the default row's VRF, from the default row's address pools — it is not in the walled garden;
- is named after its circuit:
guest-<nni>.<c-vlan>, for exampleguest-ms3-lon-1-a.138(a label, not something to parse: an NNI key may itself contain hyphens); - has no accounting subject, so nothing is accounted for it (
show accountingcounts these under guest sessions); - is marked unclaimed, and stays so across a restart.
Guests are listed on the appliance — your provisioning system has no line to show them under:
No unclaimed sessions.
The list shows each guest's NNI, VLANs, access type, MAC, addresses, uptime and traffic — what you
need to work out whose circuit it is. In the web UI the Unclaimed tile on the Sessions page
shows the same list; over the API it is GET /api/v1/sessions?unclaimed=true. The count is
bngUnclaimedSessionCount over SNMP and netavo_bng_sessions_unclaimed for Prometheus.
Adoption#
When a line appears in the view for a guest's circuit, the appliance turns the live session into
that line without disconnecting it. This happens after a refresh of the view
(auth database cache-refresh-interval, 300 seconds by default): the appliance only knows about
the line once a refresh has loaded its row, so a new line takes effect within one interval.
A DHCP renewal does not make it happen sooner. A renewal is answered from the rows the last refresh loaded; it adopts the session only in the short time between a refresh loading the row and the same refresh reaching that session.
cache-refresh-interval is read when the control plane starts; the commit that changes it says
so.
The session keeps its addresses, its NAT mapping and its uptime. It takes the line's name, plan and rates, and accounting starts for the line from that moment: an accounting Start is sent, carrying the session's original start time. Traffic the circuit passed as a guest is not charged to the line. The session's throughput graph carries on unbroken.
A guest is disconnected instead, so that the router reconnects as the line, when the line could not have been given the session it already has:
- the line is in a different VRF;
- the line has a static address or prefix that the session does not hold;
- the line draws from a different address pool;
- the line is relayed to another LNS.
A guest is also disconnected when its circuit's line is disabled or suspended, or when the NNI
stops accepting unknown circuits (its default row is removed). A blocked line is adopted and
then blocked, exactly as a new login would be.
At most 200 guests are adopted or disconnected per refresh; the rest follow at the next. Each
adoption is logged as SESSION_ADOPTED.
Keeping sessions in step with the view#
After every refresh the appliance checks each session that was identified by its circuit against what the view says about that circuit now:
| The circuit now has | The session |
|---|---|
| the same line | gets the line's current status and rates; a disabled line is disconnected |
| a different line | is disconnected, and comes back as the new line |
| no line, and the NNI accepts unknown circuits | DHCP: restarted as a guest at its next renewal. PPPoE: disconnected, and redials as a guest |
| no line, and the NNI does not accept unknown circuits | is disconnected |
The line is identified by its ServiceId. Renaming a line does not disturb its session.
Removing an NNI or its rows ends its sessions
If you delete an access NNI from the configuration, or the view stops publishing an NNI's rows, the sessions on that NNI are disconnected at the next refresh. A refresh that fails (the database cannot be read) changes nothing.
If two rows claim the same NNI and C-VLAN, the more restrictive one applies — a disabled row wins
over an active one — and show subscribers source reports the conflict. Usernames in the view
do not have to be unique for circuits to be matched correctly, but a duplicated username can only
log in as one of its rows, and the appliance warns about it.
When rows disappear#
Removing a line's row, giving its circuit to another line, removing an NNI's default row or undeclaring an NNI all take a live session's authority away. The appliance does not act on that the first time it sees it, because a subscriber view can be briefly empty or incomplete and still load successfully.
- Two refreshes must agree. A session is ended for a missing or replaced row only when two
successful refreshes in a row say the same thing. With the default interval that is one extra
interval before a removal takes effect. A DHCP renewal in between is answered normally and the
customer keeps their address. Disabling a line in its own row (
Status = disabled), and blocking, suspending or re-rating it, still take effect at the next refresh. - At most a tenth of an NNI per refresh. One refresh ends at most 50 sessions on an NNI for
a missing or replaced row, or 10 % of its sessions if that is more. The rest follow at later
refreshes. Lines whose own row says
disabledare not counted: they are disconnected at once — unless so many rows turned at once that the whole view is doubted (next point). - An empty or much smaller view is not applied at all. See the subscriber source.
- An unreadable row protects its circuit. If the view has a row for a circuit but the row is malformed, the session on that circuit is left as it is until the row can be read.
These alarms tell you when this is happening. The first two carry the NNI as their instance; all clear by themselves:
| Alarm | Severity | Raised when | What to do |
|---|---|---|---|
subscribers.nni_rows_lost |
major | the view has no rows for an access NNI that has live sessions, or the NNI is no longer declared | Check the view and the NNI key (subscribers.accessNnis[].name must equal the view's Nni). Sessions start to end at the next refresh if nothing changes. |
subscribers.reconcile_limited |
major | a refresh ended as many sessions on an NNI as it is allowed to, and more are waiting | If the removal is intended, nothing: it completes over the next refreshes. If not, correct the view before the next refresh; sessions not yet ended are kept. |
subscribers.source_unavailable |
major | the subscriber view cannot be read | Check the database and the path to it. The last view loaded is still served; if none has loaded since the control plane started, only locally configured subscribers are known, new logins get no answer (not a reject) and live IPoE sessions are renewed from the session. The load is retried every few seconds (2 s doubling to 30 s before the first load, to 60 s after) and the alarm clears when one succeeds. |
subscribers.source_implausible |
major | the view was read and came back empty, or with most of its rows gone | Nothing has been applied and nobody is disconnected. Check the view; if it is right, request subscribers source accept. See the subscriber source. |
show subscribers source shows what the last refresh held back:
NNI rows lost: ms3-lon-1-a — live sessions, no rows in the source
Held: 412 awaiting a second refresh, 0 over the per-refresh limit, 3 with an unreadable row, 0 whose disconnect failed
Both lines appear only when there is something to report, including when the view has no circuit rows left at all. The counts of rows in use and rows ignored follow the configuration as soon as an access NNI is committed; they do not wait for the next refresh.
It also names circuits that two rows claim (Contested: ms3-lon-1-a:141), next to the count of
rows that lost; the same list is in the refresh's warning in the log.
PPPoE on an access NNI#
PPPoE and IPoE can share an NNI. For a PPPoE login terminated on the appliance:
- A username the appliance knows is authenticated as always.
- An unknown username on a circuit that has a line is accepted as that line. The password is not checked: the circuit is the identity.
- An unknown username on a circuit with no line, on an NNI with a default row, is a guest.
- Otherwise it is rejected.
So a migrated customer's router keeps working with its old provider's login. The username it presented is shown on the session (Presented as) next to the name the session runs under.
This works with CHAP and PAP. The appliance asks for CHAP first; a router that can only do PAP
refuses that and is then asked for PAP. Which protocols are allowed, and in what order, is
protocols pppoe auth-protocols (default chap,pap; chap alone refuses PAP-only routers). The
setting is read when the control plane starts.
A router that will agree to neither is disconnected after a few attempts (lcp-not-converging
in the session log) rather than left negotiating.
RADIUS authentication: NAS-Port and NAS-Port-Id have changed for PPPoE
An appliance that authenticates subscribers by RADIUS now sends the real access circuit of
every PPPoE login: NAS-Port is the subscriber port index and NAS-Port-Id is
phy<port>/vlan<s-vlan>.<c-vlan>. Earlier releases sent NAS-Port 0 and NAS-Port-Id
phy0/vlan0 for every PPPoE login. This applies to all PPPoE logins, not only those on an
access NNI, and cannot be turned off. If your RADIUS policy matches on the old values,
change it before upgrading. L2TP logins are unchanged.
A circuit runs one session. If a router sends both DHCP and PPPoE on the same VLAN, whichever comes up first keeps the circuit.
Relay to another LNS#
A row for an NNI and C-VLAN that carries TunnelEndpoints relays that circuit's PPPoE to those
L2TP endpoints, whatever username the router presents. The appliance does not authenticate the
login; the far LNS does, with any protocol it chooses.
Relay by realm is not available yet
The view may also publish realm rows (Realm), meaning "relay any login of this realm". The
appliance recognises them and currently rejects such a login rather than terminating it
locally. Do not publish realm rows for an NNI in production until this is released.
Worked example#
IPoE subscribers on NNI ms3-lon-1-a, addressed from pools in a VRF and translated by on-box CGN:
set subscribers access-nni ms3-lon-1-a interface eno1
set subscribers access-nni ms3-lon-1-a s-vlan 200
set routing vrf fttx-south table-id 2501
set routing vrf fttx-south rd 208:2501
set routing vrf fttx-south import-rt 208:2501
set routing vrf fttx-south export-rt 208:2501
set routing vrf fttx-south gateway-ip 100.64.16.1
set routing vrf fttx-south cgn-ip-group ms3-lon-1-a-cgn
set cgn enabled true
set cgn ip-group ms3-lon-1-a-cgn public-subnets 45.84.201.0/28
set address-pool ms3-ipoe-v4 family ipv4
set address-pool ms3-ipoe-v4 vrf fttx-south
set address-pool ms3-ipoe-v4 subnet 100.64.16.0/20
set address-pool ms3-ipoe-v4 exclude 100.64.16.0
set address-pool ms3-ipoe-v4 exclude 100.64.16.1
set address-pool ms3-ipoe-v4 exclude 100.64.31.255
set address-pool ms3-ipoe-v6-wan family ipv6-wan
set address-pool ms3-ipoe-v6-wan vrf fttx-south
set address-pool ms3-ipoe-v6-wan subnet 2a0e:9f81:101::/52
set address-pool ms3-ipoe-v6-pd family ipv6-pd
set address-pool ms3-ipoe-v6-pd vrf fttx-south
set address-pool ms3-ipoe-v6-pd delegation-length 56
set address-pool ms3-ipoe-v6-pd subnet 2a0e:9f81:110::/44
set protocols ipoe enabled true
The same configuration as JSON is config/examples/access-nni-ipoe.json in the product source; it
is validated by the product's own test suite.
Things the appliance will insist on, and why:
- Exclude the VRF's gateway address from the pool that contains it. Subscribers are told that address as their default router; it must not also be handed to one of them.
- Do not announce an IPv4 pool in a VRF that is translated by on-box CGN. Those addresses are private. (IPv6 pools in the same VRF are announced as usual.)
- IPv6 in a VRF needs a core that carries VPNv6. The appliance originates the VRF's IPv6
pools into BGP as VPN-IPv6 routes. If the PE it peers with has no
vpnv6address family for that VRF, subscribers get IPv6 addresses and their traffic goes nowhere. Checkshow bgp vrf <vrf> ipv6 unicaston the appliance and the VPNv6 table on the PE before you put IPv6 pools in a VRF. - The CGN group's public subnet cannot overlap the pool.
- A VRF name is at most 15 characters. The view must publish the appliance's VRF name, which may be shorter than your provisioning system's.
One thing it will not insist on: an IPv4 pool hands out every address in its subnets, lowest
first, including the subnet's own network and broadcast addresses. Some routers refuse an address
ending in .0 or .255, so the example excludes the first and last address of the subnet.
A subscriber in a VRF is given the VRF's gateway-ip as its default router, and can ping it.