Merge pull request #9545 from ton31337/feature/disable-addpath-rx

bgpd: Add disable-addpath-rx knob
This commit is contained in:
Mark Stapp 2021-09-03 11:52:57 -04:00 committed by GitHub
commit 4250098311
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 291 additions and 7 deletions

View File

@ -1534,6 +1534,11 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
FOREACH_AFI_SAFI (afi, safi) { FOREACH_AFI_SAFI (afi, safi) {
if (peer->afc[afi][safi]) { if (peer->afc[afi][safi]) {
bool adv_addpath_rx =
!CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_DISABLE_ADDPATH_RX);
uint8_t flags = 0;
/* Convert AFI, SAFI to values for packet. */ /* Convert AFI, SAFI to values for packet. */
bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi,
&pkt_safi); &pkt_safi);
@ -1541,19 +1546,25 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
stream_putw(s, pkt_afi); stream_putw(s, pkt_afi);
stream_putc(s, pkt_safi); stream_putc(s, pkt_safi);
if (adv_addpath_tx) { if (adv_addpath_rx) {
stream_putc(s, BGP_ADDPATH_RX | BGP_ADDPATH_TX); SET_FLAG(flags, BGP_ADDPATH_RX);
SET_FLAG(peer->af_cap[afi][safi], SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_RX_ADV); PEER_CAP_ADDPATH_AF_RX_ADV);
} else {
UNSET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_RX_ADV);
}
if (adv_addpath_tx) {
SET_FLAG(flags, BGP_ADDPATH_TX);
SET_FLAG(peer->af_cap[afi][safi], SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_TX_ADV); PEER_CAP_ADDPATH_AF_TX_ADV);
} else { } else {
stream_putc(s, BGP_ADDPATH_RX);
SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_RX_ADV);
UNSET_FLAG(peer->af_cap[afi][safi], UNSET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_TX_ADV); PEER_CAP_ADDPATH_AF_TX_ADV);
} }
stream_putc(s, flags);
} }
} }

View File

@ -7968,6 +7968,48 @@ DEFUN (no_neighbor_ttl_security,
return bgp_vty_return(vty, peer_ttl_security_hops_unset(peer)); return bgp_vty_return(vty, peer_ttl_security_hops_unset(peer));
} }
/* disable-addpath-rx */
DEFUN(neighbor_disable_addpath_rx,
neighbor_disable_addpath_rx_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> disable-addpath-rx",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Do not accept additional paths\n")
{
char *peer_str = argv[1]->arg;
struct peer *peer;
afi_t afi = bgp_node_afi(vty);
safi_t safi = bgp_node_safi(vty);
peer = peer_and_group_lookup_vty(vty, peer_str);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
return peer_af_flag_set_vty(vty, peer_str, afi, safi,
PEER_FLAG_DISABLE_ADDPATH_RX);
}
DEFUN(no_neighbor_disable_addpath_rx,
no_neighbor_disable_addpath_rx_cmd,
"no neighbor <A.B.C.D|X:X::X:X|WORD> disable-addpath-rx",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Do not accept additional paths\n")
{
char *peer_str = argv[2]->arg;
struct peer *peer;
afi_t afi = bgp_node_afi(vty);
safi_t safi = bgp_node_safi(vty);
peer = peer_and_group_lookup_vty(vty, peer_str);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
PEER_FLAG_DISABLE_ADDPATH_RX);
}
DEFUN (neighbor_addpath_tx_all_paths, DEFUN (neighbor_addpath_tx_all_paths,
neighbor_addpath_tx_all_paths_cmd, neighbor_addpath_tx_all_paths_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths", "neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths",
@ -16606,6 +16648,9 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
} }
} }
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DISABLE_ADDPATH_RX))
vty_out(vty, " neighbor %s disable-addpath-rx\n", addr);
/* ORF capability. */ /* ORF capability. */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM)
|| peergroup_af_flag_check(peer, afi, safi, || peergroup_af_flag_check(peer, afi, safi,
@ -18228,6 +18273,24 @@ void bgp_vty_init(void)
install_element(BGP_FLOWSPECV6_NODE, install_element(BGP_FLOWSPECV6_NODE,
&no_neighbor_route_server_client_cmd); &no_neighbor_route_server_client_cmd);
/* "neighbor disable-addpath-rx" commands. */
install_element(BGP_IPV4_NODE, &neighbor_disable_addpath_rx_cmd);
install_element(BGP_IPV4_NODE, &no_neighbor_disable_addpath_rx_cmd);
install_element(BGP_IPV4M_NODE, &neighbor_disable_addpath_rx_cmd);
install_element(BGP_IPV4M_NODE, &no_neighbor_disable_addpath_rx_cmd);
install_element(BGP_IPV4L_NODE, &neighbor_disable_addpath_rx_cmd);
install_element(BGP_IPV4L_NODE, &no_neighbor_disable_addpath_rx_cmd);
install_element(BGP_IPV6_NODE, &neighbor_disable_addpath_rx_cmd);
install_element(BGP_IPV6_NODE, &no_neighbor_disable_addpath_rx_cmd);
install_element(BGP_IPV6M_NODE, &neighbor_disable_addpath_rx_cmd);
install_element(BGP_IPV6M_NODE, &no_neighbor_disable_addpath_rx_cmd);
install_element(BGP_IPV6L_NODE, &neighbor_disable_addpath_rx_cmd);
install_element(BGP_IPV6L_NODE, &no_neighbor_disable_addpath_rx_cmd);
install_element(BGP_VPNV4_NODE, &neighbor_disable_addpath_rx_cmd);
install_element(BGP_VPNV4_NODE, &no_neighbor_disable_addpath_rx_cmd);
install_element(BGP_VPNV6_NODE, &neighbor_disable_addpath_rx_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_disable_addpath_rx_cmd);
/* "neighbor addpath-tx-all-paths" commands.*/ /* "neighbor addpath-tx-all-paths" commands.*/
install_element(BGP_NODE, &neighbor_addpath_tx_all_paths_hidden_cmd); install_element(BGP_NODE, &neighbor_addpath_tx_all_paths_hidden_cmd);
install_element(BGP_NODE, &no_neighbor_addpath_tx_all_paths_hidden_cmd); install_element(BGP_NODE, &no_neighbor_addpath_tx_all_paths_hidden_cmd);

View File

@ -4208,6 +4208,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = {
{PEER_FLAG_AS_OVERRIDE, 1, peer_change_reset_out}, {PEER_FLAG_AS_OVERRIDE, 1, peer_change_reset_out},
{PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE, 1, peer_change_reset_out}, {PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE, 1, peer_change_reset_out},
{PEER_FLAG_WEIGHT, 0, peer_change_reset_in}, {PEER_FLAG_WEIGHT, 0, peer_change_reset_in},
{PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_reset},
{0, 0, 0}}; {0, 0, 0}};
/* Proper action set. */ /* Proper action set. */

View File

@ -1356,6 +1356,7 @@ struct peer {
#define PEER_FLAG_SEND_LARGE_COMMUNITY (1U << 26) /* Send large Communities */ #define PEER_FLAG_SEND_LARGE_COMMUNITY (1U << 26) /* Send large Communities */
#define PEER_FLAG_MAX_PREFIX_OUT (1U << 27) /* outgoing maximum prefix */ #define PEER_FLAG_MAX_PREFIX_OUT (1U << 27) /* outgoing maximum prefix */
#define PEER_FLAG_MAX_PREFIX_FORCE (1U << 28) /* maximum-prefix <num> force */ #define PEER_FLAG_MAX_PREFIX_FORCE (1U << 28) /* maximum-prefix <num> force */
#define PEER_FLAG_DISABLE_ADDPATH_RX (1U << 29) /* disable-addpath-rx */
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX]; enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];

View File

@ -1582,6 +1582,10 @@ Configuring Peers
Configure BGP to send best known paths to neighbor in order to preserve multi Configure BGP to send best known paths to neighbor in order to preserve multi
path capabilities inside a network. path capabilities inside a network.
.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> disable-addpath-rx
Do not accept additional paths from this neighbor.
.. clicmd:: neighbor PEER ttl-security hops NUMBER .. clicmd:: neighbor PEER ttl-security hops NUMBER
This command enforces Generalized TTL Security Mechanism (GTSM), as This command enforces Generalized TTL Security Mechanism (GTSM), as
@ -4375,8 +4379,8 @@ Show command json output:
BGP fast-convergence support BGP fast-convergence support
============================ ============================
Whenever BGP peer address becomes unreachable we must bring down the BGP Whenever BGP peer address becomes unreachable we must bring down the BGP
session immediately. Currently only single-hop EBGP sessions are brought session immediately. Currently only single-hop EBGP sessions are brought
down immediately.IBGP and multi-hop EBGP sessions wait for hold-timer down immediately.IBGP and multi-hop EBGP sessions wait for hold-timer
expiry to bring down the sessions. expiry to bring down the sessions.
This new configuration option helps user to teardown BGP sessions immediately This new configuration option helps user to teardown BGP sessions immediately

View File

@ -0,0 +1,8 @@
!
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.1.2 remote-as external
address-family ipv4 unicast
neighbor 192.168.1.2 disable-addpath-rx
exit-address-family
!

View File

@ -0,0 +1,4 @@
!
int r1-eth0
ip address 192.168.1.1/24
!

View File

@ -0,0 +1,9 @@
router bgp 65002
no bgp ebgp-requires-policy
neighbor 192.168.1.1 remote-as external
neighbor 192.168.2.3 remote-as external
neighbor 192.168.2.4 remote-as external
address-family ipv4 unicast
neighbor 192.168.1.1 addpath-tx-all-paths
exit-address-family
!

View File

@ -0,0 +1,7 @@
!
int r2-eth0
ip address 192.168.1.2/24
!
int r2-eth1
ip address 192.168.2.2/24
!

View File

@ -0,0 +1,7 @@
router bgp 65003
no bgp ebgp-requires-policy
neighbor 192.168.2.2 remote-as external
address-family ipv4 unicast
redistribute connected
exit-address-family
!

View File

@ -0,0 +1,7 @@
!
int lo
ip address 172.16.16.254/32
!
int r3-eth0
ip address 192.168.2.3/24
!

View File

@ -0,0 +1,7 @@
router bgp 65004
no bgp ebgp-requires-policy
neighbor 192.168.2.2 remote-as external
address-family ipv4 unicast
redistribute connected
exit-address-family
!

View File

@ -0,0 +1,7 @@
!
int lo
ip address 172.16.16.254/32
!
int r4-eth0
ip address 192.168.2.4/24
!

View File

@ -0,0 +1,148 @@
#!/usr/bin/env python
# Copyright (c) 2021 by
# Donatas Abraitis <donatas.abraitis@gmail.com>
#
# 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 if AddPath RX direction is not negotiated via AddPath capability.
"""
import os
import sys
import json
import time
import pytest
import functools
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
from mininet.topo import Topo
from lib.common_config import step
pytestmark = [pytest.mark.bgpd]
class TemplateTopo(Topo):
def build(self, *_args, **_opts):
tgen = get_topogen(self)
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("s2")
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r3"])
switch.add_link(tgen.gears["r4"])
def setup_module(mod):
tgen = Topogen(TemplateTopo, 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_disable_addpath_rx():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r1 = tgen.gears["r1"]
r2 = tgen.gears["r2"]
step(
"Check if r2 advertised only 2 paths to r1 (despite addpath-tx-all-paths enabled on r2)."
)
def check_bgp_advertised_routes(router):
output = json.loads(
router.vtysh_cmd(
"show bgp ipv4 unicast neighbor 192.168.1.1 advertised-routes json"
)
)
expected = {
"advertisedRoutes": {
"172.16.16.254/32": {
"addrPrefix": "172.16.16.254",
"prefixLen": 32,
},
"192.168.2.0/24": {
"addrPrefix": "192.168.2.0",
"prefixLen": 24,
},
},
"totalPrefixCounter": 2,
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(check_bgp_advertised_routes, r2)
success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "AddPath TX not working."
step("Check if AddPath RX is disabled on r1 and we receive only 2 paths.")
def check_bgp_disabled_addpath_rx(router):
output = json.loads(router.vtysh_cmd("show bgp neighbor 192.168.1.2 json"))
expected = {
"192.168.1.2": {
"bgpState": "Established",
"neighborCapabilities": {
"addPath": {
"ipv4Unicast": {"txReceived": True, "rxReceived": True}
},
},
"addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}},
}
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(check_bgp_disabled_addpath_rx, r1)
success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "AddPath RX advertised, but should not."
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))