https://github.com/bobuhiro11/mininetlab の紹介。

bobuhiro11/mininetlab - GitHub

Mininet を使うと単一のマシン上でいくつかのスイッチとホストを動作させることができる。 これを使って仮想的にホストを2つ立ち上げ、その間をFRRパッケージに含まれるBGP(Unnumbered)で接続してみる。 Mininetでは以下のようにPythonでトポロジや各ホストにおけるコマンド実行について記述できる。

一見複雑にみえるFRRもdaemonsvtysh.conffrr.confの3つのファイルを正しく配置しておけば、 frrinit.sh startで簡単に起動できる。 ホストごとにnetnsは分割されているが、mountns は分割されていない(要確認)ため、 /etc/frr/var/run/frrが2つのホスト間で衝突してしまいFRRが正常に起動できなかった。 これは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()

実行方法は以下の通り。 今回示したPythonコードは bgp_unnumbered.py として保存されているとする。 BGPによって192.168.1.XのIPが広報されている。

# 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

ミニマムな構成でFRRの動作を検証できるようになった。 徐々に実践的なネットワーク構成へと拡張させていきたい。 おわり。