Introduction:
Border Gateway Protocol (BGP) is a mainstay in enterprise networks and has many features allowing for granular control of route advertisement, route reception and route manipulation. This granular control makes it possible for a network engineer to achieve almost any routing scenario they might conceive.
One such scenario might be to only advertise a route or routes if a certain condition is met. That is what this article will be covering. We'll leverage Fortinet's FortiGate (FGT) firewalls and configure the "conditional-advertise" feature to make it happen.
This article is divided into 3 sections:
Solution Overview
Implementation
Test and verification
Let's dive in.
Solution Overview:
Below is a diagram of the environment we'll be using in this example. We will leverage 3x FGT VMs running FortiOS version 7.4.0. Each FGT will have 3 interfaces: port1 for management, port2 and port3 for BGP peering. Only FGT 2 will use all 3 interfaces.
The first FGT (bgp-cond1) will mimic what might be an ISP router advertising a default route. The second FGT (bgp-cond2) will mimic the enterprise router peering with the ISP and receiving the default route. The third FGT (bgp-cond3) will mimic an internal router that has a default route pointing to an interface other than the interface peering with bgp-cond2.
In this setup, bgp-cond3 would normally be sending traffic between port2 and port4, but with the conditional-advertise feature on bgp-cond2, we will send a route to bgp-cond3 to attract that specific traffic only when our conditions are met. In this case that condition is the existence of a default route learned by bgp-cond2 from bgp-cond1.
We will be running this on a Proxmox server where all interfaces/networks are internal to the Proxmox server except for port1 of each FGT which is connected to a physical interface and used for management of the FGTs. If you'd like to know more about Proxmox and how to setup this lab or any others, then let me know with a comment.
Implementation:
bgp-cond1
The first thing I like to do is set my hostnames, timezone and in the lab set the admin timeout to 480 (8hrs).
config system global
set admintimeout 480
set hostname "bgp-cond1"
set timezone 12
end
Next, let's setup our interfaces. I am using port1 for my management and like to put it into a separate VRF. This isn't required but can help to avoid routing issues. The physical ports were described above. Note that the below configuration is additive to the defaults, so there are some things like "allowaccess" on port1 that are already in the default config and so they are explicitly called out here. This helps to reduce the clutter.
config system interface
edit "port1"
set mode static
set vrf 31
set ip 172.16.100.221/24
set allowaccess ping https ssh http fgfm
set description "Out of Band Management"
next
edit "port2"
set ip 10.255.10.0/31
set description "bgp-cond2 Connection"
next
end
Define your static route for management purposes if needed. BGP will take care of generating the default route needed in this design.
config router static
edit 100
set gateway 172.16.100.1
set device "port1"
next
end
Configure BGP by setting your AS, router-id, features and your neighbor configuration for bgp-cond2. The important piece here is to set the "capability-default-originate enable" line as this will create the advertisement of a default route to our neighbor. The other bits may be different based on your setup.
config router bgp
set as 65001
set router-id 10.255.20.1
config neighbor
edit "10.255.10.1"
set capability-default-originate enable
set next-hop-self enable
set soft-reconfiguration enable
set remote-as 65002
next
end
end
That should be all for bgp-cond1
bgp-cond2
Again, start with your hostname and other desired settings
config system global
set admintimeout 480
set hostname "bgp-cond2"
set timezone 12
end
Setup your interfaces with port1 for management, port2 for the connection to bgp-cond1 and port3 for the connection to bgp-cond3
config system interface
edit "port1"
set mode static
set vrf 31
set ip 172.16.100.222/24
set allowaccess ping https ssh http fgfm
set description "Out of Band Management"
next
edit "port2"
set ip 10.255.10.1/31
set description "bgp-cond1 Connection"
next
edit "port3"
set ip 10.255.10.2/31
set description "bgp-cond3 Connection"
next
end
Define your static route for management purposes if needed. BGP will take care of the other routes
config router static
edit 100
set gateway 172.16.100.1
set device "port1"
next
end
Prefix lists are used as objects in the route maps we will be creating and using in BGP. Let's define a prefix list named "DEFAULT_ROUTE" for the default route and a prefix list named "COND_ROUTES" for the routes we want to conditionally advertise.
config router prefix-list
edit "DEFAULT_ROUTE"
config rule
edit 0
set prefix 0.0.0.0 0.0.0.0
unset ge
unset le
next
end
next
edit "COND_ROUTES"
config rule
edit 0
set prefix 10.255.101.0 255.255.255.0
unset ge
unset le
next
edit 0
set prefix 10.255.103.0 255.255.255.0
unset ge
unset le
next
edit 0
set prefix 10.255.105.0 255.255.255.0
unset ge
unset le
next
end
next
end
The route maps are used to reference the prefix lists and manipulate the routes advertised or received, as needed. Here we create "COND_RM" to identify our prefixes to remove from advertisement when our criteria (conditions) are met. We could do the opposite with an adjustment in the BGP neighbor config we'll cover in a moment. We create "DEFAULT_ONLY" to match the default route from bgp-cond1 and we'll use this to control what routes we are receiving from bgp-cond1. Finally, we create "NoDefault" to define what we will normally advertise to bgp-cond3. In this case, we do not want the default route advertised to bgp-cond3 because it doesn't need the route. That's why you see the "set action deny" statement in the configuration. We do want the "COND_ROUTES" to be advertised normally and there is an implied "accept" statement there in the first rule.
Note that you can do a number of things with route maps, but we are just going over what's minimally needed for this scenario.
config router route-map
edit "COND_RM"
config rule
edit 0
set match-ip-address "COND_ROUTES"
next
end
next
edit "DEFAULT_ONLY"
config rule
edit 0
set match-ip-address "DEFAULT_ROUTE"
next
end
next
edit "NoDefault"
config rule
edit 0
set match-ip-address "COND_ROUTES"
next
edit 0
set action deny
set match-ip-address "DEFAULT_ROUTE"
next
end
next
end
In the BGP configuration we set our AS number as required and optionally set the router-id.
The neighbor configured as "10.255.10.0" is bgp-cond1 and we set the remote-as to match the AS of bgp-cond1 signaling to FortiOS that this is an EBGP neighbor. The route-map-in statement chooses the DEFAULT_ONLY route map we defined previously so that we only accept a default route even if bgp-cond1 is advertising other routes as well.
For the "10.255.10.3" neighbor, we use the same AS setting but this time we use a route-map-out statement to control what routes we are advertising. Now we get to the meat of the subject and set the conditional advertisement configuration. With the "config conditional-advertise" stanza we tell FortiOS which routes to manipulate from our route-map-out statement above. Here we have identified the "COND-RM" route-map as the interesting routes to add/remove from our advertisement with the "edit" command. Then we set the condition to "condition-type exist" so that the routes matched in "COND_RM" will be advertised when the route map "DEFAULT_ONLY" is true. We could reverse the behavior by setting the contition to "non-exist".
Finally, we set our network statements in BGP as a requirement for the advertisements.
There is one more configuration that you could do at the top of the BGP configuration and that is to disable the "network-import-check" feature. Normally, FortiOS would need a route in the table before advertising networks in the "network statements" section, but this command removes that requirement. It is safest to not use this feature but it is handy for lab environments. As it is, we'll just move on with the static routes to fulfull the requirement properly.
config router bgp
set as 65002
set router-id 10.255.20.2
config neighbor
edit "10.255.10.0"
set soft-reconfiguration enable
set remote-as 65001
set route-map-in "DEFAULT_ONLY"
next
edit "10.255.10.3"
set next-hop-self enable
set soft-reconfiguration enable
set remote-as 65003
set route-map-out "NoDefault"
config conditional-advertise
edit "COND_RM"
set condition-routemap "DEFAULT_ONLY"
next
end
next
end
config network
edit 0
set prefix 10.255.101.0 255.255.255.0
next
edit 0
set prefix 10.255.103.0 255.255.255.0
next
edit 0
set prefix 10.255.105.0 255.255.255.0
next
end
end
As mentioned, we need to create some static routes so that our networks defined in BGP will be advertised. We'll use "blackhole" routes so we don't need a next-hop that could go down.
config router static
edit 0
set dst 10.255.101.0 255.255.255.0
set blackhole enable
next
edit 0
set dst 10.255.103.0 255.255.255.0
set blackhole enable
next
edit 0
set dst 10.255.105.0 255.255.255.0
set blackhole enable
next
end
bgp-cond3
There’s nothing special about the configuration for bgp-cond3 so I’m just going to paste it all together here:
config system global
set admintimeout 480
set hostname "bgp-cond3"
set timezone 12
end
config system interface
edit "port1"
set mode static
set vrf 31
set ip 172.16.100.223/24
set allowaccess ping https ssh http fgfm
set description "Out of Band Management"
next
edit "port3"
set ip 10.255.10.3/31
set description "bgp-cond2 Connection"
next
end
config router static
edit 100
set gateway 172.16.100.1
set device "port1"
next
end
config router bgp
set as 65003
set router-id 10.255.20.3
config neighbor
edit "10.255.10.2"
set next-hop-self enable
set soft-reconfiguration enable
set remote-as 65002
next
end
end
Test and Verification:
Let's run through the routing tables of each router while the default route does exist and therefore the defined condition is true.
Below you'll see that on bgp-cond1 we are receiving to routes from bgp-cond2 because there is no route-map/filter to stop the advertisement. Ideally you would apply a route-map-out filter on bgp-cond2 in the neighbor configuration for bgp-cond1 to avoid this. Notice that in VRF0 there is no default route. That route generation is taken care of in the BGP configuration with the "set capability-default-originate enable" statement.
bgp-cond1 # get router info routing-table all
Codes: K - kernel, C - connected, S - static, R - RIP, B - BGP
O - OSPF, IA - OSPF inter area
N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
E1 - OSPF external type 1, E2 - OSPF external type 2
i - IS-IS, L1 - IS-IS level-1, L2 - IS-IS level-2, ia - IS-IS inter area
V - BGP VPNv4
* - candidate default
Routing table for VRF=0
C 10.255.10.0/31 is directly connected, port2
C 10.255.20.1/32 is directly connected, loopback1
B 10.255.101.0/24 [20/0] via 10.255.10.1 (recursive is directly connected, port2), 06:58:54, [1/0]
B 10.255.103.0/24 [20/0] via 10.255.10.1 (recursive is directly connected, port2), 06:58:54, [1/0]
B 10.255.105.0/24 [20/0] via 10.255.10.1 (recursive is directly connected, port2), 06:58:54, [1/0]
Routing table for VRF=31
S* 0.0.0.0/0 [10/0] via 172.16.100.1, port1, [1/0]
C 172.16.100.0/24 is directly connected, port1
For bgp-cond2 the VRF0 table has the default route from bgp-cond1 but no other BGP routes.
bgp-cond2 # get router info routing-table all
Codes: K - kernel, C - connected, S - static, R - RIP, B - BGP
O - OSPF, IA - OSPF inter area
N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
E1 - OSPF external type 1, E2 - OSPF external type 2
i - IS-IS, L1 - IS-IS level-1, L2 - IS-IS level-2, ia - IS-IS inter area
V - BGP VPNv4
* - candidate default
Routing table for VRF=0
B* 0.0.0.0/0 [20/0] via 10.255.10.0 (recursive is directly connected, port2), 06:24:21, [1/0]
C 10.255.10.0/31 is directly connected, port2
C 10.255.10.2/31 is directly connected, port3
C 10.255.20.2/32 is directly connected, loopback1
Routing table for VRF=31
S* 0.0.0.0/0 [10/0] via 172.16.100.1, port1, [1/0]
C 172.16.100.0/24 is directly connected, port1
Also on bgp-cond2 we can see that we are advertising the 3 prefixes defined to bgp-cond3
bgp-cond2 # get router info bgp neighbors 10.255.10.3 advertised-routes
VRF 0 BGP table version is 12, local router ID is 10.255.20.2
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight RouteTag Path
*> 10.255.101.0/24 10.255.10.2 100 32768 0 i <-/->
*> 10.255.103.0/24 10.255.10.2 100 32768 0 i <-/->
*> 10.255.105.0/24 10.255.10.2 100 32768 0 i <-/->
Total number of prefixes 3
On bgp-cond3 we can see the 3 BGP prefixes and not the default route from bgp-cond2 because of the route-map that prevented advertisement of the default route.
bgp-cond3 # get router info routing-table all
Codes: K - kernel, C - connected, S - static, R - RIP, B - BGP
O - OSPF, IA - OSPF inter area
N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
E1 - OSPF external type 1, E2 - OSPF external type 2
i - IS-IS, L1 - IS-IS level-1, L2 - IS-IS level-2, ia - IS-IS inter area
V - BGP VPNv4
* - candidate default
Routing table for VRF=0
C 10.255.10.2/31 is directly connected, port3
C 10.255.20.3/32 is directly connected, loopback1
B 10.255.101.0/24 [20/0] via 10.255.10.2 (recursive is directly connected, port3), 06:27:40, [1/0]
B 10.255.103.0/24 [20/0] via 10.255.10.2 (recursive is directly connected, port3), 06:27:40, [1/0]
B 10.255.105.0/24 [20/0] via 10.255.10.2 (recursive is directly connected, port3), 06:27:40, [1/0]
Routing table for VRF=31
S* 0.0.0.0/0 [10/0] via 172.16.100.1, port1, [1/0]
C 172.16.100.0/24 is directly connected, port1
Now we will remove the "set capability-default-originate enable" statement from bgp-cond1 and see how things change
bgp-cond1 # config router bgp
bgp-cond1 (bgp) # config neighbor
bgp-cond1 (neighbor) # edit 10.255.10.1
bgp-cond1 (10.255.10.1) # unset capability-default-originate
bgp-cond1 (10.255.10.1) # next
bgp-cond1 (neighbor) #
bgp-cond2 # get router info routing-table all
Codes: K - kernel, C - connected, S - static, R - RIP, B - BGP
O - OSPF, IA - OSPF inter area
N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
E1 - OSPF external type 1, E2 - OSPF external type 2
i - IS-IS, L1 - IS-IS level-1, L2 - IS-IS level-2, ia - IS-IS inter area
V - BGP VPNv4
* - candidate default
Routing table for VRF=0
C 10.255.10.0/31 is directly connected, port2
C 10.255.10.2/31 is directly connected, port3
C 10.255.20.2/32 is directly connected, loopback1
Routing table for VRF=31
S* 0.0.0.0/0 [10/0] via 172.16.100.1, port1, [1/0]
C 172.16.100.0/24 is directly connected, port1
bgp-cond2 # get router info bgp neighbors 10.255.10.3 advertised-routes
% No prefix for neighbor 10.255.10.3
bgp-cond3 # get router info routing-table all
Codes: K - kernel, C - connected, S - static, R - RIP, B - BGP
O - OSPF, IA - OSPF inter area
N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
E1 - OSPF external type 1, E2 - OSPF external type 2
i - IS-IS, L1 - IS-IS level-1, L2 - IS-IS level-2, ia - IS-IS inter area
V - BGP VPNv4
* - candidate default
Routing table for VRF=0
C 10.255.10.2/31 is directly connected, port3
C 10.255.20.3/32 is directly connected, loopback1
Routing table for VRF=31
S* 0.0.0.0/0 [10/0] via 172.16.100.1, port1, [1/0]
C 172.16.100.0/24 is directly connected, port1
Success! We can see that the 3 BGP prefixes are no longer advertised when the default route is removed.
Conclusion:
I hope this has been helpful and that you learned something new. There are many variations on this exercise and every situation has different requirements. With this information you should be able to tackle more complex configurations going forward. Let me know in the comments if you have any questions or if there are any other topics you'd like me to cover.