SD-WAN service rule selects an unexpected interface in a BGP ECMP loopback deployment
Confirmed 8/8/2026
Problem
In a spoke-to-hub deployment using BGP Equal Cost Multi-Path (ECMP), an SD-WAN service rule can send traffic through a member other than the configured preferred member. The issue occurs when the route has more than eight ECMP outgoing paths.
Symptoms
The SD-WAN service shows all 10 members as alive and selected, and routing details list 10 valid BGP next hops. However, a session for destination 8.8.4.4 uses SD-WAN member 2, `t_hub1-1_121`, instead of the expected member 1, `t_hub1-1_111`. Kernel route output shows that the expected interface is the tenth ECMP entry and is therefore not considered on affected releases.
Environment
FortiGate using SD-WAN with BGP ECMP for spoke-to-hub routing over loopback-based tunnels. The example has 10 SD-WAN members in one service rule and evaluates destination 8.8.4.4/32 in VRF 0.
FortiOS version
Affected versions: null. The limitation is removed in FortiOS v7.2.11 and v7.4.x.
Root Cause
Affected FortiOS releases consider a maximum of eight paths from an ECMP outgoing route when an SD-WAN rule selects an egress interface. Any path appearing ninth or later in the kernel route list is ignored, even if the SD-WAN rule gives that member higher priority. In this example, `t_hub1-1_111` is tenth in the kernel list, so FortiGate selects `t_hub1-1_121`, which is within the first eight paths.
Solution
- Review the SD-WAN service rule and confirm that all intended members are included in the configured priority order. The example rule contains 10 members:
edit 100
set name "BRANCH-MPLS1"
...
set priority-members 1 2 3 4 11 21 22 23 24 31
set tie-break fib-best-match
next
- Check the route for the affected destination. In this example, 8.8.4.4/32 is learned through BGP with 10 ECMP next hops:
FOCLAB # get router info routing details 8.8.4.4
Routing table for VRF=0
Routing entry for 8.8.4.4/32
Known via "bgp", distance 20, metric 0, best
Last update 07:03:11 ago
* vrf 0 10.53.4.2, tag 2 priority 1 (recursive via t_hub2-1_111 tunnel 149.238.64.56), best-match
(recursive via t_hub2-1_211 tunnel 10.0.208.78), best-match
(recursive via t_hub2-1_121 tunnel 10.1.137.109), best-match
(recursive via t_hub2-1_131 tunnel 10.1.137.111), best-match
(recursive via t_hub2-1_141 tunnel 10.1.137.113), best-match
* vrf 0 10.53.4.1, tag 1 priority 1 (recursive via t_hub1-1_111 tunnel 149.238.65.56), best-match
(recursive via t_hub1-1_211 tunnel 10.0.208.82), best-match
(recursive via t_hub1-1_121 tunnel 10.1.137.108), best-match
(recursive via t_hub1-1_131 tunnel 10.1.137.110), best-match
(recursive via t_hub1-1_141 tunnel 10.1.137.112), best-match
- Confirm the SD-WAN member and health-check state. All 10 members in the example are alive and selected:
FOCLAB # diagnose sys sdwan service
Service(100): Address Mode(IPV4) flags=0x200 use-shortcut-sla
Tie break: cfg
Gen(3939), TOS(0x0/0x0), Protocol(0: 1->65535), Mode(sla), sla-compare-order
Service role: standalone
Members(10):
1: Seq_num(1 t_hub1-1_111), alive, sla(0x1), gid(0), cfg_order(0), local cost(10), selected
2: Seq_num(2 t_hub1-1_121), alive, sla(0x1), gid(0), cfg_order(1), local cost(10), selected
3: Seq_num(3 t_hub1-1_131), alive, sla(0x1), gid(0), cfg_order(2), local cost(10), selected
4: Seq_num(4 t_hub1-1_141), alive, sla(0x1), gid(0), cfg_order(3), local cost(10), selected
5: Seq_num(11 t_hub1-1_211), alive, sla(0x1), gid(0), cfg_order(4), local cost(10), selected
6: Seq_num(21 t_hub2-1_111), alive, sla(0x1), gid(0), cfg_order(5), local cost(10), selected
7: Seq_num(22 t_hub2-1_121), alive, sla(0x1), gid(0), cfg_order(6), local cost(10), selected
8: Seq_num(23 t_hub2-1_131), alive, sla(0x1), gid(0), cfg_order(7), local cost(10), selected
9: Seq_num(24 t_hub2-1_141), alive, sla(0x1), gid(0), cfg_order(8), local cost(10), selected
10: Seq_num(31 t_hub2-1_211), alive, sla(0x1), gid(0), cfg_order(9), local cost(10), selected
Src address(1):
0.0.0.0-255.255.255.255
- Inspect the active session to identify the interface index actually selected for the traffic:
FOCLAB # diagnose sys session list
...
orgin->sink: org pre->post, reply pre->post dev=37->431546/431546->37 gwy=10.1.137.108/10.239.88.67
hook=pre dir=org act=noop 10.239.88.67:56608->8.8.4.4:8080(0.0.0.0:0)
hook=post dir=reply act=noop 8.8.4.4:8080->10.239.88.67:56608(0.0.0.0:0
- Map the session interface index to its interface name. Here, index 431546 corresponds to
t_hub1-1_121:
FOCLAB # diagnose netlink interface list
...
if=t_hub1-1_121 family=00 type=768 index=431546 mtu=1420 link=0 master=0
- Display the kernel route and check the order of the ECMP outgoing interfaces. On affected releases, only the first eight entries are considered by the SD-WAN rule:
FOCLAB # diagnose ip route list | grep -A 15 8.8.4.4
tab=254 vf=0 scope=0 type=1 proto=11 prio=1 0.0.0.0/0.0.0.0/0->8.8.4.4/32 pref=0.0.0.0
gwy=10.1.137.113 flag=04 hops=0 oif=431551(t_hub2-1_141)
gwy=10.1.137.111 flag=04 hops=0 oif=431549(t_hub2-1_131)
gwy=10.1.137.109 flag=04 hops=0 oif=431547(t_hub2-1_121)
gwy=10.0.208.78 flag=04 hops=0 oif=47(t_hub2-1_211)
gwy=149.238.64.56 flag=04 hops=0 oif=45(t_hub2-1_111)
gwy=10.1.137.112 flag=04 hops=0 oif=431550(t_hub1-1_141)
gwy=10.1.137.110 flag=04 hops=0 oif=431548(t_hub1-1_131)
gwy=10.1.137.108 flag=04 hops=0 oif=431546(t_hub1-1_121)
gwy=10.0.208.82 flag=04 hops=0 oif=46(t_hub1-1_211) <----- Ignored 9th on the list.
gwy=149.238.65.56 flag=04 hops=0 oif=44(t_hub1-1_111) <----- Ignored 10th on the list.
- If the preferred interface is ninth or later in the kernel ECMP list, upgrade to FortiOS v7.2.11 or a v7.4.x release, where this limitation has been removed.
Verification
After upgrading, repeat the kernel-route, SD-WAN service, and session checks. Confirm that the preferred SD-WAN member is no longer excluded because it appears after the eighth ECMP path and that traffic to 8.8.4.4 uses t_hub1-1_111 when selected by the rule.
Tags
No tags yet.
Community rating
— / 5 (0)
Discussion (0)
No comments yet.