This page explains how GoBGP handles Equal Cost Multipath (ECMP) routes with Zebra daemon included in Quagga or FRRouting.
Assume you finished Getting Started and FIB manipulation.
Note: Before constructing your environment, please confirm your Zebra is built with "--enable-multipath=ARG" configure option. The APT packaged Quagga on Ubuntu 16.04 is configured with this option as following.
$ /usr/lib/quagga/zebra --version
zebra version 0.99.24.1
Copyright 1996-2005 Kunihiro Ishiguro, et al.
configured with:
--build=x86_64-linux-gnu ...(snip)... --enable-multipath=64 ...(snip)...
Here supposes the following topology and demonstrates two ECMP routes which advertised from R2 and R3 are installed to R1's Kernel routing table via Zebra.
R1: GoBGP + Zebra
R2: GoBGP
R3: GoBGP
+-------------+ +-------------+
| R1 | .1/24 .2/24 | R2 |
| ID: 1.1.1.1 |---------------------| ID: 2.2.2.2 |
| AS: 65000 | 192.168.12.0/24 | AS: 65000 |
+-------------+ +-------------+
| .1/24
|
| 192.168.13.0/24
|
| .3/24
+-------------+
| R3 |
| ID: 3.3.3.3 |
| AS: 65000 |
+-------------+
To enables ECMP features at GoBGP on R1, please confirm "use-multiple-paths" option is configured as following. With this option, GoBGP will redistribute BGP multipath routes to Zebra and Zebra will install them into Kernel routing table.
# gobgpd.toml on R1
[global.config]
as = 65000
router-id = "1.1.1.1"
[global.use-multiple-paths.config]
enabled = true
[[neighbors]]
[neighbors.config]
neighbor-address = "192.168.12.2"
peer-as = 65000
[[neighbors.afi-safis]]
[neighbors.afi-safis.config]
afi-safi-name = "ipv4-unicast"
[[neighbors.afi-safis]]
[neighbors.afi-safis.config]
afi-safi-name = "ipv6-unicast"
[[neighbors]]
[neighbors.config]
neighbor-address = "192.168.13.3"
peer-as = 65000
[[neighbors.afi-safis]]
[neighbors.afi-safis.config]
afi-safi-name = "ipv4-unicast"
[[neighbors.afi-safis]]
[neighbors.afi-safis.config]
afi-safi-name = "ipv6-unicast"
[zebra.config]
enabled = true
url = "unix:/var/run/quagga/zserv.api"
redistribute-route-type-list = ["connect"]
version = 2
# gobgpd.toml on R2
[global.config]
as = 65000
router-id = "2.2.2.2"
[[neighbors]]
[neighbors.config]
neighbor-address = "192.168.12.1"
peer-as = 65000
[[neighbors.afi-safis]]
[neighbors.afi-safis.config]
afi-safi-name = "ipv4-unicast"
[[neighbors.afi-safis]]
[neighbors.afi-safis.config]
afi-safi-name = "ipv6-unicast"
# gobgpd.toml on R3
[global.config]
as = 65000
router-id = "3.3.3.3"
[[neighbors]]
[neighbors.config]
neighbor-address = "192.168.13.1"
peer-as = 65000
[[neighbors.afi-safis]]
[neighbors.afi-safis.config]
afi-safi-name = "ipv4-unicast"
[[neighbors.afi-safis]]
[neighbors.afi-safis.config]
afi-safi-name = "ipv6-unicast"
When connections established between each routers, all routers have only "connected" routes from Zebra on R1.
R1> gobgp global rib -a ipv4
Network Next Hop AS_PATH Age Attrs
*> 1.1.1.1/32 0.0.0.0 00:00:00 [{Origin: i} {Med: 0}]
*> 192.168.12.0/24 0.0.0.0 00:00:00 [{Origin: i} {Med: 0}]
*> 192.168.13.0/24 0.0.0.0 00:00:00 [{Origin: i} {Med: 0}]
R2> gobgp global rib -a ipv4
Network Next Hop AS_PATH Age Attrs
*> 1.1.1.1/32 192.168.12.1 00:00:00 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 192.168.12.0/24 192.168.12.1 00:00:00 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 192.168.13.0/24 192.168.12.1 00:00:00 [{Origin: i} {Med: 0} {LocalPref: 100}]
And only these routes are installed on R1's Kernel routing table.
R1> ip route
192.168.12.0/24 dev r1-eth1 proto kernel scope link src 192.168.12.1
192.168.13.0/24 dev r1-eth2 proto kernel scope link src 192.168.13.1
Then, let's add new routes destinated to "10.23.1.0/24" on R2 and R3 routes. These routes should be treated as Multipath routes which have the same cost.
R2> gobgp global rib -a ipv4 add 10.23.1.0/24
R2> gobgp global rib -a ipv4
Network Next Hop AS_PATH Age Attrs
*> 1.1.1.1/32 192.168.12.1 00:10:00 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 10.23.1.0/24 0.0.0.0 00:00:00 [{Origin: ?}]
*> 192.168.12.0/24 192.168.12.1 00:10:00 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 192.168.13.0/24 192.168.12.1 00:10:00 [{Origin: i} {Med: 0} {LocalPref: 100}]
R3> gobgp global rib -a ipv4 add 10.23.1.0/24
R3> gobgp global rib -a ipv4
Network Next Hop AS_PATH Age Attrs
*> 1.1.1.1/32 192.168.13.1 00:10:00 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 10.23.1.0/24 0.0.0.0 00:00:00 [{Origin: ?}]
*> 192.168.12.0/24 192.168.13.1 00:10:00 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 192.168.13.0/24 192.168.13.1 00:10:00 [{Origin: i} {Med: 0} {LocalPref: 100}]
GoBGP on R1 will receive these routes and install them into R1's Kernel routing table via Zebra. The following shows that traffic to "10.23.1.0/24" will be forwarded through the interface r1-eth1 (nexthop is R2) or the interface r1-eth2 (nexthop is R3) with the same weight.
R1> gobgp global rib -a ipv4
Network Next Hop AS_PATH Age Attrs
*> 1.1.1.1/32 0.0.0.0 00:15:00 [{Origin: i} {Med: 0}]
*> 10.23.1.0/24 192.168.12.2 00:05:00 [{Origin: ?} {LocalPref: 100}]
* 10.23.1.0/24 192.168.13.3 00:05:00 [{Origin: ?} {LocalPref: 100}]
*> 192.168.12.0/24 0.0.0.0 00:15:00 [{Origin: i} {Med: 0}]
*> 192.168.13.0/24 0.0.0.0 00:15:00 [{Origin: i} {Med: 0}]
R1> ip route
10.23.1.0/24 proto zebra
nexthop via 192.168.12.2 dev r1-eth1 weight 1
nexthop via 192.168.13.3 dev r1-eth2 weight 1
192.168.12.0/24 dev r1-eth1 proto kernel scope link src 192.168.12.1
192.168.13.0/24 dev r1-eth2 proto kernel scope link src 192.168.13.1