mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-07 01:40:16 +00:00
Merge pull request #7507 from ton31337/fix/bgpd_do_not_send_update_if_path_really_did_not_change
bgpd: Do not send BGP UPDATE if the route actually not changed
This commit is contained in:
commit
ee117a8bd6
@ -83,6 +83,9 @@ struct bgp_adj_out {
|
|||||||
|
|
||||||
/* Advertisement information. */
|
/* Advertisement information. */
|
||||||
struct bgp_advertise *adv;
|
struct bgp_advertise *adv;
|
||||||
|
|
||||||
|
/* Attribute hash */
|
||||||
|
uint32_t attr_hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
RB_HEAD(bgp_adj_out_rb, bgp_adj_out);
|
RB_HEAD(bgp_adj_out_rb, bgp_adj_out);
|
||||||
|
@ -351,6 +351,13 @@ const struct frr_yang_module_info frr_bgp_info = {
|
|||||||
.modify = bgp_global_ebgp_requires_policy_modify,
|
.modify = bgp_global_ebgp_requires_policy_modify,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/global/suppress-duplicates",
|
||||||
|
.cbs = {
|
||||||
|
.cli_show = cli_show_router_bgp_suppress_duplicates,
|
||||||
|
.modify = bgp_global_suppress_duplicates_modify,
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/global/show-hostname",
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/global/show-hostname",
|
||||||
.cbs = {
|
.cbs = {
|
||||||
|
@ -127,6 +127,7 @@ int bgp_global_fast_external_failover_modify(struct nb_cb_modify_args *args);
|
|||||||
int bgp_global_local_pref_modify(struct nb_cb_modify_args *args);
|
int bgp_global_local_pref_modify(struct nb_cb_modify_args *args);
|
||||||
int bgp_global_default_shutdown_modify(struct nb_cb_modify_args *args);
|
int bgp_global_default_shutdown_modify(struct nb_cb_modify_args *args);
|
||||||
int bgp_global_ebgp_requires_policy_modify(struct nb_cb_modify_args *args);
|
int bgp_global_ebgp_requires_policy_modify(struct nb_cb_modify_args *args);
|
||||||
|
int bgp_global_suppress_duplicates_modify(struct nb_cb_modify_args *args);
|
||||||
int bgp_global_show_hostname_modify(struct nb_cb_modify_args *args);
|
int bgp_global_show_hostname_modify(struct nb_cb_modify_args *args);
|
||||||
int bgp_global_show_nexthop_hostname_modify(struct nb_cb_modify_args *args);
|
int bgp_global_show_nexthop_hostname_modify(struct nb_cb_modify_args *args);
|
||||||
int bgp_global_import_check_modify(struct nb_cb_modify_args *args);
|
int bgp_global_import_check_modify(struct nb_cb_modify_args *args);
|
||||||
@ -3639,6 +3640,9 @@ void cli_show_router_bgp_route_selection(struct vty *vty,
|
|||||||
void cli_show_router_bgp_ebgp_requires_policy(struct vty *vty,
|
void cli_show_router_bgp_ebgp_requires_policy(struct vty *vty,
|
||||||
struct lyd_node *dnode,
|
struct lyd_node *dnode,
|
||||||
bool show_defaults);
|
bool show_defaults);
|
||||||
|
void cli_show_router_bgp_suppress_duplicates(struct vty *vty,
|
||||||
|
struct lyd_node *dnode,
|
||||||
|
bool show_defaults);
|
||||||
void cli_show_router_bgp_default_shutdown(struct vty *vty,
|
void cli_show_router_bgp_default_shutdown(struct vty *vty,
|
||||||
struct lyd_node *dnode,
|
struct lyd_node *dnode,
|
||||||
bool show_defaults);
|
bool show_defaults);
|
||||||
|
@ -1597,6 +1597,27 @@ int bgp_global_ebgp_requires_policy_modify(struct nb_cb_modify_args *args)
|
|||||||
return NB_OK;
|
return NB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XPath:
|
||||||
|
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/global/suppress-duplicates
|
||||||
|
*/
|
||||||
|
int bgp_global_suppress_duplicates_modify(struct nb_cb_modify_args *args)
|
||||||
|
{
|
||||||
|
if (args->event != NB_EV_APPLY)
|
||||||
|
return NB_OK;
|
||||||
|
|
||||||
|
struct bgp *bgp;
|
||||||
|
|
||||||
|
bgp = nb_running_get_entry(args->dnode, NULL, true);
|
||||||
|
|
||||||
|
if (yang_dnode_get_bool(args->dnode, NULL))
|
||||||
|
SET_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES);
|
||||||
|
else
|
||||||
|
UNSET_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES);
|
||||||
|
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XPath:
|
* XPath:
|
||||||
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/global/show-hostname
|
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/global/show-hostname
|
||||||
|
@ -444,6 +444,13 @@ int bgp_generate_updgrp_packets(struct thread *thread)
|
|||||||
* yet.
|
* yet.
|
||||||
*/
|
*/
|
||||||
if (!next_pkt || !next_pkt->buffer) {
|
if (!next_pkt || !next_pkt->buffer) {
|
||||||
|
/* Make sure we supress BGP UPDATES
|
||||||
|
* for normal processing later again.
|
||||||
|
*/
|
||||||
|
if (!paf->t_announce_route)
|
||||||
|
UNSET_FLAG(paf->subgroup->sflags,
|
||||||
|
SUBGRP_STATUS_FORCE_UPDATES);
|
||||||
|
|
||||||
if (CHECK_FLAG(peer->cap,
|
if (CHECK_FLAG(peer->cap,
|
||||||
PEER_CAP_RESTART_RCV)) {
|
PEER_CAP_RESTART_RCV)) {
|
||||||
if (!(PAF_SUBGRP(paf))->t_coalesce
|
if (!(PAF_SUBGRP(paf))->t_coalesce
|
||||||
@ -2116,6 +2123,11 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
|
|||||||
peer->orf_plist[afi][safi];
|
peer->orf_plist[afi][safi];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Avoid supressing duplicate routes later
|
||||||
|
* when processing in subgroup_announce_table().
|
||||||
|
*/
|
||||||
|
SET_FLAG(paf->subgroup->sflags, SUBGRP_STATUS_FORCE_UPDATES);
|
||||||
|
|
||||||
/* If the peer is configured for default-originate clear the
|
/* If the peer is configured for default-originate clear the
|
||||||
* SUBGRP_STATUS_DEFAULT_ORIGINATE flag so that we will
|
* SUBGRP_STATUS_DEFAULT_ORIGINATE flag so that we will
|
||||||
* re-advertise the
|
* re-advertise the
|
||||||
|
@ -1387,6 +1387,11 @@ static int updgrp_policy_update_walkcb(struct update_group *updgrp, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
|
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
|
||||||
|
/* Avoid supressing duplicate routes later
|
||||||
|
* when processing in subgroup_announce_table().
|
||||||
|
*/
|
||||||
|
SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
if (bgp_debug_update(NULL, NULL, updgrp, 0))
|
if (bgp_debug_update(NULL, NULL, updgrp, 0))
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
|
@ -252,19 +252,13 @@ struct update_subgroup {
|
|||||||
uint64_t id;
|
uint64_t id;
|
||||||
|
|
||||||
uint16_t sflags;
|
uint16_t sflags;
|
||||||
|
#define SUBGRP_STATUS_DEFAULT_ORIGINATE (1 << 0)
|
||||||
|
#define SUBGRP_STATUS_FORCE_UPDATES (1 << 1)
|
||||||
|
|
||||||
/* Subgroup flags, see below */
|
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
|
#define SUBGRP_FLAG_NEEDS_REFRESH (1 << 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* We need to do an outbound refresh to get this subgroup into a
|
|
||||||
* consistent state.
|
|
||||||
*/
|
|
||||||
#define SUBGRP_FLAG_NEEDS_REFRESH (1 << 0)
|
|
||||||
|
|
||||||
#define SUBGRP_STATUS_DEFAULT_ORIGINATE (1 << 0)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add the given value to the specified counter on a subgroup and its
|
* Add the given value to the specified counter on a subgroup and its
|
||||||
* parent structures.
|
* parent structures.
|
||||||
|
@ -464,6 +464,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest,
|
|||||||
struct peer *adv_peer;
|
struct peer *adv_peer;
|
||||||
struct peer_af *paf;
|
struct peer_af *paf;
|
||||||
struct bgp *bgp;
|
struct bgp *bgp;
|
||||||
|
uint32_t attr_hash = attrhash_key_make(attr);
|
||||||
|
|
||||||
peer = SUBGRP_PEER(subgrp);
|
peer = SUBGRP_PEER(subgrp);
|
||||||
afi = SUBGRP_AFI(subgrp);
|
afi = SUBGRP_AFI(subgrp);
|
||||||
@ -487,6 +488,26 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if we are sending the same route. This is needed to
|
||||||
|
* avoid duplicate UPDATES. For instance, filtering communities
|
||||||
|
* at egress, neighbors will see duplicate UPDATES despite
|
||||||
|
* the route wasn't changed actually.
|
||||||
|
* Do not suppress BGP UPDATES for route-refresh.
|
||||||
|
*/
|
||||||
|
if (CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES)
|
||||||
|
&& !CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES)
|
||||||
|
&& adj->attr_hash == attr_hash) {
|
||||||
|
if (BGP_DEBUG(update, UPDATE_OUT)) {
|
||||||
|
char attr_str[BUFSIZ] = {0};
|
||||||
|
|
||||||
|
bgp_dump_attr(attr, attr_str, sizeof(attr_str));
|
||||||
|
|
||||||
|
zlog_debug("%s suppress UPDATE w/ attr: %s", peer->host,
|
||||||
|
attr_str);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (adj->adv)
|
if (adj->adv)
|
||||||
bgp_advertise_clean_subgroup(subgrp, adj);
|
bgp_advertise_clean_subgroup(subgrp, adj);
|
||||||
adj->adv = bgp_advertise_new();
|
adj->adv = bgp_advertise_new();
|
||||||
@ -502,6 +523,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest,
|
|||||||
else
|
else
|
||||||
adv->baa = baa_new();
|
adv->baa = baa_new();
|
||||||
adv->adj = adj;
|
adv->adj = adj;
|
||||||
|
adj->attr_hash = attr_hash;
|
||||||
|
|
||||||
/* Add new advertisement to advertisement attribute list. */
|
/* Add new advertisement to advertisement attribute list. */
|
||||||
bgp_advertise_add(adv->baa, adv);
|
bgp_advertise_add(adv->baa, adv);
|
||||||
|
@ -119,6 +119,10 @@ FRR_CFG_DEFAULT_BOOL(BGP_EBGP_REQUIRES_POLICY,
|
|||||||
{ .val_bool = false, .match_version = "< 7.4", },
|
{ .val_bool = false, .match_version = "< 7.4", },
|
||||||
{ .val_bool = true },
|
{ .val_bool = true },
|
||||||
)
|
)
|
||||||
|
FRR_CFG_DEFAULT_BOOL(BGP_SUPPRESS_DUPLICATES,
|
||||||
|
{ .val_bool = false, .match_version = "< 7.6", },
|
||||||
|
{ .val_bool = true },
|
||||||
|
)
|
||||||
|
|
||||||
DEFINE_HOOK(bgp_inst_config_write,
|
DEFINE_HOOK(bgp_inst_config_write,
|
||||||
(struct bgp *bgp, struct vty *vty),
|
(struct bgp *bgp, struct vty *vty),
|
||||||
@ -487,6 +491,8 @@ int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
|
|||||||
SET_FLAG((*bgp)->flags, BGP_FLAG_DETERMINISTIC_MED);
|
SET_FLAG((*bgp)->flags, BGP_FLAG_DETERMINISTIC_MED);
|
||||||
if (DFLT_BGP_EBGP_REQUIRES_POLICY)
|
if (DFLT_BGP_EBGP_REQUIRES_POLICY)
|
||||||
SET_FLAG((*bgp)->flags, BGP_FLAG_EBGP_REQUIRES_POLICY);
|
SET_FLAG((*bgp)->flags, BGP_FLAG_EBGP_REQUIRES_POLICY);
|
||||||
|
if (DFLT_BGP_SUPPRESS_DUPLICATES)
|
||||||
|
SET_FLAG((*bgp)->flags, BGP_FLAG_SUPPRESS_DUPLICATES);
|
||||||
|
|
||||||
ret = BGP_SUCCESS;
|
ret = BGP_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -876,6 +882,7 @@ static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi,
|
|||||||
struct listnode **nnode, enum bgp_clear_type stype)
|
struct listnode **nnode, enum bgp_clear_type stype)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct peer_af *paf;
|
||||||
|
|
||||||
/* if afi/.safi not specified, spin thru all of them */
|
/* if afi/.safi not specified, spin thru all of them */
|
||||||
if ((afi == AFI_UNSPEC) && (safi == SAFI_UNSPEC)) {
|
if ((afi == AFI_UNSPEC) && (safi == SAFI_UNSPEC)) {
|
||||||
@ -883,6 +890,11 @@ static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi,
|
|||||||
safi_t tmp_safi;
|
safi_t tmp_safi;
|
||||||
|
|
||||||
FOREACH_AFI_SAFI (tmp_afi, tmp_safi) {
|
FOREACH_AFI_SAFI (tmp_afi, tmp_safi) {
|
||||||
|
paf = peer_af_find(peer, tmp_afi, tmp_safi);
|
||||||
|
if (paf && paf->subgroup)
|
||||||
|
SET_FLAG(paf->subgroup->sflags,
|
||||||
|
SUBGRP_STATUS_FORCE_UPDATES);
|
||||||
|
|
||||||
if (!peer->afc[tmp_afi][tmp_safi])
|
if (!peer->afc[tmp_afi][tmp_safi])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -901,6 +913,11 @@ static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi,
|
|||||||
if (!peer->afc[afi][tmp_safi])
|
if (!peer->afc[afi][tmp_safi])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
paf = peer_af_find(peer, afi, tmp_safi);
|
||||||
|
if (paf && paf->subgroup)
|
||||||
|
SET_FLAG(paf->subgroup->sflags,
|
||||||
|
SUBGRP_STATUS_FORCE_UPDATES);
|
||||||
|
|
||||||
if (stype == BGP_CLEAR_SOFT_NONE)
|
if (stype == BGP_CLEAR_SOFT_NONE)
|
||||||
ret = peer_clear(peer, nnode);
|
ret = peer_clear(peer, nnode);
|
||||||
else
|
else
|
||||||
@ -912,6 +929,11 @@ static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi,
|
|||||||
if (!peer->afc[afi][safi])
|
if (!peer->afc[afi][safi])
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
paf = peer_af_find(peer, afi, safi);
|
||||||
|
if (paf && paf->subgroup)
|
||||||
|
SET_FLAG(paf->subgroup->sflags,
|
||||||
|
SUBGRP_STATUS_FORCE_UPDATES);
|
||||||
|
|
||||||
if (stype == BGP_CLEAR_SOFT_NONE)
|
if (stype == BGP_CLEAR_SOFT_NONE)
|
||||||
ret = peer_clear(peer, nnode);
|
ret = peer_clear(peer, nnode);
|
||||||
else
|
else
|
||||||
@ -2555,6 +2577,37 @@ DEFUN_YANG(no_bgp_always_compare_med,
|
|||||||
return nb_cli_apply_changes(vty, NULL);
|
return nb_cli_apply_changes(vty, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN_YANG(bgp_suppress_duplicates,
|
||||||
|
bgp_suppress_duplicates_cmd,
|
||||||
|
"bgp suppress-duplicates",
|
||||||
|
"BGP specific commands\n"
|
||||||
|
"Suppress duplicate updates if the route actually not changed\n")
|
||||||
|
{
|
||||||
|
nb_cli_enqueue_change(vty, "./global/suppress-duplicates",
|
||||||
|
NB_OP_MODIFY, "true");
|
||||||
|
return nb_cli_apply_changes(vty, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN_YANG(no_bgp_suppress_duplicates,
|
||||||
|
no_bgp_suppress_duplicates_cmd,
|
||||||
|
"no bgp suppress-duplicates",
|
||||||
|
NO_STR
|
||||||
|
"BGP specific commands\n"
|
||||||
|
"Suppress duplicate updates if the route actually not changed\n")
|
||||||
|
{
|
||||||
|
nb_cli_enqueue_change(vty, "./global/suppress-duplicates",
|
||||||
|
NB_OP_MODIFY, "false");
|
||||||
|
return nb_cli_apply_changes(vty, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_show_router_bgp_suppress_duplicates(struct vty *vty,
|
||||||
|
struct lyd_node *dnode,
|
||||||
|
bool show_defaults)
|
||||||
|
{
|
||||||
|
if (yang_dnode_get_bool(dnode, NULL) != SAVE_BGP_SUPPRESS_DUPLICATES)
|
||||||
|
vty_out(vty, " bgp suppress-duplicates\n");
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN_YANG(bgp_ebgp_requires_policy,
|
DEFUN_YANG(bgp_ebgp_requires_policy,
|
||||||
bgp_ebgp_requires_policy_cmd,
|
bgp_ebgp_requires_policy_cmd,
|
||||||
"bgp ebgp-requires-policy",
|
"bgp ebgp-requires-policy",
|
||||||
@ -17031,6 +17084,16 @@ int bgp_config_write(struct vty *vty)
|
|||||||
if (bgp->reject_as_sets)
|
if (bgp->reject_as_sets)
|
||||||
vty_out(vty, " bgp reject-as-sets\n");
|
vty_out(vty, " bgp reject-as-sets\n");
|
||||||
|
|
||||||
|
/* Suppress duplicate updates if the route actually not changed
|
||||||
|
*/
|
||||||
|
if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES)
|
||||||
|
!= SAVE_BGP_SUPPRESS_DUPLICATES)
|
||||||
|
vty_out(vty, " %sbgp suppress-duplicates\n",
|
||||||
|
CHECK_FLAG(bgp->flags,
|
||||||
|
BGP_FLAG_SUPPRESS_DUPLICATES)
|
||||||
|
? ""
|
||||||
|
: "no ");
|
||||||
|
|
||||||
/* BGP default ipv4-unicast. */
|
/* BGP default ipv4-unicast. */
|
||||||
if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4))
|
if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4))
|
||||||
vty_out(vty, " no bgp default ipv4-unicast\n");
|
vty_out(vty, " no bgp default ipv4-unicast\n");
|
||||||
@ -17614,6 +17677,10 @@ void bgp_vty_init(void)
|
|||||||
install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd);
|
install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd);
|
||||||
install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd);
|
install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd);
|
||||||
|
|
||||||
|
/* bgp suppress-duplicates */
|
||||||
|
install_element(BGP_NODE, &bgp_suppress_duplicates_cmd);
|
||||||
|
install_element(BGP_NODE, &no_bgp_suppress_duplicates_cmd);
|
||||||
|
|
||||||
/* bgp reject-as-sets */
|
/* bgp reject-as-sets */
|
||||||
install_element(BGP_NODE, &bgp_reject_as_sets_cmd);
|
install_element(BGP_NODE, &bgp_reject_as_sets_cmd);
|
||||||
install_element(BGP_NODE, &no_bgp_reject_as_sets_cmd);
|
install_element(BGP_NODE, &no_bgp_reject_as_sets_cmd);
|
||||||
|
@ -464,6 +464,7 @@ struct bgp {
|
|||||||
/* This flag is set if the instance is in administrative shutdown */
|
/* This flag is set if the instance is in administrative shutdown */
|
||||||
#define BGP_FLAG_SHUTDOWN (1 << 27)
|
#define BGP_FLAG_SHUTDOWN (1 << 27)
|
||||||
#define BGP_FLAG_SUPPRESS_FIB_PENDING (1 << 28)
|
#define BGP_FLAG_SUPPRESS_FIB_PENDING (1 << 28)
|
||||||
|
#define BGP_FLAG_SUPPRESS_DUPLICATES (1 << 29)
|
||||||
|
|
||||||
enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE]
|
enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE]
|
||||||
[BGP_GLOBAL_GR_EVENT_CMD];
|
[BGP_GLOBAL_GR_EVENT_CMD];
|
||||||
|
@ -454,6 +454,17 @@ Reject routes with AS_SET or AS_CONFED_SET types
|
|||||||
|
|
||||||
This command enables rejection of incoming and outgoing routes having AS_SET or AS_CONFED_SET type.
|
This command enables rejection of incoming and outgoing routes having AS_SET or AS_CONFED_SET type.
|
||||||
|
|
||||||
|
Suppress duplicate updates
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. index:: [no] bgp suppress-duplicates
|
||||||
|
.. clicmd:: [no] bgp suppress-duplicates
|
||||||
|
|
||||||
|
For example, BGP routers can generate multiple identical announcements with
|
||||||
|
empty community attributes if stripped at egress. This is an undesired behavior.
|
||||||
|
Suppress duplicate updates if the route actually not changed.
|
||||||
|
Default: enabled.
|
||||||
|
|
||||||
Disable checking if nexthop is connected on EBGP sessions
|
Disable checking if nexthop is connected on EBGP sessions
|
||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
11
tests/topotests/bgp_community_change_update/c1/bgpd.conf
Normal file
11
tests/topotests/bgp_community_change_update/c1/bgpd.conf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
!
|
||||||
|
debug bgp updates
|
||||||
|
!
|
||||||
|
router bgp 65001
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
neighbor 10.0.1.2 remote-as external
|
||||||
|
neighbor 10.0.1.2 timers 3 10
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute connected
|
||||||
|
exit-address-family
|
||||||
|
!
|
@ -0,0 +1,6 @@
|
|||||||
|
!
|
||||||
|
interface c1-eth0
|
||||||
|
ip address 10.0.1.1/30
|
||||||
|
!
|
||||||
|
ip forwarding
|
||||||
|
!
|
@ -0,0 +1,225 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Reference: https://www.cmand.org/communityexploration
|
||||||
|
|
||||||
|
--y2--
|
||||||
|
/ | \
|
||||||
|
c1 ---- x1 ---- y1 | z1
|
||||||
|
\ | /
|
||||||
|
--y3--
|
||||||
|
|
||||||
|
1. z1 announces 192.168.255.254/32 to y2, y3.
|
||||||
|
2. y2 and y3 tags this prefix at ingress with appropriate
|
||||||
|
communities 65004:2 (y2) and 65004:3 (y3).
|
||||||
|
3. x1 filters all communities at the egress to c1.
|
||||||
|
4. Shutdown the link between y1 and y2.
|
||||||
|
5. y1 will generate a BGP UPDATE message regarding the next-hop change.
|
||||||
|
6. x1 will generate a BGP UPDATE message regarding community change.
|
||||||
|
|
||||||
|
To avoid sending duplicate BGP UPDATE messages we should make sure
|
||||||
|
we send only actual route updates. In this example, x1 will skip
|
||||||
|
BGP UPDATE to c1 because the actual route is the same
|
||||||
|
(filtered communities - nothing changes).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
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
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateTopo(Topo):
|
||||||
|
def build(self, *_args, **_opts):
|
||||||
|
tgen = get_topogen(self)
|
||||||
|
|
||||||
|
tgen.add_router("z1")
|
||||||
|
tgen.add_router("y1")
|
||||||
|
tgen.add_router("y2")
|
||||||
|
tgen.add_router("y3")
|
||||||
|
tgen.add_router("x1")
|
||||||
|
tgen.add_router("c1")
|
||||||
|
|
||||||
|
# 10.0.1.0/30
|
||||||
|
switch = tgen.add_switch("s1")
|
||||||
|
switch.add_link(tgen.gears["c1"])
|
||||||
|
switch.add_link(tgen.gears["x1"])
|
||||||
|
|
||||||
|
# 10.0.2.0/30
|
||||||
|
switch = tgen.add_switch("s2")
|
||||||
|
switch.add_link(tgen.gears["x1"])
|
||||||
|
switch.add_link(tgen.gears["y1"])
|
||||||
|
|
||||||
|
# 10.0.3.0/30
|
||||||
|
switch = tgen.add_switch("s3")
|
||||||
|
switch.add_link(tgen.gears["y1"])
|
||||||
|
switch.add_link(tgen.gears["y2"])
|
||||||
|
|
||||||
|
# 10.0.4.0/30
|
||||||
|
switch = tgen.add_switch("s4")
|
||||||
|
switch.add_link(tgen.gears["y1"])
|
||||||
|
switch.add_link(tgen.gears["y3"])
|
||||||
|
|
||||||
|
# 10.0.5.0/30
|
||||||
|
switch = tgen.add_switch("s5")
|
||||||
|
switch.add_link(tgen.gears["y2"])
|
||||||
|
switch.add_link(tgen.gears["y3"])
|
||||||
|
|
||||||
|
# 10.0.6.0/30
|
||||||
|
switch = tgen.add_switch("s6")
|
||||||
|
switch.add_link(tgen.gears["y2"])
|
||||||
|
switch.add_link(tgen.gears["z1"])
|
||||||
|
|
||||||
|
# 10.0.7.0/30
|
||||||
|
switch = tgen.add_switch("s7")
|
||||||
|
switch.add_link(tgen.gears["y3"])
|
||||||
|
switch.add_link(tgen.gears["z1"])
|
||||||
|
|
||||||
|
|
||||||
|
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_community_update_path_change():
|
||||||
|
tgen = get_topogen()
|
||||||
|
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
def _bgp_converge_initial():
|
||||||
|
output = json.loads(
|
||||||
|
tgen.gears["c1"].vtysh_cmd("show ip bgp neighbor 10.0.1.2 json")
|
||||||
|
)
|
||||||
|
expected = {
|
||||||
|
"10.0.1.2": {
|
||||||
|
"bgpState": "Established",
|
||||||
|
"addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 8}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
step("Check if an initial topology is converged")
|
||||||
|
test_func = functools.partial(_bgp_converge_initial)
|
||||||
|
success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||||
|
assert result is None, "Failed to see bgp convergence in c1"
|
||||||
|
|
||||||
|
step("Disable link between y1 and y2")
|
||||||
|
tgen.gears["y1"].run("ip link set dev y1-eth1 down")
|
||||||
|
|
||||||
|
def _bgp_converge_link_disabled():
|
||||||
|
output = json.loads(tgen.gears["y1"].vtysh_cmd("show ip bgp nei 10.0.3.2 json"))
|
||||||
|
expected = {"10.0.3.2": {"bgpState": "Active"}}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
step("Check if a topology is converged after a link down between y1 and y2")
|
||||||
|
test_func = functools.partial(_bgp_converge_link_disabled)
|
||||||
|
success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||||
|
assert result is None, "Failed to see bgp convergence in y1"
|
||||||
|
|
||||||
|
def _bgp_check_for_duplicate_updates():
|
||||||
|
duplicate = False
|
||||||
|
i = 0
|
||||||
|
while i < 5:
|
||||||
|
if (
|
||||||
|
len(
|
||||||
|
tgen.gears["c1"].run(
|
||||||
|
'grep "10.0.1.2 rcvd 192.168.255.254/32 IPv4 unicast...duplicate ignored" bgpd.log'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
> 0
|
||||||
|
):
|
||||||
|
duplicate = True
|
||||||
|
i += 1
|
||||||
|
sleep(0.5)
|
||||||
|
return duplicate
|
||||||
|
|
||||||
|
step("Check if we see duplicate BGP UPDATE message in c1 (suppress-duplicates)")
|
||||||
|
assert (
|
||||||
|
_bgp_check_for_duplicate_updates() == False
|
||||||
|
), "Seen duplicate BGP UPDATE message in c1 from x1"
|
||||||
|
|
||||||
|
step("Disable bgp suppress-duplicates at x1")
|
||||||
|
tgen.gears["x1"].run(
|
||||||
|
"vtysh -c 'conf' -c 'router bgp' -c 'no bgp suppress-duplicates'"
|
||||||
|
)
|
||||||
|
|
||||||
|
step("Enable link between y1 and y2")
|
||||||
|
tgen.gears["y1"].run("ip link set dev y1-eth1 up")
|
||||||
|
|
||||||
|
def _bgp_converge_link_enabled():
|
||||||
|
output = json.loads(tgen.gears["y1"].vtysh_cmd("show ip bgp nei 10.0.3.2 json"))
|
||||||
|
expected = {
|
||||||
|
"10.0.3.2": {
|
||||||
|
"bgpState": "Established",
|
||||||
|
"addressFamilyInfo": {
|
||||||
|
"ipv4Unicast": {"acceptedPrefixCounter": 5, "sentPrefixCounter": 4}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
step("Check if a topology is converged after a link up between y1 and y2")
|
||||||
|
test_func = functools.partial(_bgp_converge_link_enabled)
|
||||||
|
success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||||
|
assert result is None, "Failed to see bgp convergence in y1"
|
||||||
|
|
||||||
|
step(
|
||||||
|
"Check if we see duplicate BGP UPDATE message in c1 (no bgp suppress-duplicates)"
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
_bgp_check_for_duplicate_updates() == True
|
||||||
|
), "Didn't see duplicate BGP UPDATE message in c1 from x1"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = ["-s"] + sys.argv[1:]
|
||||||
|
sys.exit(pytest.main(args))
|
20
tests/topotests/bgp_community_change_update/x1/bgpd.conf
Normal file
20
tests/topotests/bgp_community_change_update/x1/bgpd.conf
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
!
|
||||||
|
debug bgp updates
|
||||||
|
!
|
||||||
|
router bgp 65002
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
neighbor 10.0.1.1 remote-as external
|
||||||
|
neighbor 10.0.1.1 timers 3 10
|
||||||
|
neighbor 10.0.2.2 remote-as external
|
||||||
|
neighbor 10.0.2.2 timers 3 10
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute connected
|
||||||
|
neighbor 10.0.1.1 route-map c1 out
|
||||||
|
exit-address-family
|
||||||
|
!
|
||||||
|
bgp community-list standard c1 seq 1 permit 65004:2
|
||||||
|
bgp community-list standard c1 seq 2 permit 65004:3
|
||||||
|
!
|
||||||
|
route-map c1 permit 10
|
||||||
|
set comm-list c1 delete
|
||||||
|
!
|
@ -0,0 +1,9 @@
|
|||||||
|
!
|
||||||
|
interface x1-eth0
|
||||||
|
ip address 10.0.1.2/30
|
||||||
|
!
|
||||||
|
interface x1-eth1
|
||||||
|
ip address 10.0.2.1/30
|
||||||
|
!
|
||||||
|
ip forwarding
|
||||||
|
!
|
12
tests/topotests/bgp_community_change_update/y1/bgpd.conf
Normal file
12
tests/topotests/bgp_community_change_update/y1/bgpd.conf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
router bgp 65003
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
neighbor 10.0.2.1 remote-as external
|
||||||
|
neighbor 10.0.2.1 timers 3 10
|
||||||
|
neighbor 10.0.3.2 remote-as internal
|
||||||
|
neighbor 10.0.3.2 timers 3 10
|
||||||
|
neighbor 10.0.4.2 remote-as internal
|
||||||
|
neighbor 10.0.4.2 timers 3 10
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute connected
|
||||||
|
exit-address-family
|
||||||
|
!
|
12
tests/topotests/bgp_community_change_update/y1/zebra.conf
Normal file
12
tests/topotests/bgp_community_change_update/y1/zebra.conf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
!
|
||||||
|
interface y1-eth0
|
||||||
|
ip address 10.0.2.2/30
|
||||||
|
!
|
||||||
|
interface y1-eth1
|
||||||
|
ip address 10.0.3.1/30
|
||||||
|
!
|
||||||
|
interface y1-eth2
|
||||||
|
ip address 10.0.4.1/30
|
||||||
|
!
|
||||||
|
ip forwarding
|
||||||
|
!
|
18
tests/topotests/bgp_community_change_update/y2/bgpd.conf
Normal file
18
tests/topotests/bgp_community_change_update/y2/bgpd.conf
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
router bgp 65003
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
neighbor 10.0.3.1 remote-as internal
|
||||||
|
neighbor 10.0.3.1 timers 3 10
|
||||||
|
neighbor 10.0.5.2 remote-as internal
|
||||||
|
neighbor 10.0.5.2 timers 3 10
|
||||||
|
neighbor 10.0.6.2 remote-as external
|
||||||
|
neighbor 10.0.6.2 timers 3 10
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute connected
|
||||||
|
neighbor 10.0.3.1 route-reflector-client
|
||||||
|
neighbor 10.0.5.2 route-reflector-client
|
||||||
|
neighbor 10.0.6.2 route-map z1 in
|
||||||
|
exit-address-family
|
||||||
|
!
|
||||||
|
route-map z1 permit 10
|
||||||
|
set community 65004:2
|
||||||
|
!
|
12
tests/topotests/bgp_community_change_update/y2/zebra.conf
Normal file
12
tests/topotests/bgp_community_change_update/y2/zebra.conf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
!
|
||||||
|
interface y2-eth0
|
||||||
|
ip address 10.0.3.2/30
|
||||||
|
!
|
||||||
|
interface y2-eth1
|
||||||
|
ip address 10.0.5.1/30
|
||||||
|
!
|
||||||
|
interface y2-eth2
|
||||||
|
ip address 10.0.6.1/30
|
||||||
|
!
|
||||||
|
ip forwarding
|
||||||
|
!
|
18
tests/topotests/bgp_community_change_update/y3/bgpd.conf
Normal file
18
tests/topotests/bgp_community_change_update/y3/bgpd.conf
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
router bgp 65003
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
neighbor 10.0.4.1 remote-as internal
|
||||||
|
neighbor 10.0.4.1 timers 3 10
|
||||||
|
neighbor 10.0.5.1 remote-as internal
|
||||||
|
neighbor 10.0.5.1 timers 3 10
|
||||||
|
neighbor 10.0.7.2 remote-as external
|
||||||
|
neighbor 10.0.7.2 timers 3 10
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute connected
|
||||||
|
neighbor 10.0.4.1 route-reflector-client
|
||||||
|
neighbor 10.0.5.1 route-reflector-client
|
||||||
|
neighbor 10.0.7.2 route-map z1 in
|
||||||
|
exit-address-family
|
||||||
|
!
|
||||||
|
route-map z1 permit 10
|
||||||
|
set community 65004:3
|
||||||
|
!
|
12
tests/topotests/bgp_community_change_update/y3/zebra.conf
Normal file
12
tests/topotests/bgp_community_change_update/y3/zebra.conf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
!
|
||||||
|
interface y3-eth0
|
||||||
|
ip address 10.0.4.2/30
|
||||||
|
!
|
||||||
|
interface y3-eth1
|
||||||
|
ip address 10.0.5.2/30
|
||||||
|
!
|
||||||
|
interface y3-eth2
|
||||||
|
ip address 10.0.7.1/30
|
||||||
|
!
|
||||||
|
ip forwarding
|
||||||
|
!
|
10
tests/topotests/bgp_community_change_update/z1/bgpd.conf
Normal file
10
tests/topotests/bgp_community_change_update/z1/bgpd.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
router bgp 65004
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
neighbor 10.0.6.1 remote-as external
|
||||||
|
neighbor 10.0.6.1 timers 3 10
|
||||||
|
neighbor 10.0.7.1 remote-as external
|
||||||
|
neighbor 10.0.7.1 timers 3 10
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute connected
|
||||||
|
exit-address-family
|
||||||
|
!
|
12
tests/topotests/bgp_community_change_update/z1/zebra.conf
Normal file
12
tests/topotests/bgp_community_change_update/z1/zebra.conf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
!
|
||||||
|
interface lo
|
||||||
|
ip address 192.168.255.254/32
|
||||||
|
!
|
||||||
|
interface z1-eth0
|
||||||
|
ip address 10.0.6.2/30
|
||||||
|
!
|
||||||
|
interface z1-eth1
|
||||||
|
ip address 10.0.7.2/30
|
||||||
|
!
|
||||||
|
ip forwarding
|
||||||
|
!
|
@ -358,6 +358,13 @@ submodule frr-bgp-common {
|
|||||||
"Apply administrative shutdown to newly configured peers.";
|
"Apply administrative shutdown to newly configured peers.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
leaf suppress-duplicates {
|
||||||
|
type boolean;
|
||||||
|
default "true";
|
||||||
|
description
|
||||||
|
"Suppress duplicate updates if the route actually not changed.";
|
||||||
|
}
|
||||||
|
|
||||||
leaf ebgp-requires-policy {
|
leaf ebgp-requires-policy {
|
||||||
type boolean;
|
type boolean;
|
||||||
default "true";
|
default "true";
|
||||||
|
Loading…
Reference in New Issue
Block a user