Introducing https://github.com/bobuhiro11/mininetlab.
Using Mininet, you can run several switches and hosts on a single machine. I’ll use this to virtually launch two hosts and connect them via BGP (Unnumbered) included in the FRR package. In Mininet, you can describe the topology and command execution on each host in Python as follows.
Although FRR may seem complex at first glance, if you properly place the three files daemons, vtysh.conf, and frr.conf,
you can easily start it with frrinit.sh start.
While netns is separated for each host, mountns is not separated (needs verification), so
/etc/frr and /var/run/frr collide between the two hosts and FRR couldn’t start properly.
This can be avoided with privateDirs = ['/etc/frr', '/var/run/frr'].
#!/usr/bin/env python
from mininet.net import Mininet
from mininet.log import setLogLevel
import time
frr_conf = '''
hostname {name}
password zebra
!
router bgp {asnum}
bgp router-id {router_id}
bgp bestpath as-path multipath-relax
neighbor h1-eth0 interface remote-as external
neighbor h2-eth0 interface remote-as external
address-family ipv4 unicast
network {router_id}/32
network {network}
exit-address-family
!
line vty
!
end
'''
vtysh_conf = '''
service integrated-vtysh-config
'''
daemons = '''
bgpd=yes
vtysh_enable=yes
zebra_options=" -A 127.0.0.1 -s 90000000"
bgpd_options=" -A 127.0.0.1"
'''
def put_file(host, file_name, content, **kwargs):
with open("/tmp/tmp", mode="w") as f:
f.write(content.format(**kwargs))
host.cmdPrint("cp /tmp/tmp " + file_name)
def run():
setLogLevel('info')
net = Mininet()
privateDirs = ['/etc/frr', '/var/run/frr']
h1 = net.addHost('h1', ip='192.168.0.1/24',
privateDirs=privateDirs, asnum=65001)
h2 = net.addHost('h2', ip='192.168.0.2/24',
privateDirs=privateDirs, asnum=65002)
net.addLink(h1, h2)
net.start()
for i, h in enumerate(net.hosts):
put_file(h, "/etc/frr/daemons", daemons)
put_file(h, "/etc/frr/vtysh.conf", vtysh_conf)
put_file(h, "/etc/frr/frr.conf", frr_conf, name=h.name,
router_id=h.IP(), asnum=h.params['asnum'],
network='192.168.1.{}/32'.format(i+1))
h.cmd("/usr/lib/frr/frrinit.sh start")
h.cmd('ip address add 192.168.1.{}/32 dev {}-eth0'.format(i+1, h.name))
time.sleep(5)
h1.cmdPrint('vtysh -c "show bgp summary"')
h1.cmdPrint('vtysh -c "show ip bgp"')
h1.cmdPrint('ip route')
# send ping in the advertised route
h1.cmdPrint('ping -c 1 192.168.1.2')
net.stop()
return 0
if __name__ == '__main__':
run()
The execution method is as follows.
Assume the Python code shown this time is saved as bgp_unnumbered.py.
The 192.168.1.X IPs are advertised via BGP.
# Assuming Ubuntu 20.04 LTS
$ apt install -y frr
$ git clone git://github.com/mininet/mininet
$ pushd mininet
$ git checkout -b mininet-2.3.0 2.3.0
$ ./util/install.sh -nv
$ popd
$ python bgp_unnumbered.py
*** Configuring hosts
h1 h2
*** Starting controller
*** Starting 0 switches
*** h1 : ('cp /tmp/tmp /etc/frr/daemons',)
*** h1 : ('cp /tmp/tmp /etc/frr/vtysh.conf',)
*** h1 : ('cp /tmp/tmp /etc/frr/frr.conf',)
*** h2 : ('cp /tmp/tmp /etc/frr/daemons',)
*** h2 : ('cp /tmp/tmp /etc/frr/vtysh.conf',)
*** h2 : ('cp /tmp/tmp /etc/frr/frr.conf',)
*** h1 : ('vtysh -c "show bgp summary"',)
IPv4 Unicast Summary:
BGP router identifier 192.168.0.1, local AS number 65001 vrf-id 0
BGP table version 4
RIB entries 7, using 1288 bytes of memory
Peers 2, using 41 KiB of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
h1-eth0 4 65002 5 5 0 0 0 00:00:03 2
h2-eth0 4 0 0 0 0 0 0 never Idle
Total number of neighbors 2
*** h1 : ('vtysh -c "show ip bgp"',)
BGP table version is 4, local router ID is 192.168.0.1, vrf id 0
Default local pref 100, local AS 65001
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
Network Next Hop Metric LocPrf Weight Path
*> 192.168.0.1/32 0.0.0.0 0 32768 i
*> 192.168.0.2/32 h1-eth0 0 0 65002 i
*> 192.168.1.1/32 0.0.0.0 0 32768 i
*> 192.168.1.2/32 h1-eth0 0 0 65002 i
Displayed 4 routes and 4 total paths
*** h1 : ('ip route',)
192.168.0.0/24 dev h1-eth0 proto kernel scope link src 192.168.0.1
192.168.0.2 via 169.254.0.1 dev h1-eth0 proto bgp metric 20 onlink
192.168.1.2 via 169.254.0.1 dev h1-eth0 proto bgp metric 20 onlink
*** h1 : ('ping -c 1 192.168.1.2',)
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.037 ms
--- 192.168.1.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.037/0.037/0.037/0.000 ms
*** Stopping 0 controllers
*** Stopping 1 links
.
*** Stopping 0 switches
*** Stopping 2 hosts
h1 h2
*** Done
Now I can verify FRR operation in a minimal configuration. I’d like to gradually expand it into a more practical network configuration. That’s all.