]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgp_vrf_netns: add basic test to support netns backend with netns
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 31 Jan 2018 10:04:02 +0000 (11:04 +0100)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 28 Nov 2018 01:22:13 +0000 (20:22 -0500)
The test consist in starting a BGP router on a NETNS, and interacting
with an exaBGP instance. The test automatically relies on VRF with netns
backend but can be easily configured so as to perform basic BGP VRF
testing with VRF with VRF-lite backend.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
12 files changed:
tests/topotests/bgp_vrf_netns/__init__.py [new file with mode: 0644]
tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.dot [new file with mode: 0644]
tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.pdf [new file with mode: 0644]
tests/topotests/bgp_vrf_netns/exabgp.env [new file with mode: 0644]
tests/topotests/bgp_vrf_netns/peer1/exa-receive.py [new file with mode: 0755]
tests/topotests/bgp_vrf_netns/peer1/exa-send.py [new file with mode: 0755]
tests/topotests/bgp_vrf_netns/peer1/exabgp.cfg [new file with mode: 0644]
tests/topotests/bgp_vrf_netns/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_vrf_netns/r1/summary.txt [new file with mode: 0644]
tests/topotests/bgp_vrf_netns/r1/summary20.txt [new file with mode: 0644]
tests/topotests/bgp_vrf_netns/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py [new file with mode: 0755]

diff --git a/tests/topotests/bgp_vrf_netns/__init__.py b/tests/topotests/bgp_vrf_netns/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.dot b/tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.dot
new file mode 100644 (file)
index 0000000..2b1f72b
--- /dev/null
@@ -0,0 +1,50 @@
+## Color coding:
+#########################
+##  Main FRR: #f08080  red
+##  Switches: #d0e0d0  gray
+##  RIP:      #19e3d9  Cyan
+##  RIPng:    #fcb314  dark yellow
+##  OSPFv2:   #32b835  Green
+##  OSPFv3:   #19e3d9  Cyan
+##  ISIS IPv4 #fcb314  dark yellow
+##  ISIS IPv6 #9a81ec  purple
+##  BGP IPv4  #eee3d3  beige
+##  BGP IPv6  #fdff00  yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph bgp_vrf_netns_eBGP_topo1 {
+       label="bgp vrf netns topo1 - eBGP with different AS numbers";
+    labelloc="t";
+
+       # Routers
+       r1 [
+               label="r1\nrtr-id 10.0.255.1/32",
+               shape=doubleoctagon,
+               fillcolor="#f08080",
+               style=filled,
+       ];
+
+       # 1 Switch for eBGP Peers
+       s1 [
+               label="s1\n10.0.1.0/24",
+               shape=oval,
+               fillcolor="#d0e0d0",
+               style=filled,
+       ];
+
+       # 1 ExaBGP Peers AS 101
+       peer1 [
+               label="eBGP peer1\nAS101\nrtr-id 10.0.1.101/32",
+               shape=rectangle,
+               fillcolor="#eee3d3",
+               style=filled,
+       ];
+
+       # Connections
+       r1 -- s1 [label="eth0\n.1"];
+
+       peer1 -- s1 [label="eth0\n.101"];
+
+       # Arrange network to make cleaner diagram
+       { rank=same peer1 } -- s1 -- { rank=same r1 } [style=invis]
+}
diff --git a/tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.pdf b/tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.pdf
new file mode 100644 (file)
index 0000000..6da2288
Binary files /dev/null and b/tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.pdf differ
diff --git a/tests/topotests/bgp_vrf_netns/exabgp.env b/tests/topotests/bgp_vrf_netns/exabgp.env
new file mode 100644 (file)
index 0000000..a328e04
--- /dev/null
@@ -0,0 +1,54 @@
+
+[exabgp.api]
+encoder = text
+highres = false
+respawn = false
+socket = ''
+
+[exabgp.bgp]
+openwait = 60
+
+[exabgp.cache]
+attributes = true
+nexthops = true
+
+[exabgp.daemon]
+daemonize = true
+pid = '/var/run/exabgp/exabgp.pid'
+user = 'exabgp'
+##daemonize = false
+
+[exabgp.log]
+all = false
+configuration = true
+daemon = true
+destination = '/var/log/exabgp.log'
+enable = true
+level = INFO
+message = false
+network = true
+packets = false
+parser = false
+processes = true
+reactor = true
+rib = false
+routes = false
+short = false
+timers = false
+
+[exabgp.pdb]
+enable = false
+
+[exabgp.profile]
+enable = false
+file = ''
+
+[exabgp.reactor]
+speed = 1.0
+
+[exabgp.tcp]
+acl = false
+bind = ''
+delay = 0
+once = false
+port = 179
diff --git a/tests/topotests/bgp_vrf_netns/peer1/exa-receive.py b/tests/topotests/bgp_vrf_netns/peer1/exa-receive.py
new file mode 100755 (executable)
index 0000000..5334ea5
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+"""
+exa-receive.py: Save received routes form ExaBGP into file
+"""
+
+from sys import stdin,argv
+from datetime import datetime
+
+# 1st arg is peer number
+peer = int(argv[1])
+
+# When the parent dies we are seeing continual newlines, so we only access so many before stopping
+counter = 0
+
+routesavefile = open('/tmp/peer%s-received.log' % peer, 'w')
+
+while True:
+    try:
+        line = stdin.readline()
+        timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ')
+        routesavefile.write(timestamp + line)
+        routesavefile.flush()
+
+        if line == "":
+            counter += 1
+            if counter > 100:
+                break
+            continue
+
+        counter = 0
+    except KeyboardInterrupt:
+        pass
+    except IOError:
+        # most likely a signal during readline
+        pass
+
+routesavefile.close()
diff --git a/tests/topotests/bgp_vrf_netns/peer1/exa-send.py b/tests/topotests/bgp_vrf_netns/peer1/exa-send.py
new file mode 100755 (executable)
index 0000000..9a2a201
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+"""
+exa-send.py: Send a few testroutes with ExaBGP
+"""
+
+from sys import stdout,argv
+from time import sleep
+
+sleep(5)
+
+# 1st arg is peer number
+# 2nd arg is number of routes to send
+peer = int(argv[1])
+numRoutes = int(argv[2])
+asnum = 99
+
+# Announce numRoutes equal routes per PE - different neighbor AS
+for i in range(0, numRoutes):
+    stdout.write('announce route 10.201.%s.0/24 med 100 community %i:1 next-hop 10.0.%i.%i\n' % (i, i, (((peer-1) / 5) + 1), peer+100))
+    stdout.flush()
+
+#Loop endlessly to allow ExaBGP to continue running
+while True:
+    sleep(1)
+
diff --git a/tests/topotests/bgp_vrf_netns/peer1/exabgp.cfg b/tests/topotests/bgp_vrf_netns/peer1/exabgp.cfg
new file mode 100644 (file)
index 0000000..2d0ca89
--- /dev/null
@@ -0,0 +1,21 @@
+group controller {
+
+    process announce-routes {
+        run "/etc/exabgp/exa-send.py 1 10";
+    }
+
+    process receive-routes {
+        run "/etc/exabgp/exa-receive.py 1";
+        receive-routes;
+        encoder text;
+    }
+
+    neighbor 10.0.1.1 {
+        router-id 10.0.1.101;
+        local-address 10.0.1.101;
+        local-as 99;
+        peer-as 100;
+        graceful-restart;
+    }
+
+}
diff --git a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..e3f158d
--- /dev/null
@@ -0,0 +1,8 @@
+!
+router bgp 100 vrf r1-cust1
+ bgp router-id 10.0.1.1
+ bgp bestpath as-path multipath-relax
+ neighbor 10.0.1.101 remote-as 99
+ !
+!
+
diff --git a/tests/topotests/bgp_vrf_netns/r1/summary.txt b/tests/topotests/bgp_vrf_netns/r1/summary.txt
new file mode 100644 (file)
index 0000000..7473fa2
--- /dev/null
@@ -0,0 +1,17 @@
+{
+"ipv4Unicast":{
+  "routerId":"10.0.1.1",
+  "as":100,
+  "vrfName":"r1-cust1",
+  "peerCount":1,
+  "peers":{
+    "10.0.1.101":{
+      "outq":0,
+      "inq":0,
+      "prefixReceivedCount":10,
+      "state":"Established"
+    }
+  },
+  "totalPeers":1
+}
+}
diff --git a/tests/topotests/bgp_vrf_netns/r1/summary20.txt b/tests/topotests/bgp_vrf_netns/r1/summary20.txt
new file mode 100644 (file)
index 0000000..18318e0
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "routerId":"10.0.1.1",
+  "as":100,
+  "vrfName":"re1-cust1",
+  "peerCount":1,
+  "peers":{
+    "10.0.1.101":{
+      "outq":0,
+      "inq":0,
+      "prefixReceivedCount":10,
+      "state":"Established"
+    }
+  },
+  "totalPeers":1
+}
diff --git a/tests/topotests/bgp_vrf_netns/r1/zebra.conf b/tests/topotests/bgp_vrf_netns/r1/zebra.conf
new file mode 100644 (file)
index 0000000..817d954
--- /dev/null
@@ -0,0 +1,7 @@
+!
+interface r1-eth0 vrf r1-cust1
+ ip address 10.0.1.1/24
+!
+line vty
+!
+debug vrf
diff --git a/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py b/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py
new file mode 100755 (executable)
index 0000000..b63d68d
--- /dev/null
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_vrf_netns_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2018 by 6WIND
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bgp_vrf_netns_topo1.py: Test BGP topology with EBGP on NETNS VRF
+"""
+
+import json
+import os
+import sys
+import pytest
+import getopt
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+total_ebgp_peers = 1
+CustomizeVrfWithNetns = True
+
+#####################################################
+##
+##   Network Topology Definition
+##
+#####################################################
+
+class BGPVRFNETNSTopo1(Topo):
+    "BGP EBGP VRF NETNS Topology 1"
+
+    def build(self, **_opts):
+        tgen = get_topogen(self)
+
+        # Setup Routers
+        tgen.add_router('r1')
+
+        # Setup Switches
+        switch = tgen.add_switch('s1')
+        switch.add_link(tgen.gears['r1'])
+
+        # Add eBGP ExaBGP neighbors
+        peer_ip = '10.0.1.101'
+        peer_route = 'via 10.0.1.1'
+        peer = tgen.add_exabgp_peer('peer1',
+                                    ip=peer_ip, defaultRoute=peer_route)
+        switch = tgen.gears['s1']
+        switch.add_link(peer)
+
+
+#####################################################
+##
+##   Tests starting
+##
+#####################################################
+
+def setup_module(module):
+    tgen = Topogen(BGPVRFNETNSTopo1, module.__name__)
+    tgen.start_topology()
+
+    # Get r1 reference
+    router = tgen.gears['r1']
+
+    # check for zebra capability
+    if CustomizeVrfWithNetns == True:
+        if router.check_capability(
+                TopoRouter.RD_ZEBRA,
+                '--vrfwnetns'
+                ) == False:
+            return  pytest.skip('Skipping BGP VRF NETNS Test. VRF NETNS backend not available on FRR')
+        if os.system('ip netns list') != 0:
+            return  pytest.skip('Skipping BGP VRF NETNS Test. NETNS not available on System')
+    # retrieve VRF backend kind
+    if CustomizeVrfWithNetns == True:
+        logger.info('Testing with VRF Namespace support')
+
+    # create VRF r1-cust1
+    # move r1-eth0 to VRF r1-cust1
+    cmds = ['ip netns add {0}-cust1',
+            'ip link set dev {0}-eth0 netns {0}-cust1',
+            'ip netns exec {0}-cust1 ifconfig {0}-eth0 up']
+    for cmd in cmds:
+        router.run(cmd.format('r1'))
+
+    #run daemons
+    router.load_config(
+        TopoRouter.RD_ZEBRA,
+        os.path.join(CWD, '{}/zebra.conf'.format('r1')),
+        '--vrfwnetns'
+    )
+    router.load_config(
+        TopoRouter.RD_BGP,
+        os.path.join(CWD, '{}/bgpd.conf'.format('r1'))
+    )
+
+    logger.info('Launching BGP and ZEBRA')
+    # BGP and ZEBRA start without underlying VRF
+    router.start()
+    # Starting Hosts and init ExaBGP on each of them
+    topotest.sleep(10, 'starting BGP on peer')
+    peer_list = tgen.exabgp_peers()
+    for pname, peer in peer_list.iteritems():
+        peer_dir = os.path.join(CWD, pname)
+        env_file = os.path.join(CWD, 'exabgp.env')
+        topotest.sleep(1, 'Running ExaBGP peer')
+        peer.start(peer_dir, env_file)
+        logger.info(pname)
+
+def teardown_module(module):
+    tgen = get_topogen()
+    # move back r1-eth0 to default VRF
+    # delete VRF r1-cust1
+    cmds = ['ip netns delete {0}-cust1',
+            'ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1']
+    for cmd in cmds:
+        tgen.net['r1'].cmd(cmd.format('r1'))
+
+    tgen.stop_topology()
+
+def test_bgp_vrf_learn():
+    "Test daemon learnt VRF context"
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # Expected result
+    output = tgen.gears['r1'].vtysh_cmd("show vrf", isjson=False)
+    logger.info('output is: {}'.format(output))
+
+    output = tgen.gears['r1'].vtysh_cmd("show bgp vrfs", isjson=False)
+    logger.info('output is: {}'.format(output))
+
+    
+def test_bgp_convergence():
+    "Test for BGP topology convergence"
+    tgen = get_topogen()
+
+    # uncomment if you want to troubleshoot
+    # tgen.mininet_cli()
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    topotest.sleep(20, 'waiting for bgp convergence')
+
+    # Expected result
+    router = tgen.gears['r1']
+    if router.has_version('<', '3.0'):
+        reffile = os.path.join(CWD, 'r1/summary20.txt')
+    else:
+        reffile = os.path.join(CWD, 'r1/summary.txt')
+
+    expected = json.loads(open(reffile).read())
+
+    # Define test function and call it
+    def _convergence_test():
+        output = router.vtysh_cmd('show bgp vrf r1-cust1 summary json', isjson=True)
+        return topotest.json_cmp(output, expected)
+
+    _, res = topotest.run_and_expect(_convergence_test, None, count=10, wait=1)
+    assertmsg = 'BGP router network did not converge'
+    assert res is None, assertmsg
+
+def test_bgp_vrf_netns():
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    expect = {
+        'routerId': '10.0.1.1',
+        'routes': {
+        },
+    }
+
+    for subnet in range(0, 10):
+        netkey = '10.201.{}.0/24'.format(subnet)
+        expect['routes'][netkey] = []
+        peer = {'valid': True}
+        expect['routes'][netkey].append(peer)
+
+    def _output_cmp():
+        output = tgen.gears['r1'].vtysh_cmd('show ip bgp vrf r1-cust1 ipv4 json', isjson=True)
+        return topotest.json_cmp(output, expect)
+
+    _, res = topotest.run_and_expect(_output_cmp, None, count=1, wait=3)
+    assertmsg = 'expected routes in "show ip bgp vrf r1-cust1 ipv4" output'
+    assert res is None, assertmsg
+
+if __name__ == '__main__':
+
+    args = ["-s"] + sys.argv[1:]
+    ret = pytest.main(args)
+
+    sys.exit(ret)