diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 06f6073781..85f09ccf0b 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1187,6 +1187,33 @@ int aspath_loop_check(struct aspath *aspath, as_t asno) return count; } +/* AS path loop check. If aspath contains asno + * that is a confed id then return >= 1. + */ +int aspath_loop_check_confed(struct aspath *aspath, as_t asno) +{ + struct assegment *seg; + int count = 0; + + if (aspath == NULL || aspath->segments == NULL) + return 0; + + seg = aspath->segments; + + while (seg) { + unsigned int i; + + for (i = 0; i < seg->length; i++) + if (seg->type != AS_CONFED_SEQUENCE && + seg->type != AS_CONFED_SET && seg->as[i] == asno) + count++; + + seg = seg->next; + } + return count; +} + + /* When all of AS path is private AS return 1. */ bool aspath_private_as_check(struct aspath *aspath) { diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 0b58e1adc4..97bc7c0aca 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -111,6 +111,7 @@ extern unsigned int aspath_key_make(const void *p); extern unsigned int aspath_get_first_as(struct aspath *aspath); extern unsigned int aspath_get_last_as(struct aspath *aspath); extern int aspath_loop_check(struct aspath *aspath, as_t asno); +extern int aspath_loop_check_confed(struct aspath *aspath, as_t asno); extern bool aspath_private_as_check(struct aspath *aspath); extern struct aspath *aspath_replace_specific_asn(struct aspath *aspath, as_t target_asn, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4ade647cd0..9fb8d7cfee 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2197,7 +2197,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* If we're a CONFED we need to loop check the CONFED ID too */ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { - if (aspath_loop_check(piattr->aspath, bgp->confed_id)) { + if (aspath_loop_check_confed(piattr->aspath, bgp->confed_id)) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) zlog_debug( "%pBP [Update:SEND] suppress announcement to peer AS %u is AS path.", @@ -4114,16 +4114,23 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, /* AS path loop check. */ if (do_loop_check) { - if (aspath_loop_check(attr->aspath, bgp->as) > allowas_in || - (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) && - (aspath_loop_check(attr->aspath, bgp->confed_id) > - allowas_in))) { + if (aspath_loop_check(attr->aspath, bgp->as) > + peer->allowas_in[afi][safi]) { peer->stat_pfx_aspath_loop++; reason = "as-path contains our own AS;"; goto filtered; } } + /* If we're a CONFED we need to loop check the CONFED ID too */ + if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) && do_loop_check) + if (aspath_loop_check_confed(attr->aspath, bgp->confed_id) > + peer->allowas_in[afi][safi]) { + peer->stat_pfx_aspath_loop++; + reason = "as-path contains our own confed AS;"; + goto filtered; + } + /* Route reflector originator ID check. If ACCEPT_OWN mechanism is * enabled, then take care of that too. */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 1f532d4990..862b5bdd1f 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1960,13 +1960,6 @@ DEFUN (bgp_confederation_peers, for (i = idx_asn; i < argc; i++) { as = strtoul(argv[i]->arg, NULL, 10); - - if (bgp->as == as) { - vty_out(vty, - "%% Local member-AS not allowed in confed peer list\n"); - continue; - } - bgp_confederation_peers_add(bgp, as); } return CMD_SUCCESS; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 12ee96ff45..e6a7a4cc43 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -671,7 +671,7 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as) struct peer *peer; struct listnode *node, *nnode; - if (bgp->as == as) + if (!bgp) return; if (bgp_confederation_peers_check(bgp, as)) @@ -687,8 +687,8 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as) if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) { for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (peer->as == as) { - (void)peer_sort(peer); peer->local_as = bgp->as; + (void)peer_sort(peer); if (BGP_IS_VALID_STATE_FOR_NOTIF( peer->status)) { peer->last_reset = @@ -738,8 +738,8 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as) if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) { for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (peer->as == as) { - (void)peer_sort(peer); peer->local_as = bgp->confed_id; + (void)peer_sort(peer); if (BGP_IS_VALID_STATE_FOR_NOTIF( peer->status)) { peer->last_reset = diff --git a/tests/topotests/bgp_confed1/__init__.py b/tests/topotests/bgp_confed1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json new file mode 100644 index 0000000000..d3988eb0e7 --- /dev/null +++ b/tests/topotests/bgp_confed1/r1/bgp_ipv4_unicast.json @@ -0,0 +1,63 @@ +{ + "vrfId":0, + "vrfName":"default", + "routerId":"203.0.113.1", + "defaultLocPrf":100, + "localAS":100, + "routes":{"203.0.113.0/28":[ + { + "network":"203.0.113.0\/28", + "peerId":"(unspec)", + "path":"", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.16/28":[ + { + "network":"203.0.113.16\/28", + "peerId":"192.0.2.2", + "path":"300", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.2", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.32/28":[ + { + "network":"203.0.113.32\/28", + "peerId":"192.0.2.2", + "path":"300", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.2", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.48/28":[ + { + "network":"203.0.113.48\/28", + "peerId":"192.0.2.2", + "path":"300 400", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.2", + "afi":"ipv4", + "used":true + } + ] + } +] } } diff --git a/tests/topotests/bgp_confed1/r1/bgp_summary.json b/tests/topotests/bgp_confed1/r1/bgp_summary.json new file mode 100644 index 0000000000..f999021a20 --- /dev/null +++ b/tests/topotests/bgp_confed1/r1/bgp_summary.json @@ -0,0 +1,13 @@ +{ + "ipv4Unicast":{ + "routerId":"203.0.113.1", + "as":100, + "peers":{ + "192.0.2.2":{ + "remoteAs": 300, + "state": "Established", + "peerState":"OK" + } + } + } +} diff --git a/tests/topotests/bgp_confed1/r1/bgpd.conf b/tests/topotests/bgp_confed1/r1/bgpd.conf new file mode 100644 index 0000000000..8413ef7fc3 --- /dev/null +++ b/tests/topotests/bgp_confed1/r1/bgpd.conf @@ -0,0 +1,13 @@ +debug bgp neighbor-events +debug bgp nht +debug bgp updates in +debug bgp updates out +! +router bgp 100 + no bgp ebgp-requires-policy +! + neighbor 192.0.2.2 remote-as 300 + address-family ipv4 unicast + network 203.0.113.0/28 + exit-address-family +! diff --git a/tests/topotests/bgp_confed1/r1/isisd.conf b/tests/topotests/bgp_confed1/r1/isisd.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_confed1/r1/zebra.conf b/tests/topotests/bgp_confed1/r1/zebra.conf new file mode 100644 index 0000000000..5f76e74493 --- /dev/null +++ b/tests/topotests/bgp_confed1/r1/zebra.conf @@ -0,0 +1,6 @@ +interface r1-eth0 + ip address 192.0.2.1/28 +! +interface lo + ip address 203.0.113.1/28 +! diff --git a/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json new file mode 100644 index 0000000000..b4a0946072 --- /dev/null +++ b/tests/topotests/bgp_confed1/r2/bgp_ipv4_unicast.json @@ -0,0 +1,63 @@ +{ + "vrfId":0, + "vrfName":"default", + "routerId":"203.0.113.17", + "defaultLocPrf":100, + "localAS":200, + "routes":{"203.0.113.0/28": [ + { + "network":"203.0.113.0\/28", + "peerId":"192.0.2.1", + "path":"100", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.1", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.16/28":[ + { + "network":"203.0.113.16\/28", + "peerId":"(unspec)", + "path":"", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.32/28":[ + { + "network":"203.0.113.32\/28", + "peerId":"192.0.2.18", + "path":"(300)", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.18", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.48/28":[ + { + "network":"203.0.113.48\/28", + "peerId":"192.0.2.18", + "path":"(300) 400", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.50", + "afi":"ipv4", + "used":true + } + ] + } +] } } diff --git a/tests/topotests/bgp_confed1/r2/bgp_summary.json b/tests/topotests/bgp_confed1/r2/bgp_summary.json new file mode 100644 index 0000000000..c2690a145a --- /dev/null +++ b/tests/topotests/bgp_confed1/r2/bgp_summary.json @@ -0,0 +1,18 @@ +{ + "ipv4Unicast":{ + "routerId":"203.0.113.17", + "as":200, + "peers":{ + "192.0.2.1":{ + "remoteAs":100, + "state":"Established", + "peerState":"OK" + }, + "192.0.2.18":{ + "remoteAs":300, + "state":"Established", + "peerState":"OK" + } + } + } +} diff --git a/tests/topotests/bgp_confed1/r2/bgpd.conf b/tests/topotests/bgp_confed1/r2/bgpd.conf new file mode 100644 index 0000000000..9f6a9852de --- /dev/null +++ b/tests/topotests/bgp_confed1/r2/bgpd.conf @@ -0,0 +1,18 @@ +debug bgp neighbor-events +debug bgp nht +debug bgp updates in +debug bgp updates out +! +router bgp 200 + no bgp ebgp-requires-policy + bgp confederation identifier 300 + bgp confederation peers 300 + neighbor 192.0.2.1 remote-as 100 + neighbor 192.0.2.18 remote-as 300 + ! + address-family ipv4 unicast + network 203.0.113.16/28 + neighbor 192.0.2.18 default-originate + exit-address-family +! + diff --git a/tests/topotests/bgp_confed1/r2/isisd.conf b/tests/topotests/bgp_confed1/r2/isisd.conf new file mode 100644 index 0000000000..135bb00a83 --- /dev/null +++ b/tests/topotests/bgp_confed1/r2/isisd.conf @@ -0,0 +1,8 @@ +interface r2-eth1 + ip router isis 1 + isis circuit-type level-2-only + +router isis 1 + is-type level-2-only + net 49.0001.0002.0002.0002.00 + redistribute ipv4 connected level-2 diff --git a/tests/topotests/bgp_confed1/r2/zebra.conf b/tests/topotests/bgp_confed1/r2/zebra.conf new file mode 100644 index 0000000000..85ebe9ee02 --- /dev/null +++ b/tests/topotests/bgp_confed1/r2/zebra.conf @@ -0,0 +1,9 @@ +interface r2-eth0 + ip address 192.0.2.2/28 +! +interface r2-eth1 + ip address 192.0.2.17/28 +! +interface lo + ip address 203.0.113.17/28 +! diff --git a/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json new file mode 100644 index 0000000000..a263a9f4a7 --- /dev/null +++ b/tests/topotests/bgp_confed1/r3/bgp_ipv4_unicast.json @@ -0,0 +1,77 @@ +{ + "vrfId":0, + "vrfName":"default", + "routerId":"203.0.113.33", + "defaultLocPrf":100, + "localAS":300, + "routes":{"0.0.0.0/0":[ + { + "network":"0.0.0.0\/0", + "peerId":"192.0.2.17", + "path":"(200)", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.17", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.0/28":[ + { + "network":"203.0.113.0\/28", + "peerId":"192.0.2.17", + "path":"(200) 100", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.1", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.16/28":[ + { + "network":"203.0.113.16\/28", + "peerId":"192.0.2.17", + "path":"(200)", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.17", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.32/28":[ + { + "network":"203.0.113.32\/28", + "peerId":"(unspec)", + "path":"", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.48/28":[ + { + "network":"203.0.113.48\/28", + "peerId":"192.0.2.50", + "path":"400", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.50", + "afi":"ipv4", + "used":true + } + ] + } +] } } diff --git a/tests/topotests/bgp_confed1/r3/bgp_summary.json b/tests/topotests/bgp_confed1/r3/bgp_summary.json new file mode 100644 index 0000000000..0cc0d53895 --- /dev/null +++ b/tests/topotests/bgp_confed1/r3/bgp_summary.json @@ -0,0 +1,18 @@ +{ + "ipv4Unicast":{ + "routerId":"203.0.113.33", + "as":300, + "peers":{ + "192.0.2.17":{ + "remoteAs":200, + "state":"Established", + "peerState":"OK" + }, + "192.0.2.50":{ + "remoteAs":400, + "state":"Established", + "peerState":"OK" + } + } + } +} diff --git a/tests/topotests/bgp_confed1/r3/bgpd.conf b/tests/topotests/bgp_confed1/r3/bgpd.conf new file mode 100644 index 0000000000..3a018a42b3 --- /dev/null +++ b/tests/topotests/bgp_confed1/r3/bgpd.conf @@ -0,0 +1,17 @@ +debug bgp neighbor-events +debug bgp nht +debug bgp updates in +debug bgp updates out +! +router bgp 300 + no bgp ebgp-requires-policy + bgp confederation identifier 300 + bgp confederation peers 200 + neighbor 192.0.2.17 remote-as 200 + neighbor 192.0.2.50 remote-as 400 +! + address-family ipv4 unicast + network 203.0.113.32/28 + exit-address-family +! + diff --git a/tests/topotests/bgp_confed1/r3/isisd.conf b/tests/topotests/bgp_confed1/r3/isisd.conf new file mode 100644 index 0000000000..a0b120019b --- /dev/null +++ b/tests/topotests/bgp_confed1/r3/isisd.conf @@ -0,0 +1,8 @@ +interface r3-eth1 + ip router isis 1 + isis circuit-type level-2-only + +router isis 1 + is-type level-2-only + net 49.0001.0003.0003.0003.00 + redistribute ipv4 connected level-2 diff --git a/tests/topotests/bgp_confed1/r3/zebra.conf b/tests/topotests/bgp_confed1/r3/zebra.conf new file mode 100644 index 0000000000..555c8ed3cf --- /dev/null +++ b/tests/topotests/bgp_confed1/r3/zebra.conf @@ -0,0 +1,10 @@ +! +interface r3-eth0 + ip address 192.0.2.49/28 +! +interface r3-eth1 + ip address 192.0.2.18/28 +! +interface lo + ip address 203.0.113.33/28 +! diff --git a/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json b/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json new file mode 100644 index 0000000000..8a1f0b6762 --- /dev/null +++ b/tests/topotests/bgp_confed1/r4/bgp_ipv4_unicast.json @@ -0,0 +1,77 @@ +{ + "vrfId":0, + "vrfName":"default", + "routerId":"203.0.113.49", + "defaultLocPrf":100, + "localAS":400, + "routes":{"0.0.0.0/0":[ + { + "network":"0.0.0.0\/0", + "peerId":"192.0.2.49", + "path":"300", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.49", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.0/28":[ + { + "network":"203.0.113.0\/28", + "peerId":"192.0.2.49", + "path":"300 100", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.49", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.16/28":[ + { + "network":"203.0.113.16\/28", + "peerId":"192.0.2.49", + "path":"300", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.49", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.32/28":[ + { + "network":"203.0.113.32\/28", + "peerId":"192.0.2.49", + "path":"300", + "origin":"IGP", + "nexthops":[ + { + "ip":"192.0.2.49", + "afi":"ipv4", + "used":true + } + ] + } +],"203.0.113.48/28":[ + { + "network":"203.0.113.48\/28", + "peerId":"(unspec)", + "path":"", + "origin":"IGP", + "nexthops":[ + { + "ip":"0.0.0.0", + "afi":"ipv4", + "used":true + } + ] + } +] } } diff --git a/tests/topotests/bgp_confed1/r4/bgp_summary.json b/tests/topotests/bgp_confed1/r4/bgp_summary.json new file mode 100644 index 0000000000..11a0c45cc7 --- /dev/null +++ b/tests/topotests/bgp_confed1/r4/bgp_summary.json @@ -0,0 +1,13 @@ +{ + "ipv4Unicast":{ + "routerId":"203.0.113.49", + "as":400, + "peers":{ + "192.0.2.49":{ + "remoteAs":300, + "state":"Established", + "peerState":"OK" + } + } + } +} diff --git a/tests/topotests/bgp_confed1/r4/bgpd.conf b/tests/topotests/bgp_confed1/r4/bgpd.conf new file mode 100644 index 0000000000..134f221543 --- /dev/null +++ b/tests/topotests/bgp_confed1/r4/bgpd.conf @@ -0,0 +1,14 @@ +debug bgp neighbor-events +debug bgp nht +debug bgp updates in +debug bgp updates out +! +router bgp 400 + no bgp ebgp-requires-policy + bgp disable-ebgp-connected-route-check +! + neighbor 192.0.2.49 remote-as 300 + address-family ipv4 unicast + network 203.0.113.48/28 + exit-address-family +! diff --git a/tests/topotests/bgp_confed1/r4/isisd.conf b/tests/topotests/bgp_confed1/r4/isisd.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_confed1/r4/zebra.conf b/tests/topotests/bgp_confed1/r4/zebra.conf new file mode 100644 index 0000000000..28c448eef8 --- /dev/null +++ b/tests/topotests/bgp_confed1/r4/zebra.conf @@ -0,0 +1,6 @@ +interface r4-eth0 + ip address 192.0.2.50/28 +! +interface lo + ip address 203.0.113.49/28 +! diff --git a/tests/topotests/bgp_confed1/test_bgp_confed1.py b/tests/topotests/bgp_confed1/test_bgp_confed1.py new file mode 100644 index 0000000000..7a35a10852 --- /dev/null +++ b/tests/topotests/bgp_confed1/test_bgp_confed1.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +# +# test_bgp_confed1.py +# +# 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 6WIND DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 6WIND 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_confed1.py: Test the FRR BGP confederations with AS member +same as confederation Id, verify BGP prefixes and path distribution +""" + +import os +import sys +import json +from functools import partial +import pytest + +# 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 + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + +def setup_module(mod): + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_convergence(): + "Assert that BGP is converging." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for bgp peers to go up") + + for router in tgen.routers().values(): + ref_file = "{}/{}/bgp_summary.json".format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + test_func = partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=125, wait=2.0) + assertmsg = "{}: bgp did not converge".format(router.name) + assert res is None, assertmsg + + +def test_bgp_confed_ipv4_unicast(): + "Assert that BGP is exchanging BGP route." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for bgp peers exchanging UPDATES") + + for router in tgen.routers().values(): + ref_file = "{}/{}/bgp_ipv4_unicast.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))