Dynamic Circuits Part II: RADIUS support
• Herbert WolversonIn Dynamic Circuits, Part I we introduced a powerful new capability to LibreQoS: circuits can be built dynamically from detected traffic. This alone unlocks a number of powerful new abilities:
- Public Wi-Fi can have a range dedicated to users who connect, and they each get full CAKE shaping on demand.
- Set up “backup” subnets to detect users who appear online but haven’t yet obtained a provisioning entry (by mistake, or just to close holes).
Dynamic circuits appear quickly and vanish when they are no longer in use.
In the original article, we alluded to a bigger target: RADIUS support. The LibreQoS team have actually wanted this for several years, as it permits integration with a huge number of systems.
Why RADIUS Accounting? Why not just RADIUS?
RADIUS is a huge beast, and you should definitely use FreeRADIUS, or the MikroTik User Manager (FreeRADIUS is far better, but requires some work to set up). LibreQoS really shouldn’t try and do everything that a good RADIUS server can do. Instead, LibreQoS is focusing on its mission: traffic shaping and quality of experience.
RADIUS accounting is a good fit. It’s vendor agnostic. MikroTik, Juniper, Cisco, etc. all support emitting accounting reports when a subscriber connects, while they remain connected, and when they disconnect. It’s an open standard. Best of all, RADIUS accounting includes the information that’s needed: who connected, where they connected, and (optionally) what level of service they should receive.
RADIUS Accounting Implementation
RADIUS Accounting is implemented as part of the open-source core and will be available to everyone who installs version 2.2 (or builds from source). Our development strategy went roughly like this:
- Implement RFC 2866 - RADIUS Accounting in a detailed, thorough way. Run it through a battery of tests for security and protocol compliance. We kept improving it until it could cleanly reject deliberately broken traffic and interoperate fully with FreeRADIUS’s excellent radclient tool.
- Implement handling for popular attribute types used to specify client rates. Again, test extensively until the attributes were matched and various “gotchas” (such as units of measure!) were handled.
- Add LibreQoS configuration that lets you enable the server (the crate can also run stand-alone for verification), while leaving it off by default.
- Add configuration for various modes of operation (see below).
- Build a test suite that creates a MikroTik CHR virtual machine, a FreeRADIUS VM, and a LibreQoS VM. Then run a full batch of integration tests to ensure end-to-end success on our initial supported scenarios.
We left the automated test suite in the repository so the community can verify the work and offer improvements.
Modes of Operation
We supported three modes of operation to begin with:
- Many BNG setups receive the provisioned speed with the RADIUS response and forward it with the RADIUS Accounting request. If speed information is present in the accounting request, LibreQoS will provision a dynamic circuit named after the login and apply the requested plan.
- Not all BNGs forward provisioned speed, and other RADIUS clients (such as DHCP servers) usually do not. To make sure we support this scenario, LibreQoS can compare either the provided
Calling-Station-Id(usually the MAC address) orUser-Nameagainst an existingShapedDevices.csvsetup (which could be manually populated, or come from an integration). The dynamic circuit will then be created using the details from the devices file. - If you don’t want to specify your devices, or they all obtain the same plan - you can run in “default mode” and have a default plan applied to all connecting devices when the BNG or NAS submits RADIUS accounting.
MikroTik BNG Setup
MikroTik PPPoE setups with a BNG are a popular use-case for LibreQoS. LibreQoS could already “read inside” PPPoE headers to obtain the source and destination IP addresses and apply shaping. So the preferred setup remains:
Clients -> LibreQoS -> MikroTik BNG -> Internet
Previously, you’ve had to rely on an integration that periodically connects to the MikroTik and uses its API to extract lists of currently connected users. It works, but it leaves a “hole” in which customers aren’t provisioned. Some users try to mitigate this by running the integration scheduler VERY frequently, which can cause stability issues and isn’t great.
Now, you can configure your PPPoE system with RADIUS accounting. Create a shared secret between LibreQoS and the device that sends the accounting packets (the MikroTik, or your RADIUS proxy), and enable accounting. Whenever a user connects, the accounting packet is sent to LibreQoS - and the dynamic circuit is created.
LibreQoS Setup for a MikroTik BNG
First, LibreQoS needs to listen for accounting packets and be allowed to turn them into dynamic circuits. Add or update the following in /etc/lqos.conf, replacing the example addresses, parent node, and speeds with values from your network. Don’t duplicate a section that’s already present - TOML will quite reasonably refuse to load it!
[dynamic_circuits]
enabled = true
[radius_accounting]
enabled = true
listen = "192.0.2.10:1813"
default_ttl_seconds = 900
stale_grace_seconds = 120
[radius_accounting.dynamic_circuit_application]
enabled = true
match_shaped_devices_by_mac = true
match_shaped_devices_by_username = true
fallback_parent_node = "MikroTik BNG"
[radius_accounting.fallback_speed_profile]
download_min_mbps = 5.0
upload_min_mbps = 2.0
download_max_mbps = 30.0
upload_max_mbps = 10.0
[[radius_accounting.clients]]
name = "mikrotik-bng"
source = ["192.0.2.1/32"]
secret_file = "/etc/libreqos/radius-secrets/mikrotik-bng"
The listen value is an address on the LibreQoS server. The client source is the address the accounting packets actually arrive from. That’s usually the MikroTik, but if you are using a RADIUS proxy it is the proxy’s address. Don’t just open UDP port 1813 to the world: the source restriction and shared secret are both important.
The example enables all three modes described above. A speed sent in the accounting packet wins; after that LibreQoS tries to match the User-Name or Calling-Station-Id against the existing MAC field in ShapedDevices.csv; finally, an unknown customer receives the fallback plan. If you don’t want unknown customers to receive a circuit, omit the fallback speed profile. If you do use it, fallback_parent_node must name a real node in your network.json.
For example, a PPPoE login can be placed in the MAC field (we re-used the field to avoid adding yet another column):
Circuit ID,Circuit Name,Device ID,Device Name,Parent Node,Parent Node ID,Anchor Node ID,MAC,IPv4,IPv6,Download Min Mbps,Upload Min Mbps,Download Max Mbps,Upload Max Mbps,Comment
customer-42,Customer 42,customer-42,Customer 42,MikroTik BNG,,,[email protected],,,10,5,60,20,PPPoE username identity
Put the shared secret (on one line, without quotes) in the file referenced above, and protect it from other users:
sudo install -d -m 0700 /etc/libreqos/radius-secrets
sudoedit /etc/libreqos/radius-secrets/mikrotik-bng
sudo chmod 600 /etc/libreqos/radius-secrets/mikrotik-bng
sudo systemctl restart lqosd
Restart lqosd whenever you change the RADIUS configuration, secret, or the identity and plan fields read from ShapedDevices.csv.
MikroTik Setup for the BNG
If you are building a small PPPoE server, the RouterOS outline looks like this. Existing BNGs will already have most of it - substitute your real interface, pool, addresses, and secret rather than blindly creating a second PPPoE server!
/ip pool add name=pppoe-subscribers ranges=100.64.0.2-100.64.255.254
/ppp profile add name=pppoe-radius local-address=100.64.0.1 remote-address=pppoe-subscribers
/interface pppoe-server server add interface=ether3 service-name=internet default-profile=pppoe-radius one-session-per-host=yes disabled=no
/radius add service=ppp address=192.0.2.20 src-address=192.0.2.1 authentication-port=1812 accounting-port=1813 secret=replace-this-secret
/ppp aaa set use-radius=yes accounting=yes interim-update=5m
192.0.2.20 is the RADIUS endpoint in this example. If RADIUS is authenticating your PPPoE users, this should usually be a FreeRADIUS (or similar) proxy. The proxy forwards authentication to your normal AAA server and sends the accounting stream to LibreQoS. For this setup, change the LibreQoS client source in the previous example to the proxy’s forwarding address, and use the secret shared between the proxy and LibreQoS. LibreQoS deliberately does not answer authentication requests - it’s a shaper, not a replacement for FreeRADIUS.
If your PPP users are authenticated from local /ppp secret entries and you only want RADIUS accounting, the MikroTik can send directly to LibreQoS instead. Point /radius at the LibreQoS address and leave use-radius disabled:
/radius add service=ppp address=192.0.2.10 src-address=192.0.2.1 accounting-port=1813 secret=replace-this-secret
/ppp aaa set use-radius=no accounting=yes interim-update=5m
Make the interim interval comfortably shorter than LibreQoS’s default_ttl_seconds. We use five minutes with a fifteen-minute TTL in the example. This means a missed Stop packet won’t leave an immortal circuit, while an active session is refreshed long before it expires.
RouterOS sends a Calling-Station-Id containing the PPPoE client’s MAC address, the login as User-Name, and the assigned address as Framed-IP-Address. If your RADIUS server returns Mikrotik-Rate-Limit, RouterOS also includes it in accounting. Be careful with direction: MikroTik writes rates from the router’s point of view. In our end-to-end test, 25M/10M became 10 Mbps download and 25 Mbps upload in LibreQoS. Test one real plan before rolling this out to everyone.
You can watch the RouterOS counters with /radius monitor 0 (replace 0 with the number shown by /radius print) and watch LibreQoS at the same time:
sudo journalctl -u lqosd -f
Connect one test subscriber, wait for an Interim-Update, and then disconnect it. You should see the dynamic circuit created, refreshed, and removed - the complete Start/Interim/Stop lifecycle.
DHCP RADIUS Support
DHCP is pleasantly similar. RouterOS can use RADIUS to authorize leases and send accounting, or it can leave your existing DHCP setup alone and send accounting only. For most existing networks, accounting-only is the safest place to start:
/radius add service=dhcp address=192.0.2.10 src-address=192.0.2.1 accounting-port=1813 secret=replace-this-secret
/ip dhcp-server set subscribers use-radius=accounting
subscribers is the name of the existing DHCP server in this example. With use-radius=accounting, the MikroTik continues assigning leases exactly as it did before, but reports their lifecycle to LibreQoS.
If RADIUS should also decide whether a client receives a lease (and optionally return Framed-IP-Address, Framed-Pool, or Mikrotik-Rate-Limit), use yes instead:
/ip dhcp-server set subscribers use-radius=yes
Just like PPPoE, full RADIUS-backed DHCP normally points at a RADIUS proxy when LibreQoS and the authentication server are separate. The proxy handles the Access-Request/Access-Accept conversation and forwards Accounting-Start, Interim-Update, and Accounting-Stop packets to LibreQoS.
For DHCP, RouterOS sends the client MAC address as User-Name, the active client identifier as Calling-Station-Id, and the leased address as Framed-IP-Address. Keep both matching options enabled on LibreQoS and put known customer MAC addresses in the MAC field of ShapedDevices.csv. LibreQoS normalizes the common colon, hyphen, dotted, and plain-hex MAC formats before matching the calling-station value.
Accounting-only DHCP doesn’t receive a speed from an Access-Accept, so it normally obtains the plan from ShapedDevices.csv or the fallback profile. Full RADIUS-backed DHCP can use Mikrotik-Rate-Limit when your RADIUS server supplies it.
Finally, make sure the DHCP lease and LibreQoS TTLs make sense together. A live lease must renew (and produce an accounting update) before LibreQoS expires it. Test a short lease first: acquire an address, renew it, then release it, watching journalctl for the same creation, refresh, and removal lifecycle used by PPPoE.
Moving Forward
There’s plenty of room for this feature to improve in the future:
- Better support for multiple BNGs (identified with different shared secrets).
- Better topology insertion.
- Better rules for extracting information for customers.
Overall, we’re really excited to finish this feature. It should open up compatibility with MANY billing systems and methods of operation. Let us know what you’re running, so we can work with you to support your needs (within reason; we obviously have to fit requests into our schedule, product design, etc.). We’re excited to join you on the LibreQoS 2.2 journey!