⚠️ Modernization Notice This post was written in 2018 against Cisco IOS XE / ISG on the ASR 1000. Behavior around parameterized QoS, CoA, and policy-map chaining has changed across releases. Treat the configs and outputs here as a record of what I tested at the time, and validate against the current IOS XE configuration guides before deploying.
Overview
On the ASR 1000 (and IOS XE in general) there are broadly two ways to apply QoS to subscriber sessions: per-session and per-flow. They cannot be applied at the same time on the same session, so the first decision is which model fits your service.
Per-session policing applies to the whole session — every flow is treated the same. It can be installed at session start from the Access-Accept, or applied/changed later via CoA. The Cisco-Session-Info AVP carries the rates, for example:
| |
Look up the Cisco RADIUS CoA Interface Guide — Appendix A documents this attribute in detail. Because it is a single, general policer for the whole session, you cannot prioritize particular traffic types (VoIP, etc.) with it.
Per-flow QoS is applied through a regular MQC policy-map, which lets you classify and treat traffic differently. There are three ways to deploy it:
- Define and apply the QoS policy from the CLI.
- Define the QoS policy in the CLI, but apply it from RADIUS.
- Define and apply the QoS policy entirely from RADIUS — this is what Cisco calls Parameterized QoS.
Two important caveats before the examples:
- You cannot apply per-session and per-flow QoS simultaneously.
- The QoS order of operation is different on the ASR 1000 / IOS XE. Read Hierarchical Color-Aware Policing carefully before relying on input policing or marking.
Further reading:
- Deploying the Quality of Service (QoS)
- Configuring ISG Policies for Regulating Network Access
- Configuring RADIUS-Based Policing, IOS XE 3S
- Hierarchical Color-Aware Policing
Base ISG Configuration
The following is the relevant (non-exhaustive) ISG/PPPoE configuration that the examples build on:
| |
Per-Session Example
The subscriber’s rates are carried in the AAA profile:
| |
After the session comes up, the per-user policer reflects those rates:
| |
Changing the rate with CoA
Push a new rate to the live session with a Change-Filter-Request:
| |
The policer updates in place:
| |
Per-Flow QoS
Method 2.1 — Define and apply from the CLI
The simplest case: attach a policy-map directly under the virtual-template so it applies to every session. This is rarely useful on its own, because you still need a way to vary the parameters per customer (via RADIUS or similar). I’m not including a configuration for it since it is trivial.
Method 2.2 — Define in the CLI, apply from RADIUS
Here the class-maps and ACLs live on the ISG, but RADIUS selects or modifies the policy per customer.
Example 1 — policy-map name per customer. RADIUS sends a policy-map name in the Access-Accept. This means every customer or speed tier needs its own policy-map configured with that customer’s up/down speeds and service classes. It works, but the configuration grows with every speed group. (No config shown — it is straightforward.)
Example 2 — one generic policy-map, modified via RADIUS. A generic parent/child policy-map is defined once in the CLI and then changed dynamically with RADIUS attributes (add/modify classes).
MQC CLI configuration:
| |
Subscriber profile:
| |
To change the parent shaper/policer on a live session via CoA, chain the class-default of the parent policy. Watch the doubling: ISG applies twice the value sent in the CoA message because of subscriber service police percent-factor 100 (for policing) or subscriber service shaper percent-factor 100 (for shaping). You can also change other class values the same way.
| |
The resulting policy shows the doubled values — a requested police(220000) lands as cir 440000, and the input service-policy name encodes the chained value:
| |
The same parameters can also be set in the initial Access-Accept instead of via CoA — a general policy-map is configured on the ISG and its values are set from the subscriber’s bandwidth profile (a form of dynamic template):
| |
Full show policy-map interface Vi2.1 for both the CoA case (session 887) and the initial Access-Accept case (session 888): show-policy-map-perflow-example2.md.
Example 3 — generic parent with an empty child class. Real deployments mix many up/down speed combinations, and only some customers buy voice service. Defining a separate policy-map per combination bloats the configuration. In Example 2 the child policy already carried a default voice class; here I instead apply an empty child policy, which is what lets RADIUS add the customer’s classes onto the parent policy-map later.
| |
A word on physical vs. service speed. This generic-shaper approach regulates the customer to their purchased service speed, which is fine on its own. But if you also rely on the QoS hierarchy for congestion management, the parent shaper must not exceed the customer’s physical access speed. If the service speed is higher than the line sync rate, congestion happens at the physical layer before the QoS mechanism ever sees the configured rate as “congested,” and prioritization breaks. (See Broadband Forum TR-147, sections 6.1–6.2.)
For example, a customer buys 10 Mb down / 1 Mb up, but the DSLAM syncs at 4 Mb. Regulating them to 10 Mb is harmless, but QoS expects the 10 Mb shaper to be the congestion point — which never happens, because the real bottleneck is the 4 Mb line.
The fix is to make RADIUS aware of the physical sync rate. The DSLAM can insert PPPoE intermediate-agent tags (dsl-sync-rate), and RADIUS can use those when setting the customer’s QoS parameters and for reporting. ANCP is another way to learn the line rate.
Input (CE → PE) classes. Below I add a BB_QoS_VOIP_UP qos-group that is not defined in the CLI-defined BB_GENERIC_PARENT_UP (the class-map itself must still be pre-defined in the CLI). Some QoS actions are not supported on input — for example set-mpls-exp-topmost-transmit. Read Hierarchical Color-Aware Policing for the input-policing limitations.
| |
If you want to change the overall session bandwidth (for fair-usage reasons) without affecting an upper class like voice, add a default class to the child policy at the rate you want:
| |
Output (PE → CE) classes. Similar to the input policy, but with more classes:
| |
With this, all customer inbound traffic is policed to 3 Mb, the BB_GENERIC_PARENT_UP voice class gets 256 K, and the default class gets 1 M.
Handling the speed mismatch in RADIUS. I also wrote a small bit of logic on the RADIUS side to solve the physical-speed problem, using the DSLAM’s dsl-sync-rate PPPoE tag:
| |
RADIUS compares the customer’s physical (sync) speed against their service speed and decides which policy-maps to send:
| |
Because the applied policy name shows up in the CDRs, you can also report which customers ended up on the ERROR policy-maps.
Method 2.3 — Define and apply entirely from RADIUS (Parameterized QoS)
This is the method documented in the ASR 9000 configuration guide. On the ASR 1000 the policy is expected to be defined in the CLI (Configuring Parameterized QoS Policy Through RADIUS), so I never had a clean way to try the full ASR 9000 style. I did attempt a minimal version on the ASR 1000 — just a shaper under the default class, built entirely from RADIUS — but the session never came up:
| |
The authorization fails while building the service-policy:
| |
Full SSS PM / AAA AUTHOR debug for this failed attempt: parameterized-qos-from-radius-failure.md.
Reader Tip: FreeRADIUS and the kbps→bps gotcha
A reader, Harald Kapper, later shared a useful FreeRADIUS pointer for per-session custom values on the ASR 1000. With FreeRADIUS you can send a cisco-avpair like the following (and store it in the radreply/groupreply table if you use a database):
| |
Depending on the FreeRADIUS version (v2 vs v3), the back-ticks around the expansion may or may not be needed. The trailing 000 matters: the BRAS receives the data rate in kbps via the DSL line-rate attribute, while QoS on the ASR 1000 expects bps.
Summary
- The ASR 1000 offers per-session (one policer for the whole session, via
Cisco-Service-Info/ CoA) and per-flow (MQC policy-map) QoS, and the two cannot be combined on the same session. - For real broadband deployments, the practical pattern is one generic parent/child policy-map defined in the CLI, parameterized per customer from RADIUS (Example 2/3), rather than a policy-map per speed tier.
- Mind the percent-factor 100 doubling when sending rates over CoA.
- Match the parent shaper to the customer’s physical line rate, not just their service speed — otherwise the QoS hierarchy never sees the real congestion point. Feed the line rate to RADIUS via
dsl-sync-ratePPPoE tags or ANCP, and fall back to ERROR policy-maps when the numbers don’t add up. - Fully RADIUS-defined parameterized QoS (method 2.3) is an ASR 9000 feature; on the ASR 1000 I could not get it to come up and reverted to CLI-defined, RADIUS-parameterized policies.
References
- Deploying the Quality of Service (QoS) — ASR 1000
- Configuring RADIUS-Based Policing, IOS XE 3S
- Hierarchical Color-Aware Policing
- Configuring ISG Policies for Regulating Network Access
- Cisco RADIUS CoA Interface Guide (Appendix A —
Cisco-Service-Info) - Broadband Forum TR-147 — Layer 2 Control Mechanism (sections 6.1–6.2, access-rate handling)
The content of this post was created by the author; AI was used for editing and restructuring.