Merge pull request #12322 from fdumontet6WIND/confed_num

bgp:  fix case where confederation id same as member-as
This commit is contained in:
Russ White 2022-12-06 08:59:44 -05:00 committed by GitHub
commit 17ccfbb6c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 623 additions and 15 deletions

View File

@ -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)
{

View File

@ -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,

View File

@ -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.
*/

View File

@ -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;

View File

@ -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 =

View File

View File

@ -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
}
]
}
] } }

View File

@ -0,0 +1,13 @@
{
"ipv4Unicast":{
"routerId":"203.0.113.1",
"as":100,
"peers":{
"192.0.2.2":{
"remoteAs": 300,
"state": "Established",
"peerState":"OK"
}
}
}
}

View File

@ -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
!

View File

@ -0,0 +1,6 @@
interface r1-eth0
ip address 192.0.2.1/28
!
interface lo
ip address 203.0.113.1/28
!

View File

@ -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
}
]
}
] } }

View File

@ -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"
}
}
}
}

View File

@ -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
!

View File

@ -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

View File

@ -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
!

View File

@ -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
}
]
}
] } }

View File

@ -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"
}
}
}
}

View File

@ -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
!

View File

@ -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

View File

@ -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
!

View File

@ -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
}
]
}
] } }

View File

@ -0,0 +1,13 @@
{
"ipv4Unicast":{
"routerId":"203.0.113.49",
"as":400,
"peers":{
"192.0.2.49":{
"remoteAs":300,
"state":"Established",
"peerState":"OK"
}
}
}
}

View File

@ -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
!

View File

@ -0,0 +1,6 @@
interface r4-eth0
ip address 192.0.2.50/28
!
interface lo
ip address 203.0.113.49/28
!

View File

@ -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))