01The four moving parts, and the pipeline
Four elements do all the work. Keep them straight and the steering logic is readable:
| Underlay | The transports (ISP1, ISP2, MPLS, LTE). They provide raw reachability to the far end. |
|---|---|
| Overlay | The tunnels (IPsec/GRE) riding the underlay. These — plus raw WAN interfaces — become SD-WAN members. |
| Zones | Named groups of members by role (overlay, underlay). Rules and firewall policies point at zones. |
| Routes | The FIB entries that make a member a valid candidate for a destination. No route, no steering. |
Steering is those four consumed in a fixed order — a decision pipeline:
Packet in
│
▼
[1] Route lookup ───── no route ─────▶ drop
│ (members with a route = candidates)
▼
[2] SD-WAN rule match ──── no match ──▶ [implicit rule]
│ src / dst / app / ToS load-balance
▼ the whole zone
[3] SLA health-check filter
│ keep members: alive + in SLA
▼
[4] Strategy selects ONE member
│ (manual / lowest-cost / best-quality / load-balance)
▼
Firewall policy ──▶ egress on the chosen overlay/underlay member
Steering decision = route lookup + rule match + SLA filter + strategy
02Prerequisite: routes make members eligible
This is the step most people skip, and it's why tunnels sometimes never get used. SD-WAN can only steer over a member if the routing table has a route to the destination via that member. In practice you give every member an equal-cost route — a static route per tunnel, or the same prefix learned by BGP over each overlay — so all members are eligible and SD-WAN, not routing, gets to make the choice.
Candidate member = a member with a valid route to the destination
If only one member has a route, SD-WAN has nothing to decide — routing already forced the path. Equal-cost routes across the members are what hand the decision to SD-WAN.
03Step 1: Route lookup builds the candidate set
A packet arrives; the FortiGate resolves its destination in the FIB. Because each member carries an equal-cost route, the lookup returns all of them as candidates rather than one winner:
get router info routing-table all
S 10.0.0.0/8 [10/0] is directly connected, IPsec-HUB-ISP1
[10/0] is directly connected, IPsec-HUB-ISP2
Two equal-cost routes to the HQ range — one over each overlay tunnel. Without SD-WAN this is plain ECMP (hash and go). With SD-WAN, this candidate set is handed to the rules instead. If the lookup returns no route, the packet is dropped here — steering never gets a say.
04Step 2: SD-WAN rules match the traffic
SD-WAN rules (services) are evaluated top-down, first match wins — exactly like a firewall policy list. Each rule matches on some combination of source, destination, application (Internet-Service/ISDB), and ToS/DSCP:
config system sdwan
config service
edit 1
set name "ERP-to-HQ"
set src "Branch-LAN"
set dst "HQ-Subnets"
set mode sla
config sla
edit "HQ-probe"
set id 1
next
end
set priority-members 1 2 # IPsec-HUB-ISP1, IPsec-HUB-ISP2
next
end
end
The first rule whose criteria match takes the packet and constrains the candidate set to that rule's members (here, the two overlay tunnels). Order matters: put specific rules (ERP, VoIP) above broad ones (all HTTPS). If no rule matches, the packet falls through to the implicit rule — covered in step 4.
05Step 3: SLA health-check filters the members
A rule in sla mode doesn't trust a member just because it's up — it trusts it only
while it meets the SLA. Health-check probes measure latency, jitter and packet
loss continuously; a member is kept as a choice only if it's alive and
inside the thresholds:
Qualified members = rule's members ∩ (alive + within SLA thresholds)
| alive + in SLA | Stays in the running — eligible for selection. |
|---|---|
| alive but SLA breached | Dropped from the choice (too much loss/latency/jitter) while any in-SLA member remains. |
| dead | Removed entirely — the tunnel or its underlay is down. |
This is the layer that reacts to brownouts: a link that's technically up but losing 15% of packets is pulled from the candidate set so the next step never picks it.
06Step 4: The strategy picks one member
Among the qualified members, the rule's strategy makes the final call:
| Manual | Use members in configured priority order — first qualified member wins. Simple active/backup. |
|---|---|
| Lowest cost (SLA) | Of the in-SLA members, pick the cheapest (lowest cost / best priority). Prefer MPLS, fail to broadband. |
| Best quality | Pick the member with the best measured metric (lowest latency, jitter, or loss). Great for real-time. |
| Maximize bandwidth | Load-balance across all qualified members at once (per-session). |
The implicit rule is the catch-all at the bottom: any traffic that matched no explicit rule is load-balanced across the whole SD-WAN zone using the configured algorithm (source IP, source-dest IP, sessions, or spillover). It's the SD-WAN equivalent of a default route — set it deliberately so "everything else" has sane behaviour.
Selected member = strategy( qualified members )
07Follow one packet end to end
A user in the branch opens the ERP app at HQ. Watch the pipeline run:
Branch-LAN 10.20.0.5 ──▶ ERP at HQ 10.0.5.10 (TCP 443)
[1] Route lookup 10.0.5.10 ∈ 10.0.0.0/8
candidates: IPsec-HUB-ISP1, IPsec-HUB-ISP2 (equal-cost)
[2] Rule match rule 1 "ERP-to-HQ": src Branch-LAN, dst HQ-Subnets ✓ match
members constrained to: ISP1, ISP2 (zone: overlay)
[3] SLA filter ISP1: alive, loss 0.0%, lat 18ms → in SLA ✓
ISP2: alive, loss 2.1%, lat 35ms → in SLA ✓
[4] Strategy=sla lowest cost of the two → ISP1
Egress IPsec-HUB-ISP1 (overlay) → ISP1 circuit (underlay) → HQ
Now brown out ISP1 (loss climbs to 12%). Nothing else changes — step 3 simply drops ISP1 from the qualified set, so step 4 selects ISP2. The route lookup and the rule match were identical; only the SLA filter's output moved. That's the whole point of the ordering: each step narrows the set, and the fast-moving SLA layer sits right before selection.
08Verify it & where to go next
One command shows the rule, its members, their SLA state, and which one is selected right now — the whole pipeline's output in one place:
diagnose sys sdwan service
Service(1): Address Mode(IPV4) flags=0x200
Gen(3), TOS(0x0/0x0), Protocol(0), Mode(sla)
Members(2):
1: Seq_num(1 IPsec-HUB-ISP1), alive, sla(0x1), cfg_order(0), cost(0), selected
2: Seq_num(2 IPsec-HUB-ISP2), alive, sla(0x1), cfg_order(1), cost(0)
Dst address(1):
10.0.0.0-10.255.255.255
selected is the member step 4 chose; sla(0x1) means it passed the
health-check; the Dst address block is what step 2 matched. Pair it with
diagnose sys sdwan health-check (the raw latency/jitter/loss behind step 3) and
get router info routing-table all (the candidates from step 1) and you can read
any steering decision top to bottom.
From here: tune SD-WAN rule strategies per application, design the
implicit rule for default traffic, and revisit
overlay vs underlay & zones for the layout the
rules point at. When an overlay member reads dead, drop to the
IPsec Phase 1/2 mismatch
playbook. Back to the Knowledge Base, or browse more
Networking guides.