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) {
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. */
bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi,
&pkt_safi);
@ -1541,19 +1546,25 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
stream_putw(s, pkt_afi);
stream_putc(s, pkt_safi);
if (adv_addpath_tx) {
stream_putc(s, BGP_ADDPATH_RX | BGP_ADDPATH_TX);
if (adv_addpath_rx) {
SET_FLAG(flags, BGP_ADDPATH_RX);
SET_FLAG(peer->af_cap[afi][safi],
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],
PEER_CAP_ADDPATH_AF_TX_ADV);
} 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],
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));
}
/* 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,
neighbor_addpath_tx_all_paths_cmd,
"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. */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM)
|| peergroup_af_flag_check(peer, afi, safi,
@ -18228,6 +18273,24 @@ void bgp_vty_init(void)
install_element(BGP_FLOWSPECV6_NODE,
&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.*/
install_element(BGP_NODE, &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_REMOVE_PRIVATE_AS_ALL_REPLACE, 1, peer_change_reset_out},
{PEER_FLAG_WEIGHT, 0, peer_change_reset_in},
{PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_reset},
{0, 0, 0}};
/* 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_MAX_PREFIX_OUT (1U << 27) /* outgoing maximum prefix */
#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];

View File

@ -1582,6 +1582,10 @@ Configuring Peers
Configure BGP to send best known paths to neighbor in order to preserve multi
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
This command enforces Generalized TTL Security Mechanism (GTSM), as
@ -4375,8 +4379,8 @@ Show command json output:
BGP fast-convergence support
============================
Whenever BGP peer address becomes unreachable we must bring down the BGP
session immediately. Currently only single-hop EBGP sessions are brought
down immediately.IBGP and multi-hop EBGP sessions wait for hold-timer
session immediately. Currently only single-hop EBGP sessions are brought
down immediately.IBGP and multi-hop EBGP sessions wait for hold-timer
expiry to bring down the sessions.
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))