 Step 1 - HUB: loopbacks and underlay interfaces.
config system interface
  edit "BGP-LO"
    set vdom "root"
    set ip 172.16.255.1 255.255.255.255
    set allowaccess ping
    set type loopback
  next
  edit "HC-LO"
    set vdom "root"
    set ip 10.255.0.1 255.255.255.255
    set allowaccess ping
    set type loopback
  next
  edit "LAN-LO"
    set vdom "root"
    set ip 10.1.0.1 255.255.255.0
    set allowaccess ping
    set type loopback
  next
  edit "port2"
    set ip 10.0.10.1 255.255.255.0
    set allowaccess ping
  next
  edit "port3"
    set ip 10.0.20.1 255.255.255.0
    set allowaccess ping
  next
end
Step 2 - HUB: phase1 (ADVPN sender) and phase2.
config vpn ipsec phase1-interface
  edit "ADVPN-A"
    set type dynamic
    set interface "port2"
    set ike-version 2
    set peertype any
    set net-device disable
    set exchange-ip-addr4 172.16.255.1
    set proposal aes256-sha256
    set add-route disable
    set dpd on-idle
    set dhgrp 14
    set auto-discovery-sender enable
    set auto-discovery-forwarder enable
    set network-overlay enable
    set network-id 10
    set psksecret <PSK>
  next
  edit "ADVPN-B"
    set type dynamic
    set interface "port3"
    set ike-version 2
    set peertype any
    set net-device disable
    set exchange-ip-addr4 172.16.255.1
    set proposal aes256-sha256
    set add-route disable
   set dpd on-idle
    set dhgrp 14
    set auto-discovery-sender enable
   set auto-discovery-forwarder enable
    set network-overlay enable
    set network-id 20
    set psksecret <PSK>
  next
end
config vpn ipsec phase2-interface
  edit "ADVPN-A-P2"
    set phase1name "ADVPN-A"
    set proposal aes256-sha256
    set dhgrp 14
  next
  edit "ADVPN-B-P2"
    set phase1name "ADVPN-B"
    set proposal aes256-sha256
    set dhgrp 14
  next
end
config system interface
  edit "ADVPN-A"
    set ip 169.254.10.1 255.255.255.255
    set remote-ip 169.254.10.254 255.255.255.0
    set allowaccess ping
  next
  edit "ADVPN-B"
    set ip 169.254.20.1 255.255.255.255
    set remote-ip 169.254.20.254 255.255.255.0
    set allowaccess ping
  next
end
Step 3 - HUB: blackhole routes.
config router static
  edit 0
    set dst 172.16.255.0 255.255.255.0
    set blackhole enable
  next
  edit 0
    set dst 10.0.0.0 255.0.0.0
    set blackhole enable
    set distance 254
  next
end
Step 4 - HUB: SD-WAN zone and members.
config system sdwan
  set status enable
    config zone
      edit "ADVPN"
      next
    end
    config members
      edit 1
        set interface "ADVPN-A"
        set zone "ADVPN"
      next
      edit 2
        set interface "ADVPN-B"
        set zone "ADVPN"
      next
    end
  end
Step 5 - HUB: iBGP with neighbor-group and Route Reflector.
config router bgp
  set as 65000
  set router-id 172.16.255.1
  set keepalive-timer 15
  set holdtime-timer 45
  set ibgp-multipath enable
  set recursive-next-hop enable
  set recursive-inherit-priority enable
  set graceful-restart enable
    config neighbor-group
      edit "Spokes"
        set advertisement-interval 1
        set next-hop-self disable
        set soft-reconfiguration enable
        set interface "BGP-LO"
        set remote-as 65000
        set update-source "BGP-LO"
        set route-reflector-client enable
      next
    end
    config neighbor-range
      edit 0
        set prefix 172.16.255.0 255.255.255.0
        set neighbor-group "Spokes"
      next
    end
    config network
      edit 0
        set prefix 172.16.255.0 255.255.255.0
      next
      edit 0
        set prefix 10.255.0.1 255.255.255.255
      next
      edit 0
        set prefix 10.1.0.0 255.255.255.0
      next
      edit 0
        set prefix 10.0.0.0 255.0.0.0
      next
    end
  end
Step 6 - HUB: firewall policies.
config firewall policy
  edit 0
    set name "ADVPN_to_BGP-LO"
    set srcintf "ADVPN"
    set dstintf "BGP-LO"
    set srcaddr "all"
    set dstaddr "all"
    set action accept
    set schedule "always"
    set service "ALL"
  next
  edit 0
    set name "BGP-LO_to_ADVPN"
    set srcintf "BGP-LO"
    set dstintf "ADVPN"
    set srcaddr "all"
    set dstaddr "all"
    set action accept
    set schedule "always"
    set service "ALL"
  next
  edit 0
    set name "ADVPN_to_HC-LO"
    set srcintf "ADVPN"
    set dstintf "HC-LO"
    set srcaddr "all"
    set dstaddr "all"
    set action accept
    set schedule "always"
    set service "ALL"
  next
  edit 0
    set name "ADVPN_to_LAN-LO"
    set srcintf "ADVPN"
    set dstintf "LAN-LO"
    set srcaddr "all"
    set dstaddr "all"
    set action accept
    set schedule "always"
    set service "ALL"
  next
  edit 0
    set name "LAN-LO_to_ADVPN"
    set srcintf "LAN-LO"
    set dstintf "ADVPN"
    set srcaddr "all"
    set dstaddr "all"
    set action accept
    set schedule "always"
    set service "ALL"
  next
  edit 0
    set name "ADVPN_to_ADVPN"
    set srcintf "ADVPN"
    set dstintf "ADVPN"
    set srcaddr "all"
    set dstaddr "all"
    set action accept
    set schedule "always"
    set service "ALL"
  next
end
Step 7 - SPOKE: loopbacks, underlays, phase1 (ADVPN receiver) and phase2.
Replace <spoke-id> with 2 for SPOKE1 and 3 for SPOKE2.
config system interface
  edit "BGP-LO"
    set vdom "root"
    set ip 172.16.255.<spoke-id> 255.255.255.255
    set allowaccess ping
    set type loopback
  next
  edit "LAN-LO"
    set vdom "root"
    set ip 10.<spoke-id>.0.1 255.255.255.0
    set allowaccess ping
    set type loopback
  next
  edit "port2"
    set ip 10.0.10.<spoke-id> 255.255.255.0
    set allowaccess ping
  next
  edit "port3"
    set ip 10.0.20.<spoke-id> 255.255.255.0
    set allowaccess ping
  next
end
config vpn ipsec phase1-interface
  edit "ADVPN-A"
    set interface "port2"
    set ike-version 2
    set peertype any
    set net-device enable
    set exchange-ip-addr4 172.16.255.<spoke-id>
    set proposal aes256-sha256
    set dpd on-idle
    set dhgrp 14
    set auto-discovery-receiver enable
    set auto-discovery-shortcuts dependent
    set network-overlay enable
    set network-id 10
    set remote-gw 10.0.10.1
    set psksecret <PSK>
  next
  edit "ADVPN-B"
    set interface "port3"
    set ike-version 2
    set peertype any
    set net-device enable
    set exchange-ip-addr4 172.16.255.<spoke-id>
    set proposal aes256-sha256
    set dpd on-idle
    set dhgrp 14
    set auto-discovery-receiver enable
    set auto-discovery-shortcuts dependent
    set network-overlay enable
    set network-id 20
    set remote-gw 10.0.20.1
    set psksecret <PSK>
  next
end
config vpn ipsec phase2-interface
  edit "ADVPN-A-P2"
    set phase1name "ADVPN-A"
    set proposal aes256-sha256
    set dhgrp 14
  next
  edit "ADVPN-B-P2"
    set phase1name "ADVPN-B"
    set proposal aes256-sha256
    set dhgrp 14
  next
end
config system interface
  edit "ADVPN-A"
    set ip 169.254.10.<spoke-id> 255.255.255.255
    set remote-ip 169.254.10.1 255.255.255.0
    set allowaccess ping
  next
  edit "ADVPN-B"
    set ip 169.254.20.<spoke-id> 255.255.255.255
    set remote-ip 169.254.20.1 255.255.255.0
    set allowaccess ping
  next
end
Step 8 - SPOKE: blackhole and SD-WAN (zone, members, healthcheck, service rule).
config router static
  edit 0
    set dst 10.0.0.0 255.0.0.0
    set blackhole enable
    set distance 254
  next
end
config system sdwan
  set status enable
    config zone
      edit "ADVPN"
      next
    end
    config members
      edit 1
        set interface "ADVPN-A"
        set zone "ADVPN"
        set priority 1
      next
      edit 2
        set interface "ADVPN-B"
        set zone "ADVPN"
        set priority 2
      next
    end
    config health-check
      edit "HCHub"
        set server "10.255.0.1"
        set members 1 2
        set source 172.16.255.<spoke-id>
          config sla
            edit 1
              set link-cost-factor latency
              set latency-threshold 250
            next
          end
        next
      end
      config service
        edit 1
          set name "ADVPN-SLA"
          set mode sla
          set src "all"
          set dst "all"
            config sla
              edit "HCHub"
                set id 1
              next
            end
          set priority-members 1 2
        next
      end
    end
Step 9 - SPOKE: route-map and BGP.
config router route-map
  edit "FROM_HUB_TAG"
    config rule
      edit 1
        set set-tag 100
      next
    end
  next
end
config router bgp
  set as 65000
  set router-id 172.16.255.<spoke-id>
  set keepalive-timer 15
  set holdtime-timer 45
  set ibgp-multipath enable
  set recursive-next-hop enable
  set graceful-restart enable
  set tag-resolve-mode merge
    config neighbor
      edit "172.16.255.1"
        set advertisement-interval 1
        set soft-reconfiguration enable
        set interface "BGP-LO"
        set remote-as 65000
        set route-map-in "FROM_HUB_TAG"
        set update-source "BGP-LO"
        set connect-timer 1
      next
    end
    config network
      edit 0
        set prefix 172.16.255.<spoke-id> 255.255.255.255
      next
      edit 0
        set prefix 10.<spoke-id>.0.0 255.255.255.0
      next
    end
  end
Step 10 - SPOKE: firewall policies.
config firewall policy
  edit 0
    set name "BGP-LO_to_ADVPN"
    set srcintf "BGP-LO"
    set dstintf "ADVPN"
    set srcaddr "all"
    set dstaddr "all"
    set action accept
    set schedule "always"
    set service "ALL"
  next
  edit 0
    set name "ADVPN_to_BGP-LO"
    set srcintf "ADVPN"
    set dstintf "BGP-LO"
    set srcaddr "all"
    set dstaddr "all"
    set action accept
    set schedule "always"
    set service "ALL"
  next
  edit 0
    set name "ADVPN_to_LAN-LO"
    set srcintf "ADVPN"
    set dstintf "LAN-LO"
    set srcaddr "all"
    set dstaddr "all"
    set action accept
    set schedule "always"
    set service "ALL"
  next
  edit 0
    set name "LAN-LO_to_ADVPN"
    set srcintf "LAN-LO"
    set dstintf "ADVPN"
    set srcaddr "all"
    set dstaddr "all"
    set action accept
    set schedule "always"
    set service "ALL"
  next
end
Verification:
IPsec - three tunnels per spoke (HUB-A, HUB-B, and the auto-formed shortcut).
SPOKE1 # diagnose vpn tunnel list
name=ADVPN-A_0 serial=a 10.0.10.2:0->10.0.10.3:0 tun_id=10.0.10.3 status=up
name=ADVPN-A serial=1 10.0.10.2:0->10.0.10.1:0 tun_id=10.0.10.1 status=up
name=ADVPN-B serial=2 10.0.20.2:0->10.0.20.1:0 tun_id=10.0.20.1 status=up
BGP peering — TCP session loopback <-> loopback.
HUB # get router info bgp neighbors 172.16.255.2
BGP neighbor is 172.16.255.2, remote AS 65000, local AS 65000, internal link
BGP state = Established, up for 03:39:38
Update source is BGP-LO
Local host: 172.16.255.1, Local port: 179
Foreign host: 172.16.255.2, Foreign port: 9403
Nexthop interface: BGP-LO
BGP summary on HUB:
HUB # get router info bgp summary
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
172.16.255.2 4 65000 1007 1013 6 0 0 03:39:35 2
172.16.255.3 4 65000 1005 1007 6 0 0 03:39:35 2
IKE-injected loopback routes (ECMP across both overlays).
HUB # get router info routing-table all | grep 172.16.255
S 172.16.255.2/32 [15/0] via ADVPN-A tunnel 172.16.255.2
[15/0] via ADVPN-B tunnel 10.0.0.3
S 172.16.255.3/32 [15/0] via ADVPN-B tunnel 172.16.255.3
[15/0] via ADVPN-A tunnel 10.0.0.4
Spoke-to-spoke shortcut auto-forms on first inter-spoke flow.
SPOKE1 # execute ping-options source 10.2.0.1
SPOKE1 # execute ping 10.3.0.1
icmp_seq=0 ttl=254 time=10.8 ms <- first packet via HUB
icmp_seq=1 ttl=255 time=2.1 ms <- shortcut formed; direct
icmp_seq=2 ttl=255 time=1.7 ms
icmp_seq=3 ttl=255 time=2.4 ms
TTL goes from 254 to 255 between packets 0 and 1, confirming the HUB hop is gone. Latency ~5× lower.
SD-WAN healthcheck monitoring all paths including the shortcut:
diagnose sys sdwan health-check status
Health Check(HCHub):
Seq(1 ADVPN-A): state(alive) loss(0%) latency(3.5ms) jitter(2.3ms) mos(4.40) sla_map=0x1
Seq(1 ADVPN-A_0): state(alive) loss(0%) latency(3.0ms) jitter(2.8ms) mos(4.40) sla_map=0x1
Seq(2 ADVPN-B): state(alive) loss(0%) latency(2.0ms) jitter(1.6ms) mos(4.40) sla_map=0x1
sla_map=0x1 means SLA #1 (latency < 250 ms) is satisfied on every path, including the auto-formed ADVPN-A_0 shortcut.
Notes:
HUB BGP next-hop-self disable is mandatory for dependent shortcuts to fire. Earlier Fortinet examples show enable; that prevents shortcut formation. exchange-ip-addr4 <own-lo.BGP> in phase1 makes IKE inject /32 routes for peer loopbacks automatically — no manual statics needed. HUB: net-device disable + auto-discovery-sender enable + auto-discovery-forwarder enable. SPOKE: net-device enable + auto-discovery-receiver enable + auto-discovery-shortcuts dependent. Single healthcheck with multiple members (not one per overlay). FortiGate rejects two healthchecks pointing to the same server IP. Output reports each member as a separate Seq() line. Healthcheck names cannot contain hyphens on 7.4.11 (HC-A fails, HCA works). Keep the 172.16.255.0/24 summary advertised by the HUB. The first inter-spoke packet uses it as fallback while the shortcut negotiates; from packet 2 onward traffic goes direct. Firewall policy is required between BGP-LO and the ADVPN zone. Without it, BGP TCP/179 stays in Connect state.
|