Policed, Not Just Routed: Traffic Shaping and QoS Internals on Fortinet SD-WAN
The question app-aware routing doesn’t answer
From DSCP to Deep Packet Inspection covered how a FortiGate decides which overlay member or egress interface a flow takes — performance SLAs, application signatures, DSCP markings, the works. That post answers “which path?” This one answers the question that comes immediately after: once the flow is on that path, what stops it from drowning out everything else competing for the same bandwidth?
That’s traffic shaping’s job, and on FortiOS it’s a genuinely separate subsystem from path selection — separate configuration objects, separate place in the policy evaluation order, separate interaction with the NP7 hardware path covered in Part 1 of the packet-flow series. Treating the two as one blurry “QoS thing” is the most common reason shaping deployments under-perform: people tune the SLA rules expecting it to also solve congestion, and then wonder why a saturated link still has voice quality problems.
Three shaping constructs, three different jobs
FortiOS gives you three distinct shaping objects, and picking the wrong one for the job is the second most common mistake after conflating shaping with routing.
Shared shapers apply a ceiling to all traffic matching a policy, collectively. Ten users hitting a shared shaper of 50 Mbps split that 50 Mbps between them — it’s a pool, not a per-user allowance. These are the right tool when you’re protecting a link’s aggregate capacity for a traffic class (e.g., “guest Wi-Fi as a whole gets no more than 20% of this circuit”).
Per-IP shapers apply the configured rate to each source IP independently. Ten users behind a per-IP shaper of 5 Mbps each get their own 5 Mbps — fairness by host, not by class. This is what you reach for when the goal is “no single device should be able to monopolise the link,” which is a different problem than “this whole category of traffic should be capped.”
Application-based / policy shapers layer on top of either of the above by binding the shaper to a firewall policy and, optionally, an application or application-category match. This is the connective tissue back to application-aware routing — you can have a flow selected for the “best” overlay path by SLA, and still be shaped according to its application identity once it’s traveling that path.
The mistake worth calling out explicitly: reaching for a shared shaper when what you actually wanted was per-IP fairness produces a deployment where one chatty host can still starve everyone else within the shared pool — the shaper “works” by its own definition while the actual user-facing problem persists.
Where shaping sits in the evaluation order
This is the part that trips people up coming from a pure routing mental model. Shaping is evaluated as part of firewall policy processing — the same stage covered in Part 4 of the packet-flow series, downstream of the SD-WAN rule that already picked the egress path. The sequence, in practice:
- SD-WAN rules select the member/interface based on SLA performance (DSCP/app-aware routing’s domain).
- The flow matches a firewall policy on that egress path.
- That policy’s shaper assignments — shared, per-IP, or application-bound — determine the rate the flow is actually allowed to sustain, and which output queue it lands in.
- NP7 offload takes over enforcement in hardware wherever it can (more on this below).
If you only tune step 1, you’ve optimised which congested or under-performing path a flow avoids — you haven’t done anything about how it behaves once it’s competing for bandwidth on the path it lands on. Both matter; they’re just not the same lever.
Queuing: where the packet actually waits
Shapers set rate ceilings; queues are where the FortiGate decides order when multiple flows are competing for the same egress capacity at the same instant. FortiOS exposes queue priority as part of the shaping/policy configuration, and the practical effect is straightforward: a voice flow assigned to a high-priority queue gets serviced ahead of a bulk-transfer flow in a lower-priority queue when both are contending for the same interface bandwidth, independent of the rate ceiling either one is shaped to.
This is where DSCP markings earn their keep a second time. The same markings that fed application-aware routing’s path-selection logic can also drive queue assignment — a consistent marking scheme means you’re not maintaining two separate classification systems for “which path” and “which priority,” you’re reusing one signal for both decisions. If you’re designing a shaping scheme from scratch and you’ve already got DSCP discipline from the routing side, lean on it; don’t invent a parallel tagging scheme.
The NP7 question: what gets offloaded, and what doesn’t
Part 1 of the packet-flow series covered how the NP7 fast path lets established sessions bypass the CPU-bound inspection stages entirely. Shaping interacts with that fast path in a way that’s worth understanding before you design around it: rate enforcement for offloaded sessions happens in NP7 hardware, not in the CPU-bound shaping engine — which is exactly what makes shaping viable at the throughput a 50G platform is rated for. Software-only shaping at that scale would be a non-starter.
The practical implication for design: shaping policies that align cleanly with what the NP7 path can offload (straightforward rate and priority assignment, consistent per-policy shaper objects) stay fast. Configurations that force sessions back through the CPU-bound path — heavy per-session inspection requirements stacked on top of shaping, certain combinations of UTM profiles and shaping that can’t be jointly offloaded — will work, but at a throughput cost that’s easy to miss in a lab and painful to discover in production. When a shaping deployment “works in testing” but degrades under real load, the offload boundary is the first place to look, and diagnose sys session / NP7-specific session counters (covered in the troubleshooting cookbook) are the tools that show you whether a flow landed in hardware or software.
A worked design: voice, business apps, and everything else
Take a branch circuit that needs to protect VoIP, guarantee a baseline for line-of-business SaaS, and prevent recreational traffic from affecting either:
- Voice: per-IP shaper sized to a single call’s bandwidth (preventing one device from running multiple calls and starving others), bound to a high-priority queue, matched on the same DSCP marking that already steers it to the lowest-latency overlay member in the SD-WAN rules.
- Business SaaS: application-based shaper bound to the relevant application category, shared-pool ceiling sized to guarantee a baseline aggregate even under contention, medium-priority queue.
- Everything else: shared shaper capping the aggregate at a conservative ceiling, low-priority queue, no per-IP guarantee — the explicit design intent being “this traffic gets what’s left, never what’s needed.”
Notice that all three reuse the DSCP scheme from the routing side rather than inventing new classification — the path-selection decision and the shaping decision are reading the same signal and acting on it independently, which is exactly the separation of concerns this post has been arguing for.
Where this leaves the SD-WAN series
Two threads remain on the roadmap: the MPLS-to-SD-WAN cutover playbook (the practical migration counterpart to the VeloCloud MPLS-only site material), and FortiAnalyzer/FortiMonitor observability for SLA breaches — which, not coincidentally, is exactly the tool you’d reach for to confirm that the shaping design in this post is actually holding up against real traffic rather than just looking correct on paper.