DHCP/IPoE Configuration
Configure DHCP subscriber termination for IPoE sessions.
Overview
The dhcp section configures the DHCP/IPoE server (abng-dhcpd), which:
- Terminates DHCP sessions from IPoE subscribers
- Authenticates via RADIUS using MAC address
- Assigns IP addresses from RADIUS or pools
- Injects Option 82 Circuit ID for subscriber identification
Configuration Options
enabled
Enable or disable DHCP/IPoE (optional).
dhcp:
enabled: true
Type: Boolean
Required: No
Default: false
Valid values: true, false
CLI:
abng# set dhcp enabled true
Note: Requires radius.servers to be configured.
lease_time
DHCP lease time in seconds (optional).
dhcp:
lease_time: 3600
Type: Integer
Required: No
Default: 3600
Constraints: Positive integer (seconds)
Purpose: How long the subscriber can use the assigned IP.
CLI:
abng# set dhcp lease_time 3600
allocation_mode
IP address allocation mode (optional).
dhcp:
allocation_mode: "radius"
Type: String
Required: No
Default: "radius"
Valid values: "radius", "pool"
| Mode | Description |
|---|---|
radius | IP assigned by RADIUS (Framed-IP-Address) |
pool | IP assigned from configured pools |
In radius mode, abng-dhcpd authenticates the subscriber MAC against RADIUS and
the Access-Accept supplies the Framed-IP-Address plus optional rate attributes
(Athena-Rate-Down / Athena-Rate-Up). The MAC is sent to RADIUS in lowercase
(e.g. aa:bb:cc:dd:ee:ff), which matters for case-sensitive RADIUS user matching.
CLI:
abng# set dhcp allocation_mode "radius"
unnumbered
Use unnumbered IPoE (optional).
dhcp:
unnumbered: true
Type: Boolean
Required: No
Default: true
Valid values: true, false
Purpose: Assign /32 addresses instead of /24 subnets.
CLI:
abng# set dhcp unnumbered true
pools
IP address pools for allocation (optional, required if allocation_mode is "pool").
dhcp:
pools:
- network: "10.100.0.0/23"
gateway: "10.100.0.1"
dns_servers:
- "1.1.1.1"
- "8.8.8.8"
Pool Options
network
Network CIDR for the pool (required).
pools:
- network: "10.100.0.0/23"
Type: CIDR notation
Required: Yes
Constraints: Valid IPv4 CIDR (e.g., "10.100.0.0/23")
gateway
Gateway IP for the pool (required).
pools:
- gateway: "10.100.0.1"
Type: IPv4 address
Required: Yes
Constraints: Valid IPv4 address within the network
dns_servers
DNS servers for the pool (optional).
pools:
- dns_servers:
- "1.1.1.1"
- "8.8.8.8"
Type: List of IPv4 addresses
Required: No
Default: Empty
Example Configurations
RADIUS-Based Allocation
dhcp:
enabled: true
lease_time: 3600
allocation_mode: "radius"
unnumbered: true
IP addresses come from RADIUS Framed-IP-Address attribute.
Pool-Based Allocation
dhcp:
enabled: true
lease_time: 3600
allocation_mode: "pool"
unnumbered: true
pools:
- network: "10.100.0.0/23"
gateway: "10.100.0.1"
dns_servers:
- "1.1.1.1"
- "8.8.8.8"
IP addresses allocated from configured pools.
Multiple Pools
dhcp:
enabled: true
lease_time: 3600
allocation_mode: "pool"
pools:
- network: "10.100.0.0/23"
gateway: "10.100.0.1"
dns_servers: ["1.1.1.1", "8.8.8.8"]
- network: "10.101.0.0/23"
gateway: "10.101.0.1"
dns_servers: ["8.8.8.8", "1.1.1.1"]
Configuration via CLI
Enable DHCP
abng> configure
abng# set dhcp enabled true
abng# commit
Set Lease Time
abng# set dhcp lease_time 7200
abng# commit
Set Allocation Mode
abng# set dhcp allocation_mode "radius"
abng# commit
Add IP Pool
abng# set dhcp pools[0] network "10.100.0.0/23"
abng# set dhcp pools[0] gateway "10.100.0.1"
abng# set dhcp pools[0] dns_servers ["1.1.1.1", "8.8.8.8"]
abng# commit
Verification
View DHCP Configuration
abng> show configuration | match "^dhcp:"
dhcp:
enabled: true
lease_time: 3600
allocation_mode: radius
unnumbered: true
pools:
- network: 10.100.0.0/23
gateway: 10.100.0.1
dns_servers: [1.1.1.1, 8.8.8.8]
View DHCP Sessions
abng> show subscribers dhcp
┌────┬───────┬──────────┬───────────────┬────────────┬──────────┐
│ ID │ Type │ Username │ IP Address │ Interface │ Speed D/U│
├────┼───────┼──────────┼───────────────┼────────────┼──────────┤
│ 5 │ DHCP │ - │ 203.0.113.20 │ eth1.111.5 │ 50M/20M │
│ 6 │ DHCP │ - │ 203.0.113.21 │ eth1.111.6 │ 100M/40M │
└────┴───────┴──────────┴───────────────┴────────────┴──────────┘
Check abng-dhcpd Logs
sudo journalctl -u abng-dhcpd -f
Integration with RADIUS
DHCP requires RADIUS for authentication:
dhcp:
enabled: true
allocation_mode: "radius"
radius:
servers:
- host: "10.255.0.10"
secret: "your-secret"
nas_identifier: "AthenaBNG"
nas_ip_address: "10.255.0.1"
RADIUS attributes used:
- User-Name — MAC address, lowercase (e.g., "aa:bb:cc:dd:ee:ff")
- Calling-Station-Id — MAC address
- NAS-Port-Id — Circuit ID (interface name)
- Framed-IP-Address — Assigned IP address
- Framed-IP-Netmask — Subnet mask (/32 for unnumbered)
- Session-Timeout — Session timeout in seconds
- Athena-Rate-Down / Athena-Rate-Up — Optional per-subscriber download/upload rates
Integration with QoS
DHCP sessions can have per-subscriber QoS rules:
qos:
enabled: true
default_down: "50mbit"
default_up: "20mbit"
default_overhead_profile: "ipoe_ethernet"
QoS is applied when:
- DHCP session is established
- RADIUS returns rate attributes (
Athena-Rate-Down/Athena-Rate-Up) - CAKE shaping is applied per subscriber — downstream on the subscriber VLAN interface and upstream via a per-session IFB device
Unmetered subscribers: if RADIUS returns no rate attribute, the subscriber is left unmetered (no shaping). There is no implicit default rate — a subscriber with no plan runs unshaped.
Rate changes on renewal: rates re-apply on lease renewal. If the rate returned by RADIUS differs from the active session's, abng-dhcpd / abngd update it and re-apply QoS in place (the per-session IFB is keyed by session id, which is unchanged across a renewal). RADIUS CoA can also change rates mid-session.
IPv6 / DHCPv6-PD
IPoE dual-stack is available. Enable the DHCPv6-PD listener with
dhcp.ipv6_enabled, and optionally set the DNS servers advertised to clients
with dhcp.ipv6_dns:
dhcp:
ipv6_enabled: true
ipv6_dns:
- "2606:4700:4700::1111"
It follows the same RADIUS-authoritative, no-pool, fail-closed model as PPPoE:
- IA_PD is delegated from the RADIUS
Delegated-IPv6-Prefix; with no delegated prefix from RADIUS the client is answeredNoPrefixAvail— never a locally invented prefix. - IA_NA is answered
NoAddrsAvail— the IPoE WAN address comes via SLAAC (Framed-IPv6-Prefix), not stateful DHCPv6.
Dual-stack session correlation
A DHCPv6 exchange carries no Option-82 circuit-id, so a circuit-only subscriber (authenticated by its access circuit rather than a MAC) could not be matched on its own. AthenaBNG reuses the delegated prefix returned in the subscriber's IPv4 Access-Accept for the DHCPv6-PD request arriving on the same access interface — so one RADIUS authentication provisions the whole dual-stack session. Genuine v6-only subscribers still fall back to their own DHCPv6 (DUID→MAC) authentication.
See IPv6 / Dual-Stack for the full model.
Option 82 (Relay Agent Information)
By default AthenaBNG injects Option 82 with a Circuit ID derived from the
subscriber VLAN interface and a Remote ID of the BNG hostname, so upstream
RADIUS can identify the access line. The behaviour is configurable under
dhcp.option82:
dhcp:
option82:
enabled: true
existing_policy: keep # keep | replace | append
circuit_id_format: "{interface}"
remote_id: "" # empty = BNG hostname; "" omits it
trust_circuit_id: false
| Option | Purpose |
|---|---|
existing_policy | What to do when Option 82 is already present (e.g. inserted by an access node): keep, replace, or append. |
circuit_id_format | Circuit-ID template; {interface} expands to the subscriber VLAN interface. |
remote_id | Remote-ID value; empty means the hostname, "" omits it. |
trust_circuit_id | See below. |
trust_circuit_id
By default an Option 82 circuit-id is only trusted when the packet was relayed
(giaddr ≠ 0), so a directly-connected subscriber cannot forge one. Set
trust_circuit_id: true on a subscriber trunk fed by a trusted L2 access
node — for example an NBN access node that stamps the AVC circuit-id without
setting giaddr — so the injected circuit-id (the AVC) is used as the RADIUS
NAS-Port-Id. This lets you authenticate subscribers by their access circuit
regardless of the CPE behind it.
CLI:
abng# set dhcp option82 trust_circuit_id true
Re-authentication on renewal
Subscribers are re-authenticated against RADIUS on every DHCP renewal, not only at first bind. If RADIUS now rejects a previously-authorised subscriber, its lease is NAK'd and the session is torn down (route withdrawn, Accounting-Stop sent) instead of renewing indefinitely. If RADIUS is unreachable the renewal fails open — the lease is kept — so an AAA outage cannot mass-disconnect established subscribers; only an explicit reject terminates a session.
Lease Persistence
abng-dhcpd persists its active lease table to /opt/athena-bng/run/dhcp-leases.json
so a restart of the daemon does not disrupt subscribers. The file is written
atomically (temp file + rename) every 30 seconds and again on shutdown.
On startup abng-dhcpd restores the leases from this file:
- Leases that expired while the daemon was down are dropped.
- Surviving leases are re-inserted with their IPs reserved in the address pool and marked already-notified (abngd keeps the session across the dhcpd restart).
The effect is that an abng-dhcpd restart no longer NAKs renewing clients or desyncs the address pool — clients keep their lease. Lease and accounting timers are preserved using absolute timestamps, so the remaining lease time survives the restart. RADIUS Accounting-On is still sent at startup and Accounting-Stop/Off at shutdown.
This is automatic and requires no configuration.
Validation Rules
| Field | Validation |
|---|---|
enabled | Boolean |
lease_time | Positive integer (seconds) |
allocation_mode | One of: radius, pool |
unnumbered | Boolean |
pools[].network | Valid CIDR notation |
pools[].gateway | Valid IPv4 address |
pools[].dns_servers | List of valid IPv4 addresses |
option82.existing_policy | One of: keep, replace, append |
option82.trust_circuit_id | Boolean |
ipv6_enabled | Boolean |
ipv6_dns | List of valid IPv6 addresses |
Best Practices
- Allocation Mode — Use "radius" for subscriber-specific IPs
- Lease Time — Use 3600s (1 hour) for standard DHCP
- Unnumbered — Use /32 addresses for IPoE (no subnet)
- Pools — Define separate pools for different subscriber classes
- RADIUS — Always configure RADIUS for authentication
- QoS — Enable QoS for per-subscriber rate limiting
- DNS — Configure DNS servers in pools or via RADIUS
Troubleshooting
No DHCP Sessions Appearing
- Check DHCP is enabled:
show configuration | match dhcp - Check VLAN demux is enabled:
show configuration | match demux - Check VLAN interfaces are created:
show vlans - Check RADIUS is reachable:
radtest testuser testpass <radius-ip> 1812 <secret> - Check abng-dhcpd logs:
journalctl -u abng-dhcpd -f
Sessions Not Getting IP
- Check allocation mode:
show configuration | match allocation_mode - Check pools are configured (if pool mode):
show configuration | match pools - Check RADIUS returns Framed-IP-Address (if radius mode)
- Check abng-dhcpd logs:
journalctl -u abng-dhcpd -f
IP Pool Exhaustion
- Check pool size:
show configuration | match pools - Check active sessions:
show subscribers dhcp | count - Expand pool or reduce lease time
- Check for stale leases:
journalctl -u abng-dhcpd | grep "lease expired"
Next Steps
- RADIUS Configuration — RADIUS servers and AAA
- QoS Configuration — CAKE traffic shaping
- IPv6 / Dual-Stack — dual-stack subscriber service
- Configuration Overview — All configuration sections