Merge pull request #5703 from ton31337/feature/limit_outgoing_prefixes

bgpd: Add an option to limit outgoing prefixes
This commit is contained in:
Donald Sharp 2020-01-18 12:20:44 -05:00 committed by GitHub
commit b6cac82ed9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 257 additions and 2 deletions

View File

@ -143,6 +143,7 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi,
dst->v_routeadv = src->v_routeadv; dst->v_routeadv = src->v_routeadv;
dst->flags = src->flags; dst->flags = src->flags;
dst->af_flags[afi][safi] = src->af_flags[afi][safi]; dst->af_flags[afi][safi] = src->af_flags[afi][safi];
dst->pmax_out[afi][safi] = src->pmax_out[afi][safi];
XFREE(MTYPE_BGP_PEER_HOST, dst->host); XFREE(MTYPE_BGP_PEER_HOST, dst->host);
dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host); dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host);

View File

@ -208,7 +208,7 @@ struct update_subgroup {
struct bgp_synchronize *sync; struct bgp_synchronize *sync;
/* send prefix count */ /* send prefix count */
unsigned long scount; uint32_t scount;
/* announcement attribute hash */ /* announcement attribute hash */
struct hash *hash; struct hash *hash;

View File

@ -744,6 +744,22 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
addpath_tx_id = adj->addpath_tx_id; addpath_tx_id = adj->addpath_tx_id;
path = adv->pathi; path = adv->pathi;
/* Check if we need to add a prefix to the packet if
* maximum-prefix-out is set for the peer.
*/
if (CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_MAX_PREFIX_OUT)
&& subgrp->scount >= peer->pmax_out[afi][safi]) {
if (BGP_DEBUG(update, UPDATE_OUT)
|| BGP_DEBUG(update, UPDATE_PREFIX)) {
zlog_debug(
"%s reached maximum prefix to be send (%" PRIu32
")",
peer->host, peer->pmax_out[afi][safi]);
}
goto next;
}
space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s)) space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
- BGP_MAX_PACKET_SIZE_OVERFLOW; - BGP_MAX_PACKET_SIZE_OVERFLOW;
space_needed = space_needed =
@ -894,7 +910,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
subgrp->scount++; subgrp->scount++;
adj->attr = bgp_attr_intern(adv->baa->attr); adj->attr = bgp_attr_intern(adv->baa->attr);
next:
adv = bgp_advertise_clean_subgroup(subgrp, adj); adv = bgp_advertise_clean_subgroup(subgrp, adj);
} }

View File

@ -6058,6 +6058,56 @@ static int peer_maximum_prefix_unset_vty(struct vty *vty, const char *ip_str,
return bgp_vty_return(vty, ret); return bgp_vty_return(vty, ret);
} }
/* Maximum number of prefix to be sent to the neighbor. */
DEFUN(neighbor_maximum_prefix_out,
neighbor_maximum_prefix_out_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix-out (1-4294967295)",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Maximum number of prefixes to be sent to this peer\n"
"Maximum no. of prefix limit\n")
{
int idx_peer = 1;
int idx_number = 3;
struct peer *peer;
uint32_t max;
afi_t afi = bgp_node_afi(vty);
safi_t safi = bgp_node_safi(vty);
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
max = strtoul(argv[idx_number]->arg, NULL, 10);
SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT);
peer->pmax_out[afi][safi] = max;
return CMD_SUCCESS;
}
DEFUN(no_neighbor_maximum_prefix_out,
no_neighbor_maximum_prefix_out_cmd,
"no neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix-out",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Maximum number of prefixes to be sent to this peer\n")
{
int idx_peer = 2;
struct peer *peer;
afi_t afi = bgp_node_afi(vty);
safi_t safi = bgp_node_safi(vty);
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
peer->pmax_out[afi][safi] = 0;
return CMD_SUCCESS;
}
/* Maximum number of prefix configuration. prefix count is different /* Maximum number of prefix configuration. prefix count is different
for each peer configuration. So this configuration can be set for for each peer configuration. So this configuration can be set for
each peer configuration. */ each peer configuration. */
@ -9190,6 +9240,11 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
json_object_int_add(json_addr, "sentPrefixCounter", json_object_int_add(json_addr, "sentPrefixCounter",
(PAF_SUBGRP(paf))->scount); (PAF_SUBGRP(paf))->scount);
/* Maximum prefix */
if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT))
json_object_int_add(json_addr, "prefixOutAllowedMax",
p->pmax_out[afi][safi]);
/* Maximum prefix */ /* Maximum prefix */
if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) { if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) {
json_object_int_add(json_addr, "prefixAllowedMax", json_object_int_add(json_addr, "prefixAllowedMax",
@ -9476,6 +9531,13 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
vty_out(vty, " %" PRIu32 " accepted prefixes\n", vty_out(vty, " %" PRIu32 " accepted prefixes\n",
p->pcount[afi][safi]); p->pcount[afi][safi]);
/* maximum-prefix-out */
if (CHECK_FLAG(p->af_flags[afi][safi],
PEER_FLAG_MAX_PREFIX_OUT))
vty_out(vty,
" Maximum allowed prefixes sent %" PRIu32 "\n",
p->pmax_out[afi][safi]);
/* Maximum prefix */ /* Maximum prefix */
if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) { if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) {
vty_out(vty, vty_out(vty,
@ -13579,6 +13641,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
/* maximum-prefix-out */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MAX_PREFIX_OUT))
vty_out(vty, " neighbor %s maximum-prefix-out %" PRIu32 "\n",
addr, peer->pmax_out[afi][safi]);
/* Route server client. */ /* Route server client. */
if (peergroup_af_flag_check(peer, afi, safi, if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_RSERVER_CLIENT)) { PEER_FLAG_RSERVER_CLIENT)) {
@ -15115,6 +15182,26 @@ void bgp_vty_init(void)
install_element(BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd); install_element(BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd);
/* neighbor maximum-prefix-out commands. */
install_element(BGP_NODE, &neighbor_maximum_prefix_out_cmd);
install_element(BGP_NODE, &no_neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV4_NODE, &neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV4_NODE, &no_neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV4M_NODE, &neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV4L_NODE, &neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV4L_NODE, &no_neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV6_NODE, &neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV6_NODE, &no_neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV6M_NODE, &neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV6L_NODE, &neighbor_maximum_prefix_out_cmd);
install_element(BGP_IPV6L_NODE, &no_neighbor_maximum_prefix_out_cmd);
install_element(BGP_VPNV4_NODE, &neighbor_maximum_prefix_out_cmd);
install_element(BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_out_cmd);
install_element(BGP_VPNV6_NODE, &neighbor_maximum_prefix_out_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_out_cmd);
/* "neighbor maximum-prefix" commands. */ /* "neighbor maximum-prefix" commands. */
install_element(BGP_NODE, &neighbor_maximum_prefix_hidden_cmd); install_element(BGP_NODE, &neighbor_maximum_prefix_hidden_cmd);
install_element(BGP_NODE, install_element(BGP_NODE,

View File

@ -988,6 +988,7 @@ struct peer {
#define PEER_FLAG_WEIGHT (1 << 24) /* weight */ #define PEER_FLAG_WEIGHT (1 << 24) /* weight */
#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */ #define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */
#define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 26) /* Send large Communities */ #define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 26) /* Send large Communities */
#define PEER_FLAG_MAX_PREFIX_OUT (1 << 27) /* outgoing maximum prefix */
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX]; enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
@ -1170,6 +1171,9 @@ struct peer {
uint16_t pmax_restart[AFI_MAX][SAFI_MAX]; uint16_t pmax_restart[AFI_MAX][SAFI_MAX];
#define MAXIMUM_PREFIX_THRESHOLD_DEFAULT 75 #define MAXIMUM_PREFIX_THRESHOLD_DEFAULT 75
/* Send prefix count. */
uint32_t pmax_out[AFI_MAX][SAFI_MAX];
/* allowas-in. */ /* allowas-in. */
char allowas_in[AFI_MAX][SAFI_MAX]; char allowas_in[AFI_MAX][SAFI_MAX];

View File

@ -1075,6 +1075,11 @@ Configuring Peers
granular and offers much smarter matching criterion than number of received granular and offers much smarter matching criterion than number of received
prefixes, making it more suited to implementing policy. prefixes, making it more suited to implementing policy.
.. index:: [no] neighbor PEER maximum-prefix-out NUMBER
.. clicmd:: [no] neighbor PEER maximum-prefix-out NUMBER
Sets a maximum number of prefixes we can send to a given peer.
.. index:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as] .. index:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as]
.. clicmd:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as] .. clicmd:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as]

View File

@ -0,0 +1,9 @@
!
router bgp 65001
neighbor 192.168.255.1 remote-as 65002
address-family ipv4 unicast
redistribute connected
neighbor 192.168.255.1 maximum-prefix-out 2
exit-address-family
!
!

View File

@ -0,0 +1,13 @@
!
interface lo
ip address 172.16.255.250/32
ip address 172.16.255.251/32
ip address 172.16.255.252/32
ip address 172.16.255.253/32
ip address 172.16.255.254/32
!
interface r1-eth0
ip address 192.168.255.2/30
!
ip forwarding
!

View File

@ -0,0 +1,6 @@
!
router bgp 65002
neighbor 192.168.255.2 remote-as 65001
exit-address-family
!
!

View File

@ -0,0 +1,6 @@
!
interface r2-eth0
ip address 192.168.255.1/30
!
ip forwarding
!

View File

@ -0,0 +1,108 @@
#!/usr/bin/env python
#
# test_bgp_maximum_prefix_out.py
# Part of NetDEF Topology Tests
#
# Copyright (c) 2020 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 `neighbor <X.X.X.X> maximum-prefix-out <Y>` is working
correctly.
"""
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
class TemplateTopo(Topo):
def build(self, *_args, **_opts):
tgen = get_topogen(self)
for routern in range(1, 3):
tgen.add_router('r{}'.format(routern))
switch = tgen.add_switch('s1')
switch.add_link(tgen.gears['r1'])
switch.add_link(tgen.gears['r2'])
def setup_module(mod):
tgen = Topogen(TemplateTopo, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
for i, (rname, router) in enumerate(router_list.iteritems(), 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_maximum_prefix_out():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
router = tgen.gears['r2']
def _bgp_converge(router):
output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json"))
expected = {
'192.168.255.2': {
'bgpState': 'Established',
'addressFamilyInfo': {
'ipv4Unicast': {
'acceptedPrefixCounter': 2
}
}
}
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(_bgp_converge, router)
success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, 'Failed bgp convergence in "{}"'.format(router)
if __name__ == '__main__':
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))