01The four moving parts, and the pipeline

Four elements do all the work. Keep them straight and the steering logic is readable:

UnderlayThe transports (ISP1, ISP2, MPLS, LTE). They provide raw reachability to the far end.
OverlayThe tunnels (IPsec/GRE) riding the underlay. These — plus raw WAN interfaces — become SD-WAN members.
ZonesNamed groups of members by role (overlay, underlay). Rules and firewall policies point at zones.
RoutesThe 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 SLAStays in the running — eligible for selection.
alive but SLA breachedDropped from the choice (too much loss/latency/jitter) while any in-SLA member remains.
deadRemoved 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:

ManualUse 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 qualityPick the member with the best measured metric (lowest latency, jitter, or loss). Great for real-time.
Maximize bandwidthLoad-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.