summaryrefslogtreecommitdiffstats
path: root/tests/topotests/bgp_bmp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:16:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:16:35 +0000
commite2bbf175a2184bd76f6c54ccf8456babeb1a46fc (patch)
treef0b76550d6e6f500ada964a3a4ee933a45e5a6f1 /tests/topotests/bgp_bmp
parentInitial commit. (diff)
downloadfrr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.tar.xz
frr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.zip
Adding upstream version 9.1.upstream/9.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/topotests/bgp_bmp')
-rw-r--r--tests/topotests/bgp_bmp/__init__.py0
-rw-r--r--tests/topotests/bgp_bmp/r1/bgpd.conf22
-rw-r--r--tests/topotests/bgp_bmp/r1/zebra.conf7
-rw-r--r--tests/topotests/bgp_bmp/r2/bgpd.conf19
-rw-r--r--tests/topotests/bgp_bmp/r2/zebra.conf8
-rw-r--r--tests/topotests/bgp_bmp/test_bgp_bmp.py246
6 files changed, 302 insertions, 0 deletions
diff --git a/tests/topotests/bgp_bmp/__init__.py b/tests/topotests/bgp_bmp/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/topotests/bgp_bmp/__init__.py
diff --git a/tests/topotests/bgp_bmp/r1/bgpd.conf b/tests/topotests/bgp_bmp/r1/bgpd.conf
new file mode 100644
index 0000000..69acf6e
--- /dev/null
+++ b/tests/topotests/bgp_bmp/r1/bgpd.conf
@@ -0,0 +1,22 @@
+router bgp 65501
+ bgp router-id 192.168.0.1
+ bgp log-neighbor-changes
+ no bgp ebgp-requires-policy
+ neighbor 192.168.0.2 remote-as 65502
+ neighbor 192:168::2 remote-as 65502
+!
+ bmp targets bmp1
+ bmp connect 192.0.178.10 port 1789 min-retry 100 max-retry 10000
+ exit
+!
+ address-family ipv4 unicast
+ neighbor 192.168.0.2 activate
+ neighbor 192.168.0.2 soft-reconfiguration inbound
+ no neighbor 192:168::2 activate
+ exit-address-family
+!
+ address-family ipv6 unicast
+ neighbor 192:168::2 activate
+ neighbor 192:168::2 soft-reconfiguration inbound
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_bmp/r1/zebra.conf b/tests/topotests/bgp_bmp/r1/zebra.conf
new file mode 100644
index 0000000..6a25a6f
--- /dev/null
+++ b/tests/topotests/bgp_bmp/r1/zebra.conf
@@ -0,0 +1,7 @@
+interface r1-eth0
+ ip address 192.0.178.1/24
+!
+interface r1-eth1
+ ip address 192.168.0.1/24
+ ipv6 address 192:168::1/64
+!
diff --git a/tests/topotests/bgp_bmp/r2/bgpd.conf b/tests/topotests/bgp_bmp/r2/bgpd.conf
new file mode 100644
index 0000000..7c8255a
--- /dev/null
+++ b/tests/topotests/bgp_bmp/r2/bgpd.conf
@@ -0,0 +1,19 @@
+router bgp 65502
+ bgp router-id 192.168.0.2
+ bgp log-neighbor-changes
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.0.1 remote-as 65501
+ neighbor 192:168::1 remote-as 65501
+!
+ address-family ipv4 unicast
+ neighbor 192.168.0.1 activate
+ no neighbor 192:168::1 activate
+ redistribute connected
+ exit-address-family
+!
+ address-family ipv6 unicast
+ neighbor 192:168::1 activate
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_bmp/r2/zebra.conf b/tests/topotests/bgp_bmp/r2/zebra.conf
new file mode 100644
index 0000000..9d82bfe
--- /dev/null
+++ b/tests/topotests/bgp_bmp/r2/zebra.conf
@@ -0,0 +1,8 @@
+interface r2-eth0
+ ip address 192.168.0.2/24
+ ipv6 address 192:168::2/64
+!
+interface r2-eth1
+ ip address 172.31.0.2/24
+ ipv6 address 172:31::2/64
+!
diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp.py b/tests/topotests/bgp_bmp/test_bgp_bmp.py
new file mode 100644
index 0000000..65f191b
--- /dev/null
+++ b/tests/topotests/bgp_bmp/test_bgp_bmp.py
@@ -0,0 +1,246 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright 2023 6WIND S.A.
+# Authored by Farid Mihoub <farid.mihoub@6wind.com>
+#
+
+"""
+test_bgp_bmp.py: Test BGP BMP functionalities
+
+ +------+ +------+ +------+
+ | | | | | |
+ | BMP1 |------------| R1 |---------------| R2 |
+ | | | | | |
+ +------+ +------+ +------+
+
+Setup two routers R1 and R2 with one link configured with IPv4 and
+IPv6 addresses.
+Configure BGP in R1 and R2 to exchange prefixes from
+the latter to the first router.
+Setup a link between R1 and the BMP server, activate the BMP feature in R1
+and ensure the monitored BGP sessions logs are well present on the BMP server.
+"""
+
+from functools import partial
+from ipaddress import ip_network
+import json
+import os
+import platform
+import pytest
+import sys
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join("../"))
+sys.path.append(os.path.join("../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.bgp import verify_bgp_convergence_from_running_config
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+pytestmark = [pytest.mark.bgpd]
+
+# remember the last sequence number of the logging messages
+SEQ = 0
+
+PRE_POLICY = "pre-policy"
+POST_POLICY = "post-policy"
+
+
+def build_topo(tgen):
+ tgen.add_router("r1")
+ tgen.add_router("r2")
+ tgen.add_bmp_server("bmp1", ip="192.0.178.10", defaultRoute="via 192.0.178.1")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["bmp1"])
+
+ tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "r1-eth1", "r2-eth0")
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ for rname, router in tgen.routers().items():
+ 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)),
+ "-M bmp",
+ )
+
+ tgen.start_router()
+
+ logger.info("starting BMP servers")
+ for _, server in tgen.get_bmp_servers().items():
+ server.start()
+
+
+def teardown_module(_mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_convergence():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ result = verify_bgp_convergence_from_running_config(tgen, dut="r1")
+ assert result is True, "BGP is not converging"
+
+
+def get_bmp_messages():
+ """
+ Read the BMP logging messages.
+ """
+ messages = []
+ tgen = get_topogen()
+ text_output = tgen.gears["bmp1"].run("cat /var/log/bmp.log")
+
+ for m in text_output.splitlines():
+ # some output in the bash can break the message decoding
+ try:
+ messages.append(json.loads(m))
+ except Exception as e:
+ logger.warning(str(e) + " message: {}".format(str(m)))
+ continue
+
+ if not messages:
+ logger.error("Bad BMP log format, check your BMP server")
+
+ return messages
+
+
+def check_for_prefixes(expected_prefixes, bmp_log_type, post_policy):
+ """
+ Check for the presence of the given prefixes in the BMP server logs with
+ the given message type and the set policy.
+ """
+ global SEQ
+ # we care only about the new messages
+ messages = [
+ m for m in sorted(get_bmp_messages(), key=lambda d: d["seq"]) if m["seq"] > SEQ
+ ]
+
+ # get the list of pairs (prefix, policy, seq) for the given message type
+ prefixes = [
+ m["ip_prefix"]
+ for m in messages
+ if "ip_prefix" in m.keys()
+ and "bmp_log_type" in m.keys()
+ and m["bmp_log_type"] == bmp_log_type
+ and m["post_policy"] == post_policy
+ ]
+
+ # check for prefixes
+ for ep in expected_prefixes:
+ if ep not in prefixes:
+ msg = "The prefix {} is not present in the {} log messages."
+ logger.debug(msg.format(ep, bmp_log_type))
+ return False
+
+ SEQ = messages[-1]["seq"]
+ return True
+
+
+def set_bmp_policy(tgen, node, asn, target, safi, policy, vrf=None):
+ """
+ Configure the bmp policy.
+ """
+ vrf = " vrf {}" if vrf else ""
+ cmd = [
+ "con t\n",
+ "router bgp {}{}\n".format(asn, vrf),
+ "bmp targets {}\n".format(target),
+ "bmp monitor ipv4 {} {}\n".format(safi, policy),
+ "bmp monitor ipv6 {} {}\n".format(safi, policy),
+ "end\n",
+ ]
+ tgen.gears[node].vtysh_cmd("".join(cmd))
+
+
+def configure_prefixes(tgen, node, asn, safi, prefixes, vrf=None, update=True):
+ """
+ Configure the bgp prefixes.
+ """
+ withdraw = "no " if not update else ""
+ vrf = " vrf {}" if vrf else ""
+ for p in prefixes:
+ ip = ip_network(p)
+ cmd = [
+ "conf t\n",
+ "router bgp {}{}\n".format(asn, vrf),
+ "address-family ipv{} {}\n".format(ip.version, safi),
+ "{}network {}\n".format(withdraw, ip),
+ "exit-address-family\n",
+ ]
+ logger.debug("setting prefix: ipv{} {} {}".format(ip.version, safi, ip))
+ tgen.gears[node].vtysh_cmd("".join(cmd))
+
+
+def unicast_prefixes(policy):
+ """
+ Setup the BMP monitor policy, Add and withdraw ipv4/v6 prefixes.
+ Check if the previous actions are logged in the BMP server with the right
+ message type and the right policy.
+ """
+ tgen = get_topogen()
+ set_bmp_policy(tgen, "r1", 65501, "bmp1", "unicast", policy)
+
+ prefixes = ["172.31.0.15/32", "2111::1111/128"]
+ # add prefixes
+ configure_prefixes(tgen, "r2", 65502, "unicast", prefixes)
+
+ logger.info("checking for updated prefixes")
+ # check
+ test_func = partial(check_for_prefixes, prefixes, "update", policy == POST_POLICY)
+ success, _ = topotest.run_and_expect(test_func, True, wait=0.5)
+ assert success, "Checking the updated prefixes has been failed !."
+
+ # withdraw prefixes
+ configure_prefixes(tgen, "r2", 65502, "unicast", prefixes, update=False)
+ logger.info("checking for withdrawed prefxies")
+ # check
+ test_func = partial(check_for_prefixes, prefixes, "withdraw", policy == POST_POLICY)
+ success, _ = topotest.run_and_expect(test_func, True, wait=0.5)
+ assert success, "Checking the withdrawed prefixes has been failed !."
+
+
+def test_bmp_server_logging():
+ """
+ Assert the logging of the bmp server.
+ """
+
+ def check_for_log_file():
+ tgen = get_topogen()
+ output = tgen.gears["bmp1"].run("ls /var/log/")
+ if "bmp.log" not in output:
+ return False
+ return True
+
+ success, _ = topotest.run_and_expect(check_for_log_file, True, wait=0.5)
+ assert success, "The BMP server is not logging"
+
+
+def test_bmp_bgp_unicast():
+ """
+ Add/withdraw bgp unicast prefixes and check the bmp logs.
+ """
+ logger.info("*** Unicast prefixes pre-policy logging ***")
+ unicast_prefixes(PRE_POLICY)
+ logger.info("*** Unicast prefixes post-policy logging ***")
+ unicast_prefixes(POST_POLICY)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))