- Get start
- Enable zebra
- Peer group
- Dynamic Neighbor
- Equal Cost Multipath Routing with Zebra
- Unnumbered BGP
- Route reflector
Table of contents generated with markdown-toc
docker run -d --name=b1 --privileged chenchun/gobgp
docker run -d --name=b2 --privileged chenchun/gobgp
docker exec -it b1 bash
cat <<EOF >conf
[global.config]
as = 1
router-id = "172.17.0.2"
EOF
cat <<EOF >start.sh
kill -9 \$(ps aux | grep gobgpd | grep -v grep | awk '{print \$2}')
gobgpd -f conf >> log &
EOF
chmod +x start.sh
./start.sh
exit
docker exec -it b2 bash
cat <<EOF >conf
[global.config]
as = 2
router-id = "172.17.0.3"
EOF
cat <<EOF >start.sh
kill -9 \$(ps aux | grep gobgpd | grep -v grep | awk '{print \$2}')
gobgpd -f conf >> log &
EOF
chmod +x start.sh
./start.sh
exit
docker exec b1 gobgp neighbor add 172.17.0.3 as 2
docker exec b2 gobgp neighbor add 172.17.0.2 as 1
docker exec b1 gobgp neigh
root@e126c8afbf38:~# gobgp neigh
Peer AS Up/Down State |#Received Accepted
172.17.0.3 2 00:00:24 Establ | 0 0
root@e126c8afbf38:~# gobgp global rib
Network not in table
This is because You need to add any routes to it or enable its zebra feature, see osrg/gobgp#1493
root@e126c8afbf38:~# gobgp global rib add 10.33.0.0/16 -a ipv4
root@e126c8afbf38:~#
root@e126c8afbf38:~# gobgp global rib
Network Next Hop AS_PATH Age Attrs
*> 10.33.0.0/16 0.0.0.0 00:00:03 [{Origin: ?}]
Enable zebra
cat <<EOF >conf
[global.config]
as = 2
router-id = "172.17.0.3"
[zebra]
[zebra.config]
enabled = true
url = "unix:/var/run/quagga/zserv.api"
redistribute-route-type-list = ["connect"]
version = 2
EOF
root@99ad08ff8f30:~# gobgp global rib
Network Next Hop AS_PATH Age Attrs
*> 172.17.0.0/16 0.0.0.0 00:00:21 [{Origin: i} {Med: 0}]
* 172.17.0.0/16 172.17.0.2 1 00:00:08 [{Origin: i} {Med: 0}]
With Peer Group, you can set the same configuration to multiple peers. https://github.com/osrg/gobgp/blob/master/docs/sources/peer-group.md
# c1 configuration
[global.config]
as = 1
router-id = "172.17.0.2"
[zebra]
[zebra.config]
enabled = true
url = "unix:/var/run/quagga/zserv.api"
redistribute-route-type-list = ["connect"]
version = 2
[[peer-groups]]
[peer-groups.config]
peer-group-name = "sample-group"
peer-as = 2
[[peer-groups.afi-safis]]
[peer-groups.afi-safis.config]
afi-safi-name = "ipv4-unicast"
[[peer-groups.afi-safis]]
[peer-groups.afi-safis.config]
afi-safi-name = "ipv4-flowspec"
[[neighbors]]
[neighbors.config]
neighbor-address = "172.17.0.3"
peer-group = "sample-group"
[neighbors.timers.config]
hold-time = 99
# c2 container
[global.config]
as = 2
router-id = "172.17.0.3"
[zebra]
[zebra.config]
enabled = true
url = "unix:/var/run/quagga/zserv.api"
redistribute-route-type-list = ["connect"]
version = 2
[[neighbors]]
[neighbors.config]
neighbor-address = "172.17.0.2"
Dynamic Neighbor enables GoBGP to accept connections from the peers in specific prefix. Note that GoBGP will be passive mode to members of dynamic neighbors. So if both peers listen to each other as dynamic neighbors, the connection will never be established.
# r1
[global.config]
as = 1
router-id = "172.17.0.2"
[[peer-groups]]
[peer-groups.config]
peer-group-name = "sample-group"
peer-as = 2
[[peer-groups.afi-safis]]
[peer-groups.afi-safis.config]
afi-safi-name = "ipv4-unicast"
[[peer-groups.afi-safis]]
[peer-groups.afi-safis.config]
afi-safi-name = "ipv4-flowspec"
[[dynamic-neighbors]]
[dynamic-neighbors.config]
prefix = "172.17.0.0/16"
peer-group = "sample-group"
# r2
[global.config]
as = 2
router-id = "172.17.0.3"
[[neighbors]]
[neighbors.config]
neighbor-address = "172.17.0.2"
How GoBGP handles Equal Cost Multipath (ECMP) routes with Zebra daemon included in Quagga
docker run -d --name=r1 --privileged --hostname=r1 chenchun/gobgp #172.17.0.2/16
docker run -d --name=r2 --privileged --hostname=r2 chenchun/gobgp #172.17.0.3/16
docker run -d --name=r3 --privileged --hostname=r3 chenchun/gobgp #172.17.0.4/16
docker network create -d bridge bridge2
docker network ls
NETWORK ID NAME DRIVER SCOPE
6f9ccd10f670 bridge bridge local
94136127c737 bridge2 bridge local
f277d3e5024a host host local
9ca05ce2e370 none null local
docker network connect bridge2 r1
docker network connect bridge2 r3
docker network disconnect bridge r3
R1: GoBGP + Zebra
R2: GoBGP
R3: GoBGP
+-------------+ +-------------+
| R1 | .2/16 .3/16 | R2 |
| ID: 1.1.1.1 |---------------------| ID: 2.2.2.2 |
| AS: 65000 | 172.17.0.0/16 | AS: 65000 |
+-------------+ +-------------+
| .2/16
|
| 172.18.0.0/16
|
| .3/16
+-------------+
| R3 |
| ID: 3.3.3.3 |
| AS: 65000 |
+-------------+
r1-r3 conf
# 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 = "172.17.0.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"
[[neighbors]]
[neighbors.config]
neighbor-address = "172.18.0.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 = "172.17.0.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"
# gobgpd.toml on R3
[global.config]
as = 65000
router-id = "3.3.3.3"
[[neighbors]]
[neighbors.config]
neighbor-address = "172.18.0.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"
start each one, wait for established, check rib and linux route
root@r1:~# gobgp global rib -a ipv4
Network Next Hop AS_PATH Age Attrs
*> 172.17.0.0/16 0.0.0.0 00:01:32 [{Origin: i} {Med: 0}]
*> 172.18.0.0/16 0.0.0.0 00:01:32 [{Origin: i} {Med: 0}]
root@r1:~# ip route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
172.18.0.0/16 dev eth1 proto kernel scope link src 172.18.0.2
root@r2:~# gobgp global rib -a ipv4
Network Next Hop AS_PATH Age Attrs
*> 172.17.0.0/16 172.17.0.2 00:01:21 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 172.18.0.0/16 172.17.0.2 00:01:21 [{Origin: i} {Med: 0} {LocalPref: 100}]
root@r2:~# ip route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3
root@r3:~# gobgp global rib -a ipv4
Network Next Hop AS_PATH Age Attrs
*> 172.17.0.0/16 172.18.0.2 00:01:21 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 172.18.0.0/16 172.18.0.2 00:01:21 [{Origin: i} {Med: 0} {LocalPref: 100}]
root@r3:~# ip route
default via 172.18.0.1 dev eth1
172.18.0.0/16 dev eth1 proto kernel scope link src 172.18.0.3
add rib on r2, check rib and linux route
root@r2:~# gobgp global rib -a ipv4 add 10.23.1.0/24
root@r1:~# gobgp global rib
Network Next Hop AS_PATH Age Attrs
*> 10.23.1.0/24 172.17.0.3 00:01:14 [{Origin: ?} {LocalPref: 100}]
*> 172.17.0.0/16 0.0.0.0 00:05:49 [{Origin: i} {Med: 0}]
*> 172.18.0.0/16 0.0.0.0 00:05:49 [{Origin: i} {Med: 0}]
root@r1:~# ip r
default via 172.17.0.1 dev eth0
10.23.1.0/24 via 172.17.0.3 dev eth0 proto zebra
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
172.18.0.0/16 dev eth1 proto kernel scope link src 172.18.0.2
root@r2:~# gobgp global rib
Network Next Hop AS_PATH Age Attrs
*> 10.23.1.0/24 0.0.0.0 00:01:14 [{Origin: ?}]
*> 172.17.0.0/16 172.17.0.2 00:05:38 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 172.18.0.0/16 172.17.0.2 00:05:38 [{Origin: i} {Med: 0} {LocalPref: 100}]
root@r2:~# ip r
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3
root@r3:~# gobgp global rib
Network Next Hop AS_PATH Age Attrs
*> 172.17.0.0/16 172.18.0.2 00:05:38 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 172.18.0.0/16 172.18.0.2 00:05:38 [{Origin: i} {Med: 0} {LocalPref: 100}]
root@r3:~# ip r
default via 172.18.0.1 dev eth1
172.18.0.0/16 dev eth1 proto kernel scope link src 172.18.0.3
add rib on r3, check rib and linux route. 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 eth0 (nexthop is R2) or the interface eth1 (nexthop is R3) with the same weight.
root@r3:~# gobgp global rib -a ipv4 add 10.23.1.0/24
root@r1:~# gobgp global rib
Network Next Hop AS_PATH Age Attrs
*> 10.23.1.0/24 172.17.0.3 00:02:41 [{Origin: ?} {LocalPref: 100}]
* 10.23.1.0/24 172.18.0.3 00:00:20 [{Origin: ?} {LocalPref: 100}]
*> 172.17.0.0/16 0.0.0.0 00:07:16 [{Origin: i} {Med: 0}]
*> 172.18.0.0/16 0.0.0.0 00:07:16 [{Origin: i} {Med: 0}]
root@r1:~# ip r
default via 172.17.0.1 dev eth0
10.23.1.0/24 proto zebra
nexthop via 172.17.0.3 dev eth0 weight 1
nexthop via 172.18.0.3 dev eth1 weight 1
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
172.18.0.0/16 dev eth1 proto kernel scope link src 172.18.0.2
root@r2:~# gobgp global rib
Network Next Hop AS_PATH Age Attrs
*> 10.23.1.0/24 0.0.0.0 00:02:41 [{Origin: ?}]
*> 172.17.0.0/16 172.17.0.2 00:07:05 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 172.18.0.0/16 172.17.0.2 00:07:05 [{Origin: i} {Med: 0} {LocalPref: 100}]
root@r2:~# ip r
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3
root@r3:~# gobgp global rib
Network Next Hop AS_PATH Age Attrs
*> 10.23.1.0/24 0.0.0.0 00:00:20 [{Origin: ?}]
*> 172.17.0.0/16 172.18.0.2 00:07:05 [{Origin: i} {Med: 0} {LocalPref: 100}]
*> 172.18.0.0/16 172.18.0.2 00:07:05 [{Origin: i} {Med: 0} {LocalPref: 100}]
root@r3:~# ip r
default via 172.18.0.1 dev eth1
172.18.0.0/16 dev eth1 proto kernel scope link src 172.18.0.3
BGP is not only for the Internet. Due to proven scalability and configuration flexibility, large data center operators are using BGP for their data center networking [ietf-rtgwg-bgp-routing-large-dc].
In typical case, the topology of the network is CLOS network which can offer multiple ECMP for ToR switches. Each ToR switches run BGP daemon and peer to uplink switches connected with P2P link.
In this case, since all switches are operated by single administrator and trusted, we can skip tedious neighbor configurations like specifying neighbor address or neighbor AS number by using unnumbered BGP feature.
Unnumbered BGP utilizes IPv6 link local address to automatically decide who to connect. Also, when using unnumbered BGP, you don't need to specify neighbor AS number. GoBGP will accept any AS number in the neighbor's open message.
To use unnumbered BGP feature, be sure the link between two BGP daemons is P2P and IPv6 is enabled on interfaces connected to the link.
Also, check neighbor's IPv6 link local address is on the linux's neighbor table.
$ ip -6 neigh show
fe80::42:acff:fe11:5 dev eth0 lladdr 02:42:ac:11:00:05 REACHABLE
If neighbor's address doesn't exist, easiest way to fill the table is ping6
.
Try the command below
$ ping6 -c 1 ff02::1%eth0
PING ff02::1%eth0 (ff02::1%eth0): 56 data bytes
64 bytes from fe80::42:acff:fe11:5%eth0: icmp_seq=0 ttl=64 time=0.312 ms
--- ff02::1%eth0 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.312/0.312/0.312/0.000 ms
More reliable method is to run radvd or zebra to periodically send router advertisement.
docker run --name=r1 -d --hostname=r1 --privileged --net=none gobgp
docker run --name=r2 -d --hostname=r2 --privileged --net=none gobgp
ip link add v1 type veth peer name v2
pid1=$(docker inspect -f {{.State.Pid}} r1)
pid2=$(docker inspect -f {{.State.Pid}} r2)
mkdir -p /var/run/netns/
touch /var/run/netns/r1
touch /var/run/netns/r2
mount --bind /proc/$pid1/ns/net /var/run/netns/r1
mount --bind /proc/$pid2/ns/net /var/run/netns/r2
ip link set v1 netns r1
ip link set v2 netns r2
ip netns exec r1 ip link set v1 name eth0
ip netns exec r2 ip link set v2 name eth0
ip netns exec r1 ip link set eth0 up
ip netns exec r2 ip link set eth0 up
ip netns exec r1 ip ad add 192.168.0.1/24 dev eth0
ip netns exec r2 ip ad add 192.168.0.2/24 dev eth0
docker exec -it r1 bash
echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6
docker exec -it r2 bash
echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6
docker exec -it r1 bash
ping6 -c 1 ff02::1%eth0
ip -6 neigh show
root@r1:~# cat conf
[global.config]
as = 1
router-id = "192.168.0.1"
[[neighbors]]
[neighbors.config]
neighbor-interface = "eth0"
root@r2:~# cat conf
[global.config]
as = 2
router-id = "192.168.0.2"
[[neighbors]]
[neighbors.config]
neighbor-interface = "eth0"
for i in $(seq 1 5); do docker run -d --name=r$i --privileged --hostname=r$i chenchun/gobgp; done
root@ramichen:/home/ramichen/project/go/src/github.com/osrg/gobgp# cat setup.sh
cat <<EOF >start.sh
#!/bin/bash
kill -9 \$(ps aux | grep gobgpd | grep -v grep | awk '{print \$2}') 2>/dev/null
nohup /go/bin/gobgpd -f conf >> log
EOF
chmod +x start.sh
cat <<EOF >conf1
[global.config]
router-id = "172.17.0.2"
as = 65000
[[neighbors]]
[neighbors.config]
neighbor-address = "172.17.0.3"
peer-as = 65000
[neighbors.route-reflector.config]
route-reflector-client = true
route-reflector-cluster-id = "172.17.0.2"
[[neighbors]]
[neighbors.config]
neighbor-address = "172.17.0.4"
peer-as = 65000
[neighbors.route-reflector.config]
route-reflector-client = true
route-reflector-cluster-id = "172.17.0.2"
[[neighbors]]
[neighbors.config]
neighbor-address = "172.17.0.4"
peer-as = 65000
[neighbors.route-reflector.config]
route-reflector-client = true
route-reflector-cluster-id = "172.17.0.2"
[[neighbors]]
[neighbors.config]
neighbor-address = "172.17.0.5"
peer-as = 65000
[[neighbors]]
[neighbors.config]
neighbor-address = "172.17.0.6"
peer-as = 65000
EOF
for i in $(seq 2 5); do
cat <<EOF >conf$i
[global.config]
as = 65000
router-id = "172.17.0.$((i + 1))"
[[neighbors]]
[neighbors.config]
neighbor-address = "172.17.0.2"
peer-as = 65000
EOF
done
for i in $(seq 1 5); do
echo starting r$i
docker cp conf$i r$i:/root/conf
docker cp start.sh r$i:/root
rm conf$i
docker exec -d r$i bash -c /root/start.sh
done
sleep 2
docker exec r1 gobgp neigh
# setup.sh file end -----------
for i in $(seq 1 5); do docker exec r$i gobgp global rib add 10.0.$((i + 1)).0/24 -a ipv4; done
root@ramichen:/home/ramichen/project/go/src/github.com/osrg/gobgp# docker exec r1 gobgp neigh 172.17.0.5 adj-out
ID Network Next Hop AS_PATH Attrs
1 10.0.2.0/24 172.17.0.2 [{Origin: ?} {LocalPref: 100}]
1 10.0.3.0/24 172.17.0.3 [{Origin: ?} {LocalPref: 100}]
1 10.0.4.0/24 172.17.0.4 [{Origin: ?} {LocalPref: 100}]
root@ramichen:/home/ramichen/project/go/src/github.com/osrg/gobgp# docker exec r1 gobgp neigh 172.17.0.4 adj-out
ID Network Next Hop AS_PATH Attrs
1 10.0.2.0/24 172.17.0.2 [{Origin: ?} {LocalPref: 100} {Originator: 172.17.0.2} {ClusterList: [172.17.0.2]}]
1 10.0.3.0/24 172.17.0.3 [{Origin: ?} {LocalPref: 100} {Originator: 172.17.0.3} {ClusterList: [172.17.0.2]}]
1 10.0.5.0/24 172.17.0.5 [{Origin: ?} {LocalPref: 100} {Originator: 172.17.0.5} {ClusterList: [172.17.0.2]}]
1 10.0.6.0/24 172.17.0.6 [{Origin: ?} {LocalPref: 100} {Originator: 172.17.0.6} {ClusterList: [172.17.0.2]}]
# clean up
for i in $(seq 1 5); do docker rm -vf r$i; done