From 8650fef03e736b4209a8acb6cb3cf022be0aabb8 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 28 Nov 2022 10:13:07 +0100 Subject: [PATCH] topotests: add bgp_asdot_regex test This test ensures that the regex used to filter as paths has to be expressed in the asnotation of the BGP instance where prefixes are received. 2 aspaths have been forged, both for AS 65540, but only the former is expressed in asdot. If the local BGP instance is expressed in asdot format, then only the former ASPATH will match properly the incoming update. Reversely, when the local BGP instance is expressed in plain format, then only the latter ASPATH will match properly the incoming update. Signed-off-by: Philippe Guibert --- tests/topotests/bgp_asdot_regex/__init__.py | 0 tests/topotests/bgp_asdot_regex/r1/bgpd.conf | 27 ++++ .../bgp_asdot_regex/r1/show_bgp_ipv4.json | 80 ++++++++++++ tests/topotests/bgp_asdot_regex/r1/zebra.conf | 6 + tests/topotests/bgp_asdot_regex/r2/bgpd.conf | 26 ++++ .../bgp_asdot_regex/r2/show_bgp_ipv4.json | 80 ++++++++++++ tests/topotests/bgp_asdot_regex/r2/zebra.conf | 6 + .../bgp_asdot_regex/test_bgp_asdot_regex.py | 122 ++++++++++++++++++ 8 files changed, 347 insertions(+) create mode 100644 tests/topotests/bgp_asdot_regex/__init__.py create mode 100644 tests/topotests/bgp_asdot_regex/r1/bgpd.conf create mode 100644 tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json create mode 100644 tests/topotests/bgp_asdot_regex/r1/zebra.conf create mode 100644 tests/topotests/bgp_asdot_regex/r2/bgpd.conf create mode 100644 tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json create mode 100644 tests/topotests/bgp_asdot_regex/r2/zebra.conf create mode 100644 tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py diff --git a/tests/topotests/bgp_asdot_regex/__init__.py b/tests/topotests/bgp_asdot_regex/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_asdot_regex/r1/bgpd.conf b/tests/topotests/bgp_asdot_regex/r1/bgpd.conf new file mode 100644 index 0000000000..4dd95dd8b7 --- /dev/null +++ b/tests/topotests/bgp_asdot_regex/r1/bgpd.conf @@ -0,0 +1,27 @@ +router bgp 1.1 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.255.2 remote-as 1.2 + address-family ipv4 unicast + network 172.31.1.0/24 route-map rmapout + network 172.31.2.0/24 route-map rmapout + neighbor 192.168.255.2 route-map rmapin in + neighbor 192.168.255.2 activate + exit-address-family +exit +bgp as-path access-list only1_4 permit _1.4_ +bgp as-path access-list only65540 permit _65540_ +access-list 172313 permit 172.31.3.0/24 +access-list 172314 permit 172.31.4.0/24 +route-map rmapout permit 1 + set as-path prepend 1.4 +exit +route-map rmapin permit 1 + match ip address 172313 + match as-path only1_4 +exit +route-map rmapin permit 2 + match ip address 172314 + match as-path only65540 +exit + diff --git a/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json b/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json new file mode 100644 index 0000000000..e3703bf953 --- /dev/null +++ b/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json @@ -0,0 +1,80 @@ +{ + "vrfId": 0, + "vrfName": "default", + "tableVersion": 3, + "routerId": "192.168.255.1", + "defaultLocPrf": 100, + "localAS": "1.1", + "routes": { "172.31.1.0/24": [ + { + "valid":true, + "bestpath":true, + "selectionReason":"First path received", + "pathFrom":"external", + "prefix":"172.31.1.0", + "prefixLen":24, + "network":"172.31.1.0/24", + "metric":0, + "weight":32768, + "peerId":"(unspec)", + "path":"1.4", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "hostname":"r1", + "afi":"ipv4", + "used":true + } + ] + } +] +,"172.31.2.0/24": [ + { + "valid":true, + "bestpath":true, + "selectionReason":"First path received", + "pathFrom":"external", + "prefix":"172.31.2.0", + "prefixLen":24, + "network":"172.31.2.0/24", + "metric":0, + "weight":32768, + "peerId":"(unspec)", + "path":"1.4", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "hostname":"r1", + "afi":"ipv4", + "used":true + } + ] + } +] +,"172.31.3.0/24": [ + { + "valid":true, + "bestpath":true, + "selectionReason":"First path received", + "pathFrom":"external", + "prefix":"172.31.3.0", + "prefixLen":24, + "network":"172.31.3.0/24", + "metric":0, + "weight":0, + "peerId":"192.168.255.2", + "path":"1.2 1.4", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.168.255.2", + "hostname":"r2", + "afi":"ipv4", + "used":true + } + ] + } +] + } } diff --git a/tests/topotests/bgp_asdot_regex/r1/zebra.conf b/tests/topotests/bgp_asdot_regex/r1/zebra.conf new file mode 100644 index 0000000000..6e9b0b4a7e --- /dev/null +++ b/tests/topotests/bgp_asdot_regex/r1/zebra.conf @@ -0,0 +1,6 @@ +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_asdot_regex/r2/bgpd.conf b/tests/topotests/bgp_asdot_regex/r2/bgpd.conf new file mode 100644 index 0000000000..216dbd19ef --- /dev/null +++ b/tests/topotests/bgp_asdot_regex/r2/bgpd.conf @@ -0,0 +1,26 @@ +router bgp 65538 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.255.1 remote-as 65537 + address-family ipv4 unicast + network 172.31.3.0/24 route-map rmapout + network 172.31.4.0/24 route-map rmapout + neighbor 192.168.255.1 route-map rmapin in + neighbor 192.168.255.1 activate + exit-address-family +exit +bgp as-path access-list only65540 permit _65540_ +bgp as-path access-list only1_4 permit _1.4_ +access-list 172311 permit 172.31.1.0/24 +access-list 172312 permit 172.31.2.0/24 +route-map rmapout permit 1 + set as-path prepend 65540 +exit +route-map rmapin permit 1 + match ip address 172311 + match as-path only65540 +exit +route-map rmapin permit 2 + match ip address 172312 + match as-path only1_4 +exit diff --git a/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json b/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json new file mode 100644 index 0000000000..1af4ff7e3d --- /dev/null +++ b/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json @@ -0,0 +1,80 @@ +{ + "vrfId": 0, + "vrfName": "default", + "tableVersion": 3, + "routerId": "192.168.255.2", + "defaultLocPrf": 100, + "localAS": 65538, + "routes": { "172.31.1.0/24": [ + { + "valid":true, + "bestpath":true, + "selectionReason":"First path received", + "pathFrom":"external", + "prefix":"172.31.1.0", + "prefixLen":24, + "network":"172.31.1.0/24", + "metric":0, + "weight":0, + "peerId":"192.168.255.1", + "path":"65537 65540", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.168.255.1", + "hostname":"r1", + "afi":"ipv4", + "used":true + } + ] + } +] +,"172.31.3.0/24": [ + { + "valid":true, + "bestpath":true, + "selectionReason":"First path received", + "pathFrom":"external", + "prefix":"172.31.3.0", + "prefixLen":24, + "network":"172.31.3.0/24", + "metric":0, + "weight":32768, + "peerId":"(unspec)", + "path":"65540", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "hostname":"r2", + "afi":"ipv4", + "used":true + } + ] + } +] +,"172.31.4.0/24": [ + { + "valid":true, + "bestpath":true, + "selectionReason":"First path received", + "pathFrom":"external", + "prefix":"172.31.4.0", + "prefixLen":24, + "network":"172.31.4.0/24", + "metric":0, + "weight":32768, + "peerId":"(unspec)", + "path":"65540", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "hostname":"r2", + "afi":"ipv4", + "used":true + } + ] + } +] + } } diff --git a/tests/topotests/bgp_asdot_regex/r2/zebra.conf b/tests/topotests/bgp_asdot_regex/r2/zebra.conf new file mode 100644 index 0000000000..6c14de583b --- /dev/null +++ b/tests/topotests/bgp_asdot_regex/r2/zebra.conf @@ -0,0 +1,6 @@ +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py new file mode 100644 index 0000000000..5d5f1659e9 --- /dev/null +++ b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python + +# +# test_bgp_asdot_regex.py +# Part of Topotests +# +# Copyright 2022 6WIND S.A. +# +# 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_asdot_regex.py: + +Test how regex applies when asnotation to forge bgp config is based on dot or not. +""" + +import os +import sys +import json +import pytest +from functools import partial + +# add after imports, before defining classes or functions: +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 3): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_asdot_regex(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router1 = tgen.gears["r1"] + router2 = tgen.gears["r2"] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json")) + expected = { + "192.168.255.2": { + "bgpState": "Established", + "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 1}}, + } + } + return topotest.json_cmp(output, expected) + + logger.info("Check if neighbor sessions are up in {}".format(router1.name)) + test_func = partial(_bgp_converge, router1) + success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name) + + logger.info("BGP neighbor session is up in {}".format(router1.name)) + + logger.info("waiting for bgp peers exchanging UPDATES") + + for router in tgen.routers().values(): + ref_file = "{}/{}/show_bgp_ipv4.json".format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + test_func = partial( + topotest.router_json_cmp, router, "show bgp ipv4 unicast json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=40, wait=2.5) + assertmsg = "{}: BGP UPDATE exchange failure".format(router.name) + assert res is None, assertmsg + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args))