summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_mplsvpn.c376
-rw-r--r--bgpd/bgp_mplsvpn.h20
-rw-r--r--bgpd/bgp_packet.c8
-rw-r--r--bgpd/bgp_updgrp.c26
-rw-r--r--bgpd/bgp_updgrp.h7
-rw-r--r--bgpd/bgp_updgrp_adv.c48
-rw-r--r--bgpd/bgp_updgrp_packet.c14
-rw-r--r--bgpd/bgpd.c24
-rw-r--r--configure.ac7
-rwxr-xr-xdebian/rules7
-rw-r--r--doc/developer/packaging-debian.rst4
-rw-r--r--lib/routemap.c12
-rw-r--r--lib/routemap.h4
-rw-r--r--pimd/pim_bsm.c17
-rw-r--r--pimd/pim_cmd.c28
-rw-r--r--pimd/pim_rp.c10
-rw-r--r--pimd/subdir.am10
-rw-r--r--redhat/frr.spec.in18
-rw-r--r--tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py2102
-rwxr-xr-xtools/frrcommon.sh.in4
-rw-r--r--zebra/zebra_evpn_neigh.c5
21 files changed, 2474 insertions, 277 deletions
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index cc4ff57f4e..52180b3e48 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -767,23 +767,74 @@ static void unsetsids(struct bgp_path_info *bpi)
memset(extra->sid, 0, sizeof(extra->sid));
}
+static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn,
+ struct attr *new_attr, afi_t afi,
+ safi_t safi,
+ struct bgp_path_info *source_bpi,
+ struct bgp_path_info *bpi,
+ struct bgp *bgp_orig,
+ const struct prefix *p, int debug)
+{
+ struct bgp_path_info *bpi_ultimate;
+ struct bgp *bgp_nexthop;
+ bool nh_valid;
+
+ bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi);
+
+ if (bpi->extra && bpi->extra->bgp_orig)
+ bgp_nexthop = bpi->extra->bgp_orig;
+ else
+ bgp_nexthop = bgp_orig;
+
+ /*
+ * No nexthop tracking for redistributed routes or for
+ * EVPN-imported routes that get leaked.
+ */
+ if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
+ is_pi_family_evpn(bpi_ultimate))
+ nh_valid = 1;
+ else
+ /*
+ * TBD do we need to do anything about the
+ * 'connected' parameter?
+ */
+ nh_valid = bgp_find_or_add_nexthop(to_bgp, bgp_nexthop, afi,
+ safi, bpi, NULL, 0, p);
+
+ /*
+ * If you are using SRv6 VPN instead of MPLS, it need to check
+ * the SID allocation. If the sid is not allocated, the rib
+ * will be invalid.
+ */
+ if (to_bgp->srv6_enabled &&
+ (!new_attr->srv6_l3vpn && !new_attr->srv6_vpn)) {
+ nh_valid = false;
+ }
+
+ if (debug)
+ zlog_debug("%s: %pFX nexthop is %svalid (in vrf %s)", __func__,
+ p, (nh_valid ? "" : "not "),
+ bgp_nexthop->name_pretty);
+
+ return nh_valid;
+}
+
/*
* returns pointer to new bgp_path_info upon success
*/
static struct bgp_path_info *
-leak_update(struct bgp *bgp, /* destination bgp instance */
- struct bgp_dest *bn, struct attr *new_attr, /* already interned */
+leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
+ struct attr *new_attr, /* already interned */
afi_t afi, safi_t safi, struct bgp_path_info *source_bpi,
- mpls_label_t *label, uint32_t num_labels, void *parent,
- struct bgp *bgp_orig, struct prefix *nexthop_orig,
- int nexthop_self_flag, int debug)
+ mpls_label_t *label, uint32_t num_labels, struct bgp *bgp_orig,
+ struct prefix *nexthop_orig, int nexthop_self_flag, int debug)
{
const struct prefix *p = bgp_dest_get_prefix(bn);
struct bgp_path_info *bpi;
- struct bgp_path_info *bpi_ultimate;
struct bgp_path_info *new;
struct bgp_path_info_extra *extra;
uint32_t num_sids = 0;
+ void *parent = source_bpi;
if (new_attr->srv6_l3vpn || new_attr->srv6_vpn)
num_sids = 1;
@@ -791,7 +842,7 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
if (debug)
zlog_debug(
"%s: entry: leak-to=%s, p=%pBD, type=%d, sub_type=%d",
- __func__, bgp->name_pretty, bn, source_bpi->type,
+ __func__, to_bgp->name_pretty, bn, source_bpi->type,
source_bpi->sub_type);
/*
@@ -809,7 +860,6 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
* schemes that could be implemented in the future.
*
*/
- bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi);
/*
* match parent
@@ -827,7 +877,7 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
if (debug) {
zlog_debug(
"%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, being removed, not leaking",
- __func__, bgp->name_pretty,
+ __func__, to_bgp->name_pretty,
source_bpi->flags, bpi->flags, p);
}
return NULL;
@@ -840,7 +890,7 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
if (debug)
zlog_debug(
"%s: ->%s: %pBD: Found route, no change",
- __func__, bgp->name_pretty, bn);
+ __func__, to_bgp->name_pretty, bn);
return NULL;
}
@@ -858,8 +908,9 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
if (!ecommunity_cmp(
bgp_attr_get_ecommunity(bpi->attr),
bgp_attr_get_ecommunity(new_attr))) {
- vpn_leak_to_vrf_withdraw(bgp, bpi);
- bgp_aggregate_decrement(bgp, p, bpi, afi, safi);
+ vpn_leak_to_vrf_withdraw(to_bgp, bpi);
+ bgp_aggregate_decrement(to_bgp, p, bpi, afi,
+ safi);
bgp_path_info_delete(bn, bpi);
}
}
@@ -871,7 +922,7 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
bgp_path_info_restore(bn, bpi);
else
- bgp_aggregate_decrement(bgp, p, bpi, afi, safi);
+ bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
bgp_attr_unintern(&bpi->attr);
bpi->attr = new_attr;
bpi->uptime = bgp_clock();
@@ -914,54 +965,21 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF);
- struct bgp *bgp_nexthop = bgp;
- int nh_valid;
-
- if (bpi->extra && bpi->extra->bgp_orig)
- bgp_nexthop = bpi->extra->bgp_orig;
-
- /*
- * No nexthop tracking for redistributed routes or for
- * EVPN-imported routes that get leaked.
- */
- if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
- is_pi_family_evpn(bpi_ultimate))
- nh_valid = 1;
+ if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi,
+ source_bpi, bpi, bgp_orig, p,
+ debug))
+ bgp_path_info_set_flag(bn, bpi, BGP_PATH_VALID);
else
- /*
- * TBD do we need to do anything about the
- * 'connected' parameter?
- */
- nh_valid = bgp_find_or_add_nexthop(
- bgp, bgp_nexthop, afi, safi, bpi, NULL, 0, p);
-
- /*
- * If you are using SRv6 VPN instead of MPLS, it need to check
- * the SID allocation. If the sid is not allocated, the rib
- * will be invalid.
- */
- if (bgp->srv6_enabled
- && (!new_attr->srv6_l3vpn && !new_attr->srv6_vpn)) {
bgp_path_info_unset_flag(bn, bpi, BGP_PATH_VALID);
- nh_valid = false;
- }
-
- if (debug)
- zlog_debug("%s: nexthop is %svalid (in vrf %s)",
- __func__, (nh_valid ? "" : "not "),
- bgp_nexthop->name_pretty);
-
- if (nh_valid)
- bgp_path_info_set_flag(bn, bpi, BGP_PATH_VALID);
/* Process change. */
- bgp_aggregate_increment(bgp, p, bpi, afi, safi);
- bgp_process(bgp, bn, afi, safi);
+ bgp_aggregate_increment(to_bgp, p, bpi, afi, safi);
+ bgp_process(to_bgp, bn, afi, safi);
bgp_dest_unlock_node(bn);
if (debug)
zlog_debug("%s: ->%s: %pBD Found route, changed attr",
- __func__, bgp->name_pretty, bn);
+ __func__, to_bgp->name_pretty, bn);
return bpi;
}
@@ -970,14 +988,14 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
if (debug) {
zlog_debug(
"%s: ->%s(s_flags: 0x%x): %pFX: New route, being removed, not leaking",
- __func__, bgp->name_pretty,
+ __func__, to_bgp->name_pretty,
source_bpi->flags, p);
}
return NULL;
}
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0,
- bgp->peer_self, new_attr, bn);
+ to_bgp->peer_self, new_attr, bn);
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF);
@@ -1019,67 +1037,28 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
if (nexthop_orig)
new->extra->nexthop_orig = *nexthop_orig;
- /*
- * nexthop tracking for unicast routes
- */
- struct bgp *bgp_nexthop = bgp;
- int nh_valid;
-
- if (new->extra->bgp_orig)
- bgp_nexthop = new->extra->bgp_orig;
-
- /*
- * No nexthop tracking for redistributed routes because
- * their originating protocols will do the tracking and
- * withdraw those routes if the nexthops become unreachable
- * This also holds good for EVPN-imported routes that get
- * leaked.
- */
- if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
- is_pi_family_evpn(bpi_ultimate))
- nh_valid = 1;
+ if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi,
+ source_bpi, new, bgp_orig, p, debug))
+ bgp_path_info_set_flag(bn, new, BGP_PATH_VALID);
else
- /*
- * TBD do we need to do anything about the
- * 'connected' parameter?
- */
- nh_valid = bgp_find_or_add_nexthop(bgp, bgp_nexthop, afi, safi,
- new, NULL, 0, p);
-
- /*
- * If you are using SRv6 VPN instead of MPLS, it need to check
- * the SID allocation. If the sid is not allocated, the rib
- * will be invalid.
- */
- if (bgp->srv6_enabled
- && (!new->attr->srv6_l3vpn && !new->attr->srv6_vpn)) {
bgp_path_info_unset_flag(bn, new, BGP_PATH_VALID);
- nh_valid = false;
- }
-
- if (debug)
- zlog_debug("%s: nexthop is %svalid (in vrf %s)",
- __func__, (nh_valid ? "" : "not "),
- bgp_nexthop->name_pretty);
- if (nh_valid)
- bgp_path_info_set_flag(bn, new, BGP_PATH_VALID);
- bgp_aggregate_increment(bgp, p, new, afi, safi);
+ bgp_aggregate_increment(to_bgp, p, new, afi, safi);
bgp_path_info_add(bn, new);
bgp_dest_unlock_node(bn);
- bgp_process(bgp, bn, afi, safi);
+ bgp_process(to_bgp, bn, afi, safi);
if (debug)
zlog_debug("%s: ->%s: %pBD: Added new route", __func__,
- bgp->name_pretty, bn);
+ to_bgp->name_pretty, bn);
return new;
}
/* cf vnc_import_bgp_add_route_mode_nvegroup() and add_vnc_route() */
-void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
- struct bgp *bgp_vrf, /* from */
+void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
+ struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vrf) /* route */
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
@@ -1095,7 +1074,7 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
int nexthop_self_flag = 0;
if (debug)
- zlog_debug("%s: from vrf %s", __func__, bgp_vrf->name_pretty);
+ zlog_debug("%s: from vrf %s", __func__, from_bgp->name_pretty);
if (debug && bgp_attr_get_ecommunity(path_vrf->attr)) {
char *s = ecommunity_ecom2str(
@@ -1103,11 +1082,11 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
zlog_debug("%s: %s path_vrf->type=%d, EC{%s}", __func__,
- bgp_vrf->name, path_vrf->type, s);
+ from_bgp->name, path_vrf->type, s);
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
- if (!bgp_vpn)
+ if (!to_bgp)
return;
if (!afi) {
@@ -1120,10 +1099,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
if (!is_route_injectable_into_vpn(path_vrf))
return;
- if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
+ if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: %s skipping: %s", __func__,
- bgp_vrf->name, debugmsg);
+ from_bgp->name, debugmsg);
return;
}
@@ -1133,23 +1112,23 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
/*
* route map handling
*/
- if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) {
+ if (from_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) {
struct bgp_path_info info;
route_map_result_t ret;
memset(&info, 0, sizeof(info));
- info.peer = bgp_vpn->peer_self;
+ info.peer = to_bgp->peer_self;
info.attr = &static_attr;
- ret = route_map_apply(
- bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN],
- p, &info);
+ ret = route_map_apply(from_bgp->vpn_policy[afi]
+ .rmap[BGP_VPN_POLICY_DIR_TOVPN],
+ p, &info);
if (RMAP_DENYMATCH == ret) {
bgp_attr_flush(&static_attr); /* free any added parts */
if (debug)
zlog_debug(
"%s: vrf %s route map \"%s\" says DENY, returning",
- __func__, bgp_vrf->name_pretty,
- bgp_vrf->vpn_policy[afi]
+ __func__, from_bgp->name_pretty,
+ from_bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_TOVPN]
->name);
return;
@@ -1177,17 +1156,17 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
old_ecom = bgp_attr_get_ecommunity(&static_attr);
if (old_ecom) {
new_ecom = ecommunity_dup(old_ecom);
- if (CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
- BGP_CONFIG_VRF_TO_VRF_EXPORT))
+ if (CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST],
+ BGP_CONFIG_VRF_TO_VRF_EXPORT))
ecommunity_strip_rts(new_ecom);
- new_ecom = ecommunity_merge(new_ecom,
- bgp_vrf->vpn_policy[afi]
- .rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
+ new_ecom = ecommunity_merge(
+ new_ecom, from_bgp->vpn_policy[afi]
+ .rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
if (!old_ecom->refcnt)
ecommunity_free(&old_ecom);
} else {
new_ecom = ecommunity_dup(
- bgp_vrf->vpn_policy[afi]
+ from_bgp->vpn_policy[afi]
.rtlist[BGP_VPN_POLICY_DIR_TOVPN]);
}
bgp_attr_set_ecommunity(&static_attr, new_ecom);
@@ -1204,10 +1183,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
/* Nexthop */
/* if policy nexthop not set, use 0 */
- if (CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
+ if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {
struct prefix *nexthop =
- &bgp_vrf->vpn_policy[afi].tovpn_nexthop;
+ &from_bgp->vpn_policy[afi].tovpn_nexthop;
switch (nexthop->family) {
case AF_INET:
@@ -1228,7 +1207,7 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
assert(0);
}
} else {
- if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST],
+ if (!CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST],
BGP_CONFIG_VRF_TO_VRF_EXPORT)) {
if (afi == AFI_IP) {
/*
@@ -1266,7 +1245,7 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
nexthop_self_flag = 1;
}
- label_val = bgp_vrf->vpn_policy[afi].tovpn_label;
+ label_val = from_bgp->vpn_policy[afi].tovpn_label;
if (label_val == MPLS_LABEL_NONE) {
encode_label(MPLS_LABEL_IMPLICIT_NULL, &label);
} else {
@@ -1275,12 +1254,13 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
/* Set originator ID to "me" */
SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID));
- static_attr.originator_id = bgp_vpn->router_id;
+ static_attr.originator_id = to_bgp->router_id;
/* Set SID for SRv6 VPN */
- if (bgp_vrf->vpn_policy[afi].tovpn_sid_locator) {
- encode_label(bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label,
- &label);
+ if (from_bgp->vpn_policy[afi].tovpn_sid_locator) {
+ encode_label(
+ from_bgp->vpn_policy[afi].tovpn_sid_transpose_label,
+ &label);
static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
sizeof(struct bgp_attr_srv6_l3vpn));
static_attr.srv6_l3vpn->sid_flags = 0x00;
@@ -1298,7 +1278,7 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
static_attr.srv6_l3vpn->transposition_offset =
BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET;
memcpy(&static_attr.srv6_l3vpn->sid,
- bgp_vrf->vpn_policy[afi].tovpn_sid_locator,
+ from_bgp->vpn_policy[afi].tovpn_sid_locator,
sizeof(struct in6_addr));
}
@@ -1317,14 +1297,14 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
/* Now new_attr is an allocated interned attr */
- bn = bgp_afi_node_get(bgp_vpn->rib[afi][safi], afi, safi, p,
- &(bgp_vrf->vpn_policy[afi].tovpn_rd));
+ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p,
+ &(from_bgp->vpn_policy[afi].tovpn_rd));
struct bgp_path_info *new_info;
- new_info = leak_update(bgp_vpn, bn, new_attr, afi, safi, path_vrf,
- &label, 1, path_vrf, bgp_vrf, NULL,
- nexthop_self_flag, debug);
+ new_info =
+ leak_update(to_bgp, bn, new_attr, afi, safi, path_vrf, &label,
+ 1, from_bgp, NULL, nexthop_self_flag, debug);
/*
* Routes actually installed in the vpn RIB must also be
@@ -1336,11 +1316,11 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
* because of loop checking.
*/
if (new_info)
- vpn_leak_to_vrf_update(bgp_vrf, new_info);
+ vpn_leak_to_vrf_update(from_bgp, new_info);
}
-void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
- struct bgp *bgp_vrf, /* from */
+void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */
+ struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vrf) /* route */
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
@@ -1354,11 +1334,11 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
if (debug) {
zlog_debug(
"%s: entry: leak-from=%s, p=%pBD, type=%d, sub_type=%d",
- __func__, bgp_vrf->name_pretty, path_vrf->net,
+ __func__, from_bgp->name_pretty, path_vrf->net,
path_vrf->type, path_vrf->sub_type);
}
- if (!bgp_vpn)
+ if (!to_bgp)
return;
if (!afi) {
@@ -1371,7 +1351,7 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
if (!is_route_injectable_into_vpn(path_vrf))
return;
- if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
+ if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
return;
@@ -1380,8 +1360,8 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
if (debug)
zlog_debug("%s: withdrawing (path_vrf=%p)", __func__, path_vrf);
- bn = bgp_afi_node_get(bgp_vpn->rib[afi][safi], afi, safi, p,
- &(bgp_vrf->vpn_policy[afi].tovpn_rd));
+ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p,
+ &(from_bgp->vpn_policy[afi].tovpn_rd));
if (!bn)
return;
@@ -1397,17 +1377,16 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */
if (bpi) {
/* withdraw from looped vrfs as well */
- vpn_leak_to_vrf_withdraw(bgp_vpn, bpi);
+ vpn_leak_to_vrf_withdraw(to_bgp, bpi);
- bgp_aggregate_decrement(bgp_vpn, p, bpi, afi, safi);
+ bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
- bgp_process(bgp_vpn, bn, afi, safi);
+ bgp_process(to_bgp, bn, afi, safi);
}
bgp_dest_unlock_node(bn);
}
-void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
- struct bgp *bgp_vrf, /* from */
+void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
@@ -1415,9 +1394,9 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
safi_t safi = SAFI_MPLS_VPN;
/*
- * Walk vpn table, delete bpi with bgp_orig == bgp_vrf
+ * Walk vpn table, delete bpi with bgp_orig == from_bgp
*/
- for (pdest = bgp_table_top(bgp_vpn->rib[afi][safi]); pdest;
+ for (pdest = bgp_table_top(to_bgp->rib[afi][safi]); pdest;
pdest = bgp_route_next(pdest)) {
struct bgp_table *table;
@@ -1446,28 +1425,26 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
continue;
if (!bpi->extra)
continue;
- if ((struct bgp *)bpi->extra->bgp_orig
- == bgp_vrf) {
+ if ((struct bgp *)bpi->extra->bgp_orig ==
+ from_bgp) {
/* delete route */
if (debug)
zlog_debug("%s: deleting it",
__func__);
/* withdraw from leak-to vrfs as well */
- vpn_leak_to_vrf_withdraw(bgp_vpn, bpi);
+ vpn_leak_to_vrf_withdraw(to_bgp, bpi);
bgp_aggregate_decrement(
- bgp_vpn,
- bgp_dest_get_prefix(bn), bpi,
- afi, safi);
+ to_bgp, bgp_dest_get_prefix(bn),
+ bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
- bgp_process(bgp_vpn, bn, afi, safi);
+ bgp_process(to_bgp, bn, afi, safi);
}
}
}
}
}
-void vpn_leak_from_vrf_update_all(struct bgp *bgp_vpn, /* to */
- struct bgp *bgp_vrf, /* from */
+void vpn_leak_from_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi)
{
struct bgp_dest *bn;
@@ -1476,9 +1453,9 @@ void vpn_leak_from_vrf_update_all(struct bgp *bgp_vpn, /* to */
if (debug)
zlog_debug("%s: entry, afi=%d, vrf=%s", __func__, afi,
- bgp_vrf->name_pretty);
+ from_bgp->name_pretty);
- for (bn = bgp_table_top(bgp_vrf->rib[afi][SAFI_UNICAST]); bn;
+ for (bn = bgp_table_top(from_bgp->rib[afi][SAFI_UNICAST]); bn;
bn = bgp_route_next(bn)) {
if (debug)
@@ -1490,14 +1467,14 @@ void vpn_leak_from_vrf_update_all(struct bgp *bgp_vpn, /* to */
zlog_debug(
"%s: calling vpn_leak_from_vrf_update",
__func__);
- vpn_leak_from_vrf_update(bgp_vpn, bgp_vrf, bpi);
+ vpn_leak_from_vrf_update(to_bgp, from_bgp, bpi);
}
}
}
static void
-vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
- struct bgp *bgp_vpn, /* from */
+vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
+ struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vpn) /* route */
{
const struct prefix *p = bgp_dest_get_prefix(path_vpn->net);
@@ -1518,7 +1495,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
- if (!vpn_leak_from_vpn_active(bgp_vrf, afi, &debugmsg)) {
+ if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) {
if (debug)
zlog_debug("%s: skipping: %s", __func__, debugmsg);
return;
@@ -1526,18 +1503,18 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
/* Check for intersection of route targets */
if (!ecom_intersect(
- bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
+ to_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
bgp_attr_get_ecommunity(path_vpn->attr))) {
if (debug)
zlog_debug(
"from vpn (%s) to vrf (%s), skipping after no intersection of route targets",
- bgp_vpn->name_pretty, bgp_vrf->name_pretty);
+ from_bgp->name_pretty, to_bgp->name_pretty);
return;
}
if (debug)
zlog_debug("%s: updating %pFX to vrf %s", __func__, p,
- bgp_vrf->name_pretty);
+ to_bgp->name_pretty);
/* shallow copy */
static_attr = *path_vpn->attr;
@@ -1547,8 +1524,8 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
/* If doing VRF-to-VRF leaking, strip RTs. */
old_ecom = bgp_attr_get_ecommunity(&static_attr);
- if (old_ecom && CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
- BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
+ if (old_ecom && CHECK_FLAG(to_bgp->af_flags[afi][safi],
+ BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
new_ecom = ecommunity_dup(old_ecom);
ecommunity_strip_rts(new_ecom);
bgp_attr_set_ecommunity(&static_attr, new_ecom);
@@ -1580,7 +1557,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
nexthop_orig.u.prefix4 = path_vpn->attr->mp_nexthop_global_in;
nexthop_orig.prefixlen = IPV4_MAX_BITLEN;
- if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
+ if (CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
static_attr.nexthop.s_addr =
nexthop_orig.u.prefix4.s_addr;
@@ -1597,7 +1574,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
nexthop_orig.u.prefix6 = path_vpn->attr->mp_nexthop_global;
nexthop_orig.prefixlen = IPV6_MAX_BITLEN;
- if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
+ if (CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
static_attr.mp_nexthop_global = nexthop_orig.u.prefix6;
}
@@ -1607,15 +1584,15 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
/*
* route map handling
*/
- if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) {
+ if (to_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) {
struct bgp_path_info info;
route_map_result_t ret;
memset(&info, 0, sizeof(info));
- info.peer = bgp_vrf->peer_self;
+ info.peer = to_bgp->peer_self;
info.attr = &static_attr;
info.extra = path_vpn->extra; /* Used for source-vrf filter */
- ret = route_map_apply(bgp_vrf->vpn_policy[afi]
+ ret = route_map_apply(to_bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_FROMVPN],
p, &info);
if (RMAP_DENYMATCH == ret) {
@@ -1623,8 +1600,8 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
if (debug)
zlog_debug(
"%s: vrf %s vpn-policy route map \"%s\" says DENY, returning",
- __func__, bgp_vrf->name_pretty,
- bgp_vrf->vpn_policy[afi]
+ __func__, to_bgp->name_pretty,
+ to_bgp->vpn_policy[afi]
.rmap[BGP_VPN_POLICY_DIR_FROMVPN]
->name);
return;
@@ -1640,7 +1617,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
new_attr = bgp_attr_intern(&static_attr);
bgp_attr_flush(&static_attr);
- bn = bgp_afi_node_get(bgp_vrf->rib[afi][safi], afi, safi, p, NULL);
+ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL);
/*
* ensure labels are copied
@@ -1654,7 +1631,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
* labels for these routes enables the non-labeled nexthops
* from the originating VRF to be considered valid for this route.
*/
- if (!CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
+ if (!CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
/* work back to original route */
bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn);
@@ -1692,14 +1669,14 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
if (path_vpn->extra && path_vpn->extra->bgp_orig)
src_vrf = path_vpn->extra->bgp_orig;
else
- src_vrf = bgp_vpn;
+ src_vrf = from_bgp;
- leak_update(bgp_vrf, bn, new_attr, afi, safi, path_vpn, pLabels,
- num_labels, path_vpn, /* parent */
- src_vrf, &nexthop_orig, nexthop_self_flag, debug);
+ leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, pLabels,
+ num_labels, src_vrf, &nexthop_orig, nexthop_self_flag,
+ debug);
}
-void vpn_leak_to_vrf_update(struct bgp *bgp_vpn, /* from */
+void vpn_leak_to_vrf_update(struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vpn) /* route */
{
struct listnode *mnode, *mnnode;
@@ -1715,12 +1692,12 @@ void vpn_leak_to_vrf_update(struct bgp *bgp_vpn, /* from */
if (!path_vpn->extra
|| path_vpn->extra->bgp_orig != bgp) { /* no loop */
- vpn_leak_to_vrf_update_onevrf(bgp, bgp_vpn, path_vpn);
+ vpn_leak_to_vrf_update_onevrf(bgp, from_bgp, path_vpn);
}
}
}
-void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */
+void vpn_leak_to_vrf_withdraw(struct bgp *from_bgp, /* from */
struct bgp_path_info *path_vpn) /* route */
{
const struct prefix *p;
@@ -1804,8 +1781,7 @@ void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */
}
}
-void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */
- afi_t afi)
+void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi)
{
struct bgp_dest *bn;
struct bgp_path_info *bpi;
@@ -1817,40 +1793,38 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */
/*
* Walk vrf table, delete bpi with bgp_orig in a different vrf
*/
- for (bn = bgp_table_top(bgp_vrf->rib[afi][safi]); bn;
+ for (bn = bgp_table_top(to_bgp->rib[afi][safi]); bn;
bn = bgp_route_next(bn)) {
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
- if (bpi->extra
- && bpi->extra->bgp_orig != bgp_vrf
- && bpi->extra->parent
- && is_pi_family_vpn(bpi->extra->parent)) {
+ if (bpi->extra && bpi->extra->bgp_orig != to_bgp &&
+ bpi->extra->parent &&
+ is_pi_family_vpn(bpi->extra->parent)) {
/* delete route */
- bgp_aggregate_decrement(bgp_vrf,
+ bgp_aggregate_decrement(to_bgp,
bgp_dest_get_prefix(bn),
bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
- bgp_process(bgp_vrf, bn, afi, safi);
+ bgp_process(to_bgp, bn, afi, safi);
}
}
}
}
-void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */
- struct bgp *bgp_vpn, /* from */
+void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *vpn_from,
afi_t afi)
{
struct bgp_dest *pdest;
safi_t safi = SAFI_MPLS_VPN;
- assert(bgp_vpn);
+ assert(vpn_from);
/*
* Walk vpn table
*/
- for (pdest = bgp_table_top(bgp_vpn->rib[afi][safi]); pdest;
+ for (pdest = bgp_table_top(vpn_from->rib[afi][safi]); pdest;
pdest = bgp_route_next(pdest)) {
struct bgp_table *table;
struct bgp_dest *bn;
@@ -1867,11 +1841,11 @@ void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
- if (bpi->extra
- && bpi->extra->bgp_orig == bgp_vrf)
+ if (bpi->extra &&
+ bpi->extra->bgp_orig == to_bgp)
continue;
- vpn_leak_to_vrf_update_onevrf(bgp_vrf, bgp_vpn,
+ vpn_leak_to_vrf_update_onevrf(to_bgp, vpn_from,
bpi);
}
}
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index 8c2eae279c..fcabb16435 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -53,27 +53,27 @@ extern int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd,
enum bgp_show_type type, void *output_arg,
int tags, bool use_json);
-extern void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
+extern void vpn_leak_from_vrf_update(struct bgp *to_bgp, struct bgp *from_bgp,
struct bgp_path_info *path_vrf);
-extern void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
+extern void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, struct bgp *from_bgp,
struct bgp_path_info *path_vrf);
-extern void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn,
- struct bgp *bgp_vrf, afi_t afi);
+extern void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp,
+ struct bgp *from_bgp, afi_t afi);
-extern void vpn_leak_from_vrf_update_all(struct bgp *bgp_vpn,
- struct bgp *bgp_vrf, afi_t afi);
+extern void vpn_leak_from_vrf_update_all(struct bgp *to_bgp,
+ struct bgp *from_bgp, afi_t afi);
-extern void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, afi_t afi);
+extern void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi);
-extern void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, struct bgp *bgp_vpn,
+extern void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi);
-extern void vpn_leak_to_vrf_update(struct bgp *bgp_vpn,
+extern void vpn_leak_to_vrf_update(struct bgp *from_bgp,
struct bgp_path_info *path_vpn);
-extern void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn,
+extern void vpn_leak_to_vrf_withdraw(struct bgp *from_bgp,
struct bgp_path_info *path_vpn);
extern void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 9def9622d9..7613ccc7df 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -780,7 +780,7 @@ struct bgp_notify bgp_notify_decapsulate_hard_reset(struct bgp_notify *notify)
bn.subcode = notify->raw_data[1];
bn.length = notify->length - 2;
- bn.raw_data = XCALLOC(MTYPE_BGP_NOTIFICATION, bn.length);
+ bn.raw_data = XMALLOC(MTYPE_BGP_NOTIFICATION, bn.length);
memcpy(bn.raw_data, notify->raw_data + 2, bn.length);
return bn;
@@ -2121,6 +2121,12 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
if (outer.length) {
XFREE(MTYPE_BGP_NOTIFICATION, outer.data);
XFREE(MTYPE_BGP_NOTIFICATION, outer.raw_data);
+
+ /* If this is a Hard Reset notification, we MUST free
+ * the inner (encapsulated) notification too.
+ */
+ if (hard_reset)
+ XFREE(MTYPE_BGP_NOTIFICATION, inner.raw_data);
outer.length = 0;
}
}
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index adde379fb0..ea8d2330c5 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -1479,7 +1479,24 @@ static int updgrp_policy_update_walkcb(struct update_group *updgrp, void *arg)
"u%" PRIu64 ":s%" PRIu64" announcing default upon default routemap %s change",
updgrp->id, subgrp->id,
ctx->policy_name);
- subgroup_default_originate(subgrp, 0);
+ if (route_map_lookup_by_name(ctx->policy_name)) {
+ /*
+ * When there is change in routemap, this flow
+ * is triggered. the routemap is still present
+ * in lib, hence its a update flow. The flag
+ * needs to be unset.
+ */
+ UNSET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE);
+ subgroup_default_originate(subgrp, 0);
+ } else {
+ /*
+ * This is a explicit withdraw, since the
+ * routemap is not present in routemap lib. need
+ * to pass 1 for withdraw arg.
+ */
+ subgroup_default_originate(subgrp, 1);
+ }
}
update_subgroup_set_needs_refresh(subgrp, 0);
}
@@ -1857,6 +1874,13 @@ update_group_default_originate_route_map_walkcb(struct update_group *updgrp,
safi = SUBGRP_SAFI(subgrp);
if (peer->default_rmap[afi][safi].name) {
+ /*
+ * When there is change in routemap this flow will
+ * be triggered. We need to unset the Flag to ensure
+ * the update flow gets triggered.
+ */
+ UNSET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE);
subgroup_default_originate(subgrp, 0);
}
}
diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h
index e3309ab7c5..473017c809 100644
--- a/bgpd/bgp_updgrp.h
+++ b/bgpd/bgp_updgrp.h
@@ -252,6 +252,13 @@ struct update_subgroup {
#define SUBGRP_STATUS_DEFAULT_ORIGINATE (1 << 0)
#define SUBGRP_STATUS_FORCE_UPDATES (1 << 1)
#define SUBGRP_STATUS_TABLE_REPARSING (1 << 2)
+/*
+ * This flag has been added to ensure that the SNT counters
+ * gets incremented and decremented only during the creation
+ * and deletion workflows of default originate,
+ * not during the update workflow.
+ */
+#define SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED (1 << 3)
uint16_t flags;
#define SUBGRP_FLAG_NEEDS_REFRESH (1 << 0)
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 518ce485af..0f7f2f4c02 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -796,8 +796,11 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
struct peer *peer;
struct bgp_adj_out *adj;
route_map_result_t ret = RMAP_DENYMATCH;
+ route_map_result_t new_ret = RMAP_DENYMATCH;
afi_t afi;
safi_t safi;
+ int pref = 65536;
+ int new_pref = 0;
if (!subgrp)
return;
@@ -853,34 +856,45 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
tmp_pi.attr = &tmp_attr;
- ret = route_map_apply_ext(
+ new_ret = route_map_apply_ext(
peer->default_rmap[afi][safi].map,
- bgp_dest_get_prefix(dest), pi, &tmp_pi);
-
- if (ret == RMAP_DENYMATCH) {
- bgp_attr_flush(&tmp_attr);
- continue;
- } else {
- new_attr = bgp_attr_intern(&tmp_attr);
-
+ bgp_dest_get_prefix(dest), pi, &tmp_pi,
+ &new_pref);
+
+ if (new_ret == RMAP_PERMITMATCH) {
+ if (new_pref < pref) {
+ pref = new_pref;
+ bgp_attr_flush(new_attr);
+ new_attr = bgp_attr_intern(
+ tmp_pi.attr);
+ bgp_attr_flush(tmp_pi.attr);
+ }
subgroup_announce_reset_nhop(
(peer_cap_enhe(peer, afi, safi)
? AF_INET6
: AF_INET),
new_attr);
-
- break;
- }
- }
- if (ret == RMAP_PERMITMATCH) {
- bgp_dest_unlock_node(dest);
- break;
+ ret = new_ret;
+ } else
+ bgp_attr_flush(&tmp_attr);
}
}
bgp->peer_self->rmap_type = 0;
- if (ret == RMAP_DENYMATCH)
+ if (ret == RMAP_DENYMATCH) {
+ /*
+ * If its a implicit withdraw due to routemap
+ * deny operation need to set the flag back.
+ * This is a convertion of update flow to
+ * withdraw flow.
+ */
+ if (!withdraw &&
+ (!CHECK_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE)))
+ SET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE);
withdraw = 1;
+ }
}
/* Check if the default route is in local BGP RIB which is
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index c4a3ca7500..88a81f255d 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -1142,7 +1142,12 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp,
(void)bpacket_queue_add(SUBGRP_PKTQ(subgrp), s, &vecarr);
subgroup_trigger_write(subgrp);
- subgrp->scount++;
+
+ if (!CHECK_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED)) {
+ subgrp->scount++;
+ SET_FLAG(subgrp->sflags, SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED);
+ }
}
void subgroup_default_withdraw_packet(struct update_subgroup *subgrp)
@@ -1235,7 +1240,12 @@ void subgroup_default_withdraw_packet(struct update_subgroup *subgrp)
(void)bpacket_queue_add(SUBGRP_PKTQ(subgrp), s, NULL);
subgroup_trigger_write(subgrp);
- subgrp->scount--;
+
+ if (CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED)) {
+ subgrp->scount--;
+ UNSET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED);
+ }
}
static void
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 0bfcf5163f..122830343c 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -5275,9 +5275,13 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
{
struct peer *member;
struct listnode *node, *nnode;
+ struct update_subgroup *subgrp;
/* Set flag and configuration on peer. */
peer_af_flag_set(peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE);
+
+ subgrp = peer_subgroup(peer, afi, safi);
+
if (rmap) {
if (!peer->default_rmap[afi][safi].name
|| strcmp(rmap, peer->default_rmap[afi][safi].name) != 0) {
@@ -5285,6 +5289,17 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
+ /*
+ * When there is a change in route-map policy,
+ * this flow gets triggered. Since, the default
+ * route is already originated, the flag is set.
+ * The flag should be unset here,
+ * to trigger the flow of sending update message.
+ */
+ if (subgrp)
+ UNSET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE);
+
route_map_counter_decrement(peer->default_rmap[afi][safi].map);
peer->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
@@ -5296,6 +5311,15 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
+ /*
+ * This is triggered in case of route-map deletion.
+ * The flag needs to be unset, to trigger the flow
+ * of sending an update message.
+ */
+ if (subgrp)
+ UNSET_FLAG(subgrp->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE);
+
route_map_counter_decrement(peer->default_rmap[afi][safi].map);
peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL;
diff --git a/configure.ac b/configure.ac
index 330752a79f..b7e17d3565 100644
--- a/configure.ac
+++ b/configure.ac
@@ -635,6 +635,8 @@ AC_ARG_ENABLE([isisd],
AS_HELP_STRING([--disable-isisd], [do not build isisd]))
AC_ARG_ENABLE([pimd],
AS_HELP_STRING([--disable-pimd], [do not build pimd]))
+AC_ARG_ENABLE([pim6d],
+ AS_HELP_STRING([--enable-pim6d], [build pim6d]))
AC_ARG_ENABLE([pbrd],
AS_HELP_STRING([--disable-pbrd], [do not build pbrd]))
AC_ARG_ENABLE([sharpd],
@@ -1751,6 +1753,10 @@ AS_IF([test "$enable_pimd" != "no"], [
AC_DEFINE([HAVE_PIMD], [1], [pimd])
])
+AS_IF([test "$enable_pim6d" = "yes"], [
+ AC_DEFINE([HAVE_PIM6D], [1], [pim6d])
+])
+
AS_IF([test "$enable_pbrd" != "no"], [
AC_DEFINE([HAVE_PBRD], [1], [pbrd])
])
@@ -2711,6 +2717,7 @@ AM_CONDITIONAL([BABELD], [test "$enable_babeld" != "no"])
AM_CONDITIONAL([OSPF6D], [test "$enable_ospf6d" != "no"])
AM_CONDITIONAL([ISISD], [test "$enable_isisd" != "no"])
AM_CONDITIONAL([PIMD], [test "$enable_pimd" != "no"])
+AM_CONDITIONAL([PIM6D], [test "$enable_pim6d" = "yes"])
AM_CONDITIONAL([PBRD], [test "$enable_pbrd" != "no"])
AM_CONDITIONAL([SHARPD], [test "$enable_sharpd" = "yes"])
AM_CONDITIONAL([STATICD], [test "$enable_staticd" != "no"])
diff --git a/debian/rules b/debian/rules
index 7a719b7c60..fdb458e6a8 100755
--- a/debian/rules
+++ b/debian/rules
@@ -27,6 +27,12 @@ else
CONF_LUA=--enable-scripting
endif
+ifeq ($(filter pkg.frr.pim6d,$(DEB_BUILD_PROFILES)),)
+ CONF_PIM6=--disable-pim6d
+else
+ CONF_PIM6=--enable-pim6d
+endif
+
export PYTHON=python3
%:
@@ -46,6 +52,7 @@ override_dh_auto_configure:
\
$(CONF_RPKI) \
$(CONF_LUA) \
+ $(CONF_PIM6) \
--with-libpam \
--enable-doc \
--enable-doc-html \
diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst
index a81e052490..9aeb78c4fd 100644
--- a/doc/developer/packaging-debian.rst
+++ b/doc/developer/packaging-debian.rst
@@ -64,6 +64,10 @@ buster.)
+================+===================+=========================================+
| pkg.frr.rtrlib | pkg.frr.nortrlib | builds frr-rpki-rtrlib package (or not) |
+----------------+-------------------+-----------------------------------------+
+ | pkg.frr.lua | pkg.frr.nolua | builds lua scripting extension |
+ +----------------+-------------------+-----------------------------------------+
+ | pkg.frr.pim6d | pkg.frr.nopim6d | builds pim6d (work in progress) |
+ +----------------+-------------------+-----------------------------------------+
* the ``-uc -us`` options to disable signing the packages with your GPG key
diff --git a/lib/routemap.c b/lib/routemap.c
index 7fd5a96e5b..9529b79419 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -2540,7 +2540,8 @@ void route_map_notify_pentry_dependencies(const char *affected_name,
*/
route_map_result_t route_map_apply_ext(struct route_map *map,
const struct prefix *prefix,
- void *match_object, void *set_object)
+ void *match_object, void *set_object,
+ int *pref)
{
static int recursion = 0;
enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
@@ -2676,7 +2677,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map,
ret = route_map_apply_ext(
nextrm, prefix,
match_object,
- set_object);
+ set_object, NULL);
recursion--;
}
@@ -2721,6 +2722,13 @@ route_map_apply_end:
(map ? map->name : "null"), prefix,
route_map_result_str(ret));
+ if (pref) {
+ if (index != NULL && ret == RMAP_PERMITMATCH)
+ *pref = index->pref;
+ else
+ *pref = 65536;
+ }
+
return (ret);
}
diff --git a/lib/routemap.h b/lib/routemap.h
index 13dafe6849..ad391981e0 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -482,9 +482,9 @@ struct route_map *route_map_lookup_warn_noexist(struct vty *vty, const char *nam
extern route_map_result_t route_map_apply_ext(struct route_map *map,
const struct prefix *prefix,
void *match_object,
- void *set_object);
+ void *set_object, int *pref);
#define route_map_apply(map, prefix, object) \
- route_map_apply_ext(map, prefix, object, object)
+ route_map_apply_ext(map, prefix, object, object, NULL)
extern void route_map_add_hook(void (*func)(const char *));
extern void route_map_delete_hook(void (*func)(const char *));
diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c
index 1a13f79e71..1f7dd2f3f9 100644
--- a/pimd/pim_bsm.c
+++ b/pimd/pim_bsm.c
@@ -1280,6 +1280,7 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
struct bsm_frag *bsfrag;
struct pim_instance *pim;
uint16_t frag_tag;
+ pim_addr bsr_addr;
bool empty_bsm = false;
/* BSM Packet acceptance validation */
@@ -1330,6 +1331,8 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
}
pim->global_scope.hashMasklen = bshdr->hm_len;
frag_tag = ntohs(bshdr->frag_tag);
+ /* NB: bshdr->bsr_addr.addr is packed/unaligned => memcpy */
+ memcpy(&bsr_addr, &bshdr->bsr_addr.addr, sizeof(bsr_addr));
/* Identify empty BSM */
if ((buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN) < PIM_BSM_GRP_LEN)
@@ -1351,7 +1354,7 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
}
/* Drop if bsr is not preferred bsr */
- if (!is_preferred_bsr(pim, bshdr->bsr_addr.addr, bshdr->bsr_prio)) {
+ if (!is_preferred_bsr(pim, bsr_addr, bshdr->bsr_prio)) {
if (PIM_DEBUG_BSM)
zlog_debug("%s : Received a non-preferred BSM",
__func__);
@@ -1368,8 +1371,7 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
if (PIM_DEBUG_BSM)
zlog_debug(
"%s : nofwd_bsm received on %pPAs when accpt_nofwd_bsm false",
- __func__,
- (pim_addr *)&bshdr->bsr_addr.addr);
+ __func__, &bsr_addr);
pim->bsm_dropped++;
pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
return -1;
@@ -1381,13 +1383,12 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
* match RPF towards the BSR's IP address, or they have
* no-forward set
*/
- if (!no_fwd && !pim_nht_bsr_rpf_check(pim, bshdr->bsr_addr.addr,
- ifp, sg->src)) {
+ if (!no_fwd &&
+ !pim_nht_bsr_rpf_check(pim, bsr_addr, ifp, sg->src)) {
if (PIM_DEBUG_BSM)
zlog_debug(
"BSM check: RPF to BSR %pPAs is not %pPA%%%s",
- (pim_addr *)&bshdr->bsr_addr.addr,
- &sg->src, ifp->name);
+ &bsr_addr, &sg->src, ifp->name);
pim->bsm_dropped++;
return -1;
}
@@ -1446,7 +1447,7 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
}
/* update the scope information from bsm */
- pim_bsm_update(pim, bshdr->bsr_addr.addr, bshdr->bsr_prio);
+ pim_bsm_update(pim, bsr_addr, bshdr->bsr_prio);
if (!no_fwd) {
pim_bsm_fwd_whole_sz(pim_ifp->pim, buf, buf_size, sz);
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 813ef4ca37..843b24efde 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -864,6 +864,7 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
struct bsmmsg_rpinfo *bsm_rpinfo;
struct prefix grp;
struct bsm_hdr *hdr;
+ pim_addr bsr_addr;
uint32_t offset = 0;
uint8_t *buf;
uint32_t len = 0;
@@ -877,15 +878,16 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
len -= PIM_MSG_HEADER_LEN;
hdr = (struct bsm_hdr *)buf;
+ /* NB: bshdr->bsr_addr.addr is packed/unaligned => memcpy */
+ memcpy(&bsr_addr, &hdr->bsr_addr.addr, sizeof(bsr_addr));
/* BSM starts with bsr header */
buf += sizeof(struct bsm_hdr);
len -= sizeof(struct bsm_hdr);
if (uj) {
- json_object_string_addf(
- json, "BSR address", "%pPA",
- (pim_addr *)&hdr->bsr_addr.addr);
+ json_object_string_addf(json, "BSR address", "%pPA",
+ &bsr_addr);
json_object_int_add(json, "BSR priority",
hdr->bsr_prio);
json_object_int_add(json, "Hashmask Length",
@@ -897,9 +899,9 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
vty_out(vty, "------------------\n");
vty_out(vty, "%-15s %-15s %-15s %-15s\n", "BSR-Address",
"BSR-Priority", "Hashmask-len", "Fragment-Tag");
- vty_out(vty, "%-15pPA %-15d %-15d %-15d\n",
- (pim_addr *)&hdr->bsr_addr.addr, hdr->bsr_prio,
- hdr->hm_len, ntohs(hdr->frag_tag));
+ vty_out(vty, "%-15pPA %-15d %-15d %-15d\n", &bsr_addr,
+ hdr->bsr_prio, hdr->hm_len,
+ ntohs(hdr->frag_tag));
}
vty_out(vty, "\n");
@@ -957,7 +959,12 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
"RpAddress HoldTime Priority\n");
while (frag_rp_cnt--) {
+ pim_addr rp_addr;
+
bsm_rpinfo = (struct bsmmsg_rpinfo *)buf;
+ /* unaligned, again */
+ memcpy(&rp_addr, &bsm_rpinfo->rpaddr,
+ sizeof(rp_addr));
buf += sizeof(struct bsmmsg_rpinfo);
offset += sizeof(struct bsmmsg_rpinfo);
@@ -966,8 +973,7 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
json_row = json_object_new_object();
json_object_string_addf(
json_row, "Rp Address", "%pPA",
- (pim_addr *)&bsm_rpinfo->rpaddr
- .addr);
+ &rp_addr);
json_object_int_add(
json_row, "Rp HoldTime",
ntohs(bsm_rpinfo->rp_holdtime));
@@ -976,12 +982,10 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
bsm_rpinfo->rp_pri);
json_object_object_addf(
json_group, json_row, "%pPA",
- (pim_addr *)&bsm_rpinfo->rpaddr
- .addr);
+ &rp_addr);
} else {
vty_out(vty, "%-15pPA %-12d %d\n",
- (pim_addr *)&bsm_rpinfo->rpaddr
- .addr,
+ &rp_addr,
ntohs(bsm_rpinfo->rp_holdtime),
bsm_rpinfo->rp_pri);
}
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index aa31a67036..783c9b97e7 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -339,9 +339,7 @@ static int pim_rp_check_interface_addrs(struct rp_info *rp_info,
{
struct listnode *node;
struct pim_secondary_addr *sec_addr;
- struct prefix rpf_addr;
-
- pim_addr_to_prefix(&rpf_addr, rp_info->rp.rpf_addr);
+ pim_addr sec_paddr;
if (!pim_addr_cmp(pim_ifp->primary_address, rp_info->rp.rpf_addr))
return 1;
@@ -351,9 +349,11 @@ static int pim_rp_check_interface_addrs(struct rp_info *rp_info,
}
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
- if (prefix_same(&sec_addr->addr, &rpf_addr)) {
+ sec_paddr = pim_addr_from_prefix(&sec_addr->addr);
+ /* If an RP-address is self, It should be enough to say
+ * I am RP the prefix-length should not matter here */
+ if (!pim_addr_cmp(sec_paddr, rp_info->rp.rpf_addr))
return 1;
- }
}
return 0;
diff --git a/pimd/subdir.am b/pimd/subdir.am
index 9546a7776e..aa06b86479 100644
--- a/pimd/subdir.am
+++ b/pimd/subdir.am
@@ -170,17 +170,11 @@ clippy_scan += \
pimd_pimd_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4
pimd_pimd_LDADD = lib/libfrr.la $(LIBCAP)
-if PIMD
-if DEV_BUILD
-#
-# pim6d is only enabled for --enable-dev-build, and NOT installed currently
-# (change noinst_ to sbin_ below to install it.)
-#
-noinst_PROGRAMS += pimd/pim6d
+if PIM6D
+sbin_PROGRAMS += pimd/pim6d
pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6
pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP)
endif
-endif
pimd_test_igmpv3_join_LDADD = lib/libfrr.la
pimd_test_igmpv3_join_SOURCES = pimd/test_igmpv3_join.c
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 9d3d2b0643..135c065b15 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -24,6 +24,7 @@
%{!?with_pam: %global with_pam 0 }
%{!?with_pbrd: %global with_pbrd 1 }
%{!?with_pimd: %global with_pimd 1 }
+%{!?with_pim6d: %global with_pim6d 0 }
%{!?with_vrrpd: %global with_vrrpd 1 }
%{!?with_rtadv: %global with_rtadv 1 }
%{!?with_watchfrr: %global with_watchfrr 1 }
@@ -81,6 +82,7 @@
# if CentOS / RedHat and version < 7, then disable PIMd (too old, won't work)
%if 0%{?rhel} && 0%{?rhel} < 7
%global with_pimd 0
+ %global with_pim6d 0
%endif
# misc internal defines
@@ -102,6 +104,12 @@
%define daemon_pimd ""
%endif
+%if %{with_pim6d}
+ %define daemon_pim6d pim6d
+%else
+ %define daemon_pim6d ""
+%endif
+
%if %{with_pbrd}
%define daemon_pbrd pbrd
%else
@@ -150,7 +158,7 @@
%define daemon_pathd ""
%endif
-%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd} %{daemon_bfdd} %{daemon_vrrpd} %{daemon_pathd}
+%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_pim6d} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd} %{daemon_bfdd} %{daemon_vrrpd} %{daemon_pathd}
#release sub-revision (the two digits after the CONFDATE)
%{!?release_rev: %global release_rev 01 }
@@ -342,6 +350,11 @@ routing state through standard SNMP MIBs.
%else
--disable-pimd \
%endif
+%if %{with_pim6d}
+ --enable-pim6d \
+%else
+ --disable-pim6d \
+%endif
%if %{with_pbrd}
--enable-pbrd \
%else
@@ -666,6 +679,9 @@ fi
%if %{with_pimd}
%{_sbindir}/pimd
%endif
+%if %{with_pim6d}
+ %{_sbindir}/pim6d
+%endif
%if %{with_pbrd}
%{_sbindir}/pbrd
%endif
diff --git a/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py
new file mode 100644
index 0000000000..272a7fe291
--- /dev/null
+++ b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py
@@ -0,0 +1,2102 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF")
+# in this file.
+#
+# 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.
+# Shreenidhi A R <rshreenidhi@vmware.com>
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+"""
+Following scenerios are covered.
+1. When there is change in route-map policy associated with default-originate, changes does not reflect.
+2. When route-map associated with default-originate is deleted, default route doesn't get withdrawn
+3. Update message is not being sent when only route-map is removed from the default-originate config.
+4. SNT counter gets incremented on change of every policy associated with default-originate
+5. Route-map with multiple match clauses causes inconsistencies with default-originate.
+6. BGP-Default originate behaviour with BGP attributes
+"""
+import os
+import sys
+import time
+import pytest
+from copy import deepcopy
+from lib.topolog import logger
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topojson import build_config_from_json
+from lib.topolog import logger
+
+from lib.bgp import (
+ verify_bgp_convergence,
+ create_router_bgp,
+ get_prefix_count_route,
+ modify_as_number,
+ verify_bgp_rib,
+ get_dut_as_number,
+ verify_rib_default_route,
+ verify_fib_default_route,
+)
+from lib.common_config import (
+ verify_fib_routes,
+ step,
+ required_linux_kernel_version,
+ create_route_maps,
+ interface_status,
+ create_prefix_lists,
+ get_frr_ipv6_linklocal,
+ start_topology,
+ write_test_header,
+ verify_prefix_lists,
+ check_address_types,
+ write_test_footer,
+ reset_config_on_routers,
+ create_static_routes,
+ check_router_status,
+ delete_route_maps,
+)
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+
+# Global variables
+topo = None
+NETWORK1_1 = {"ipv4": "198.51.1.1/32", "ipv6": "2001:DB8::1:1/128"}
+DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.15")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/bgp_default_originate_topo1.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global ADDR_TYPES
+ global BGP_CONVERGENCE
+ global DEFAULT_ROUTES
+ global DEFAULT_ROUTE_NXT_HOP_R1, DEFAULT_ROUTE_NXT_HOP_R3
+ ADDR_TYPES = check_address_types()
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ interface = topo["routers"]["r1"]["links"]["r2"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r1", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_R1 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+
+ interface = topo["routers"]["r3"]["links"]["r2"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r3", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r3"]["links"]["r2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r3"]["links"]["r2"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_R3 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_default_originate_delete_conditional_routemap(request):
+ """
+ "scenerio covered":
+ 1. When there is change in route-map policy associated with default-originate, changes does not reflect.
+ 2. When route-map associated with default-originate is deleted, default route doesn't get withdrawn
+ 3. Update message is not being sent when only route-map is removed from the default-originate config.
+ 4. SNT counter gets incremented on change of every policy associated with default-originate
+ 5. Route-map with multiple match clauses causes inconsistencies with default-originate.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ global topo
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ step("Configure IPv4 and IPv6 , IBGP neighbor between R1 and R2")
+ step("Configure IPv4 and IPv6 , EBGP neighbor between R1 and R0")
+ input_dict = {
+ "r0": {
+ "bgp": {
+ "local_as": 999,
+ }
+ },
+ "r1": {
+ "bgp": {
+ "local_as": 1000,
+ }
+ },
+ "r2": {
+ "bgp": {
+ "local_as": 1000,
+ }
+ },
+ "r3": {
+ "bgp": {
+ "local_as": 2000,
+ }
+ },
+ "r4": {
+ "bgp": {
+ "local_as": 3000,
+ }
+ },
+ }
+ result = modify_as_number(tgen, topo, input_dict)
+ try:
+ assert result is True
+ except AssertionError:
+ logger.info("Expected behaviour: {}".format(result))
+ logger.info("BGP config is not created because of invalid ASNs")
+
+ step("After changing the BGP remote as , Verify the BGP Convergence")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert (
+ BGP_CONVERGENCE is True
+ ), "Complete convergence is expected after changing ASN ....! ERROR :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Configure 1 IPv4 and 1 IPv6 Static route on R0 with next-hop as Null0")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the static route \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify IPv4 and IPv6 static route are configured and up on R0")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r0", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : routes {} not found in R0 FIB \n Error: {}".format(
+ tc_name, static_routes_input, result
+ )
+
+ step(
+ "Configure redistribute static on IPv4 and IPv6 address family on R0 for R0 to R1 neighbor "
+ )
+ redistribute_static = {
+ "r0": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure redistribute configuration....! \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("verify IPv4 and IPv6 static route are received on R1")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r1", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed... Routes {} expected in r1 FIB after configuring the redistribute config on R0 \n Error: {}".format(
+ tc_name, static_routes_input, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", static_routes_input)
+ assert (
+ result is True
+ ), "Testcase {} : Failed... Routes {} expected in r1 RIB after configuring the redistribute config on R0\n Error: {}".format(
+ tc_name, static_routes_input, result
+ )
+
+ step(
+ "Configure IPv4 prefix-list 'Pv4' and and IPv6 prefix-list 'Pv6' on R1 to match BGP route Sv41, IPv6 route Sv61 permit "
+ )
+ input_dict_3 = {
+ "r1": {
+ "prefix_lists": {
+ "ipv4": {
+ "Pv4": [
+ {
+ "seqid": "1",
+ "network": NETWORK1_1["ipv4"],
+ "action": "permit",
+ },
+ ]
+ },
+ "ipv6": {
+ "Pv6": [
+ {
+ "seqid": "1",
+ "network": NETWORK1_1["ipv6"],
+ "action": "permit",
+ },
+ ]
+ },
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the prefix list \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure IPV4 and IPv6 route-map (RMv4 and RMv6) matching prefix-list (Pv4 and Pv6) respectively on R1"
+ )
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ "set": {
+ "path": {
+ "as_num": "5555",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ "set": {
+ "path": {
+ "as_num": "5555",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the route map \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure default-originate with route-map (RMv4 and RMv6) on R1, on BGP IPv4 and IPv6 address family "
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv4"}}}
+ },
+ "ipv6": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv6"}}}
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the default originate \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After configuring default-originate command , verify default routes are advertised on R2 "
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ metric=0,
+ expected_aspath="5555",
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the default originate \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the default originate \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Changing the as-path policy of the existing route-map")
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ "set": {
+ "path": {
+ "as_num": "6666",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ "set": {
+ "path": {
+ "as_num": "6666",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the route map \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify prefix sent count on R1 towards R2 \n Send count shoud not be incremented on change of existing (AS-path) policy "
+ )
+ snapshot = get_prefix_count_route(
+ tgen, topo, dut="r1", peer="r2", link="r1", sent=True, received=False
+ )
+
+ ipv4_prefix_count = False
+ ipv6_prefix_count = False
+ if snapshot["ipv4_count"] == 2:
+ ipv4_prefix_count = True
+ if snapshot["ipv6_count"] == 2:
+ ipv6_prefix_count = True
+
+ assert (
+ ipv4_prefix_count is True
+ ), "Testcase {} : Failed Error: Expected sent Prefix is 2 but obtained {} ".format(
+ tc_name, ipv4_prefix_count
+ )
+ assert (
+ ipv6_prefix_count is True
+ ), "Testcase {} : Failed Error: Expected sent Prefix is 2 but obtained {} ".format(
+ tc_name, ipv6_prefix_count
+ )
+
+ step(
+ "After changing the as-path policy verify the new policy is advertised to router R2"
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ metric=0,
+ expected_aspath="6666",
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Default route with expected attributes is not found in BGP RIB \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Default route with expected attributes is not found in BGP FIB \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the as-path policy from the route-map")
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ "set": {
+ "path": {
+ "as_num": "6666",
+ "as_action": "prepend",
+ "delete": True,
+ }
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ "set": {
+ "path": {
+ "as_num": "6666",
+ "as_action": "prepend",
+ "delete": True,
+ }
+ },
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the route map \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the route policy (AS-Path) verify that as-path is removed in r2 "
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ )
+ assert result is True, "Testcase {} : Failed ... ! \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed .... !\n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Delete the route-map ")
+
+ delete_routemap = {"r1": {"route_maps": ["RMv4", "RMv6"]}}
+ result = delete_route_maps(tgen, delete_routemap)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to delete the route-map\n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After deleting route-map , verify the default route in FIB and RIB are removed "
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ metric=0,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : After removing the route-map the default-route is not removed from R2 RIB\n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : After removing the route-map the default-route is not removed from R2 FIB \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Create route-map with with sequnce number 10 ")
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ "set": {
+ "path": {
+ "as_num": "9999",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ "set": {
+ "path": {
+ "as_num": "9999",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the route map \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After Configuring the route-map the dut is expected to receive the route policy (as-path) as 99999"
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ metric=0,
+ expected_aspath="9999",
+ )
+ assert result is True, "Testcase {} : Failed...! \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert result is True, "Testcase {} : Failed ...!\n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Create another route-map with seq number less than the previous i. <10 ")
+ input_dict_3 = {
+ "r1": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "5",
+ "match": {"ipv4": {"prefix_lists": "Pv4"}},
+ "set": {
+ "path": {
+ "as_num": "7777",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "5",
+ "match": {"ipv6": {"prefix_lists": "Pv6"}},
+ "set": {
+ "path": {
+ "as_num": "7777",
+ "as_action": "prepend",
+ }
+ },
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert (
+ result is True
+ ), "Testcase {} : Failed to configure the route map \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On creating new route-map the route-map with lower seq id should be considered "
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ metric=0,
+ expected_aspath="7777",
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Route-map with lowest prefix is not considered \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R1,
+ expected=True,
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Route-map with lowest prefix is not considered \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_default_originate_after_BGP_attributes_p1(request):
+ """
+ "Verify different BGP attributes with default-originate route "
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ global topo
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ step("Configure IPv4 and IPv6 , EBGP neighbor between R3 and R2")
+ step("Configure IPv4 and IPv6 IBGP neighbor between R3 and R4")
+ r0_local_as = topo['routers']['r0']['bgp']['local_as']
+ r1_local_as = topo['routers']['r1']['bgp']['local_as']
+ r2_local_as = topo['routers']['r2']['bgp']['local_as']
+ r3_local_as = topo['routers']['r3']['bgp']['local_as']
+ r4_local_as = topo['routers']['r4']['bgp']['local_as']
+ input_dict = {
+ "r0": {
+ "bgp": {
+ "local_as": r0_local_as,
+ }
+ },
+ "r1": {
+ "bgp": {
+ "local_as": r1_local_as,
+ }
+ },
+ "r2": {
+ "bgp": {
+ "local_as": r2_local_as,
+ }
+ },
+ "r3": {
+ "bgp": {
+ "local_as": 4000,
+ }
+ },
+ "r4": {
+ "bgp": {
+ "local_as": 4000,
+ }
+ },
+ }
+ result = modify_as_number(tgen, topo, input_dict)
+
+ try:
+ assert result is True
+ except AssertionError:
+ logger.info("Expected behaviour: {}".format(result))
+ logger.info("BGP config is not created because of invalid ASNs")
+ step("After changing the BGP AS Path Verify the BGP Convergence")
+
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step(
+ "Configure one IPv4 and one IPv6, Static route on R4 with next-hop as Null0 IPv4 route Sv41, IPv6 route Sv61 "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Verify IPv4 and IPv6 static routes configured on R4 in FIB")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure redistribute static knob on R4 , for R4 to R3 neighbor for IPv4 and IPv6 address family "
+ )
+ redistribute_static = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify After configuring redistribute static , verify route received in BGP table of R3"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r3", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r3", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ NOTE = """Configure 2 IPv4 prefix-list Pv41 Pv42 and and 2 IPv6 prefix-list Pv61 Pv62 on R3 to match BGP IPv4 route Sv41, 200.1.1.1/24 , IPv6 route Sv61 and 200::1/64"""
+ step(NOTE)
+ input_dict_3 = {
+ "r3": {
+ "prefix_lists": {
+ "ipv4": {
+ "Pv41": [
+ {
+ "seqid": "1",
+ "network": NETWORK1_1["ipv4"],
+ "action": "permit",
+ }
+ ],
+ "Pv42": [
+ {"seqid": "1", "network": "200.1.1.1/24", "action": "permit"}
+ ],
+ },
+ "ipv6": {
+ "Pv61": [
+ {
+ "seqid": "1",
+ "network": NETWORK1_1["ipv6"],
+ "action": "permit",
+ }
+ ],
+ "Pv62": [
+ {"seqid": " 1", "network": "200::1/64", "action": "permit"}
+ ],
+ },
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify IPv4 and IPv6 Prefix list got configured on R3")
+ input_dict = {"r3": {"prefix_lists": ["Pv41", "Pv61", "Pv42", "Pv62"]}}
+ result = verify_prefix_lists(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure 2 sequence of route-map for IPv4 seq1 permit Pv41 and seq2 permit Pv42 and for IPv6 seq1 permit Pv61 , seq2 permit Pv62 on R3"
+ )
+ input_dict_3 = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv4": {"prefix_lists": "Pv41"}},
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "match": {"ipv4": {"prefix_lists": "Pv42"}},
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "match": {"ipv6": {"prefix_lists": "Pv61"}},
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "match": {"ipv6": {"prefix_lists": "Pv62"}},
+ },
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Apply on route-map seq1 set as-path prepend to 200 and route-map seq2 set as-path prepend to 300 for IPv4 and IPv6 route-map "
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "path": {
+ "as_num": "200",
+ "as_action": "prepend",
+ }
+ }
+
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "300",
+ "as_action": "prepend",
+ }
+ }
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "path": {
+ "as_num": "200",
+ "as_action": "prepend",
+ }
+ }
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "300",
+ "as_action": "prepend",
+ }
+ }
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ " Configure default-originate with IPv4 and IPv6 route-map on R3 for R3-R2 IPv4 and IPv6 BGP neighbor"
+ )
+
+ local_as = get_dut_as_number(tgen, dut="r3")
+ default_originate_config = {
+ "r3": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv4"}}}
+ },
+ "ipv6": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv6"}}}
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify IPv4 and IPv6 default route received on R2 with both the AS path on R2"
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=0,
+ expected_aspath="4000 200",
+ )
+
+ step(
+ "Modify AS prepend path adding one more value 500 in route-map sequence 1 and 600 for route-map sequence 2 for IPv4 and IPv6 route-map"
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "path": {
+ "as_num": "500",
+ "as_action": "prepend",
+ }
+ }
+
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "600",
+ "as_action": "prepend",
+ }
+ }
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "path": {
+ "as_num": "500",
+ "as_action": "prepend",
+ }
+ }
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "600",
+ "as_action": "prepend",
+ }
+ }
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+
+ step("As path 500 added to IPv4 and IPv6 default -originate route received on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=0,
+ expected_aspath="4000 500",
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Apply on route-map seq1 set metric value to 70 and route-map seq2 set metric 80 IPv4 and IPv6 route-map"
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "metric": 70,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "metric": 80,
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "metric": 70,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "metric": 80,
+ },
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify Configured metric value received on R2 along with as-path for IPv4 and IPv6 default routes "
+ )
+
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "::/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=70,
+ expected_aspath="4000 500",
+ )
+
+
+ step(
+ "Modify route-map seq1 configure metric 50 and route-map seq2 configure metric 100 IPv4 and IPv6 route-map "
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "metric": 50,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "metric": 100,
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "metric": 50,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "metric": 100,
+ },
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify Configured metric value received on R2 along with as-path for IPv4 and IPv6 default routes "
+ )
+
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=50,
+ expected_aspath="4000 500",
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Delete AS-prepend from IP4 and IPv6 route-map configured on R3 ")
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+
+ "set": {
+ "path": {
+ "as_num": "500",
+ "as_action": "prepend",
+ "delete": True,
+ },
+ "delete": True,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "600",
+ "as_action": "prepend",
+ "delete": True,
+ },
+ "delete": True,
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "path": {
+ "as_num": "500",
+ "as_action": "prepend",
+ "delete": True,
+ },
+ "delete": True,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "path": {
+ "as_num": "600",
+ "as_action": "prepend",
+ "delete": True,
+ },
+ "delete": True,
+ },
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify AS-prepend is deleted from default originate route and metric value only present on R2 for IPv4 and IPv6 default routes "
+ )
+
+
+
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=50,
+ expected_aspath="4000",
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+
+ step("Delete metric value from IP4 and IPv6 route-map configured on R3 ")
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {"metric": 50, "delete": True},
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {"metric": 100, "delete": True},
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {"metric": 50, "delete": True},
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {"metric": 100, "delete": True},
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify Metric value deleted from IPv4 and IPv6 default route on R2 ,verify default routes "
+ )
+
+
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ metric=0,
+ expected_aspath="4000",
+ )
+
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ step("Change IPv4 and IPv6 , EBGP to IBGP neighbor between R3 and R2")
+ step("Change IPv4 and IPv6 IBGP to EBGP neighbor between R3 and R4")
+ r0_local_as = topo['routers']['r0']['bgp']['local_as']
+ r1_local_as = topo['routers']['r1']['bgp']['local_as']
+ r2_local_as = topo['routers']['r2']['bgp']['local_as']
+ r3_local_as = topo['routers']['r3']['bgp']['local_as']
+ r4_local_as = topo['routers']['r4']['bgp']['local_as']
+ input_dict = {
+ "r0": {
+ "bgp": {
+ "local_as": r0_local_as,
+ }
+ },
+ "r1": {
+ "bgp": {
+ "local_as": r1_local_as,
+ }
+ },
+
+ "r2": {
+ "bgp": {
+ "local_as": 1111,
+ }
+ },
+ "r3": {
+ "bgp": {
+ "local_as": 1111,
+ }
+ },
+ "r4": {
+ "bgp": {
+ "local_as": 5555,
+ }
+ },
+ }
+ result = modify_as_number(tgen, topo, input_dict)
+ try:
+ assert result is True
+ except AssertionError:
+ logger.info("Expected behaviour: {}".format(result))
+ logger.info("BGP config is not created because of invalid ASNs")
+ step("After changing the BGP AS Path Verify the BGP Convergence")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+ step(
+ "Configure one IPv4 and one IPv6, Static route on R4 with next-hop as Null0 IPv4 route Sv41, IPv6 route Sv61 "
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Verify IPv4 and IPv6 static routes configured on R4 in FIB")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure redistribute static knob on R4 , for R4 to R3 neighbor for IPv4 and IPv6 address family "
+ )
+ redistribute_static = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify After configuring redistribute static , verify route received in BGP table of R3"
+ )
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r3", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, "r3", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step(
+ " Configure default-originate with IPv4 and IPv6 route-map on R3 for R3-R2 IPv4 and IPv6 BGP neighbor"
+ )
+ local_as = get_dut_as_number(tgen, dut="r3")
+ default_originate_config = {
+ "r3": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv4"}}}
+ },
+ "ipv6": {
+ "unicast": {"default_originate": {"r2": {"route_map": "RMv6"}}}
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify IPv4 and IPv6 default route received on R2 with both the AS path on R2"
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Configure local -preference to 50 on IPv4 and IPv6 route map seq1 and 60 on seq2"
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "locPrf": 50,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "locPrf": 60,
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "locPrf": 50,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "locPrf": 60,
+ },
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify Configured metric value received on R2 along with as-path for IPv4 and IPv6 default routes "
+ )
+
+
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ locPrf=50,
+ )
+
+
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Modify local preference value to 150 on IPv4 and IPv6 route map seq1 and 160 on seq2"
+ )
+ route_map = {
+ "r3": {
+ "route_maps": {
+ "RMv4": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "locPrf": 150,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "locPrf": 160,
+ },
+ },
+ ],
+ "RMv6": [
+ {
+ "action": "permit",
+ "seq_id": "1",
+ "set": {
+ "locPrf": 150,
+ },
+ },
+ {
+ "action": "permit",
+ "seq_id": "2",
+ "set": {
+ "locPrf": 160,
+ },
+ },
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify Modified local-preference value received on R2 for IPv4 and IPv6 default routes "
+ )
+
+
+
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "::/0"}
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ locPrf=150,
+ )
+
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ # updating the topology with the updated AS-Number to avoid conflict in con configuring the AS
+ updated_topo = topo
+ updated_topo['routers']['r0']['bgp']['local_as']=get_dut_as_number(tgen,"r0")
+ updated_topo['routers']['r1']['bgp']['local_as']=get_dut_as_number(tgen,"r1")
+ updated_topo['routers']['r2']['bgp']['local_as']=get_dut_as_number(tgen,"r2")
+ updated_topo['routers']['r3']['bgp']['local_as']=get_dut_as_number(tgen,"r3")
+ updated_topo['routers']['r4']['bgp']['local_as']=get_dut_as_number(tgen,"r4")
+
+ step("Shut IPv4/IPv6 BGP neighbor from R4 ( R4-R3) using 'neighbor x.x.x.x shut' command ")
+ local_as = get_dut_as_number(tgen, dut="r4")
+ shut_neighbor = {
+ "r4": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {"shutdown":True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {"shutdown":True}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, shut_neighbor)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ interface = topo['routers']['r3']['links']['r4']['interface']
+ input_dict = {
+ "r1": {
+ "interface_list": [interface],
+ "status": "down"
+ }
+ }
+
+ result = interface_status(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Shut down the interface failed ! \n Error: {}".format(tc_name, result)
+
+ step("After shutting the interface verify the BGP convergence")
+ result = verify_bgp_convergence(tgen,topo,expected=False)
+ assert result is not True, "Testcase {} : Failed \n After shutting Down BGP convergence should Fail and return False \n Error: {}".format(tc_name, result)
+
+ step("verify default route deleted from R2 ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: After Shut down interface the default route is NOT expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: After Shut down interface the default route is NOT expected but found in FIB -> {}".format( tc_name, result)
+
+
+ step("no Shut IPv4/IPv6 BGP neighbor from R4 ( R4-R3) using 'neighbor x.x.x.x shut' command ")
+ local_as = get_dut_as_number(tgen, dut="r4")
+ shut_neighbor = {
+ "r4": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {"shutdown":False}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {"shutdown":False}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, shut_neighbor)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ interface = topo['routers']['r3']['links']['r4']['interface']
+ input_dict = {
+ "r1": {
+ "interface_list": [interface],
+ "status": "up"
+ }
+ }
+
+ result = interface_status(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Bring up interface failed ! \n Error: {}".format(tc_name, result)
+
+ step("After no shutting the interface verify the BGP convergence")
+ result = verify_bgp_convergence(tgen,topo,expected=True)
+ assert result is True, "Testcase {} : Failed \n After shutting Down BGP convergence should Fail and return False \n Error: {}".format(tc_name, result)
+
+ step("After no shut neighbor , verify default route relearn on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True)
+ assert result is True, "Testcase {} : Failed \n Error: After no Shut down interface the default route is expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected=True)
+ assert result is True, "Testcase {} : Failed \n Error: After Shut down interface the default route is expected but found in FIB -> {}".format( tc_name, result)
+
+
+
+ step("Remove IPv4/IPv6 static route configure on R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "delete": True
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Verify IPv4 and IPv6 static routes removed on R4 in FIB")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r4", static_routes_input, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("After removing static route , verify default route removed on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= False)
+ assert result is not True, "Testcase {} : Failed \n Error: After removing static the default route is NOT expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= False)
+ assert result is not True, "Testcase {} : Failed \n Error: After removing static the default route is NOT expected but found in FIB -> {}".format( tc_name, result)
+
+
+ step("Configuring the static route back in r4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Verify IPv4 and IPv6 static routes configured on R4 in FIB")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input, expected=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r4", static_routes_input, expected=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("After adding static route back , verify default route learned on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= True)
+ assert result is True, "Testcase {} : Failed \n Error: After removing static the default route is expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= True)
+ assert result is True, "Testcase {} : Failed \n Error: After removing static the default route is expected but found in FIB -> {}".format( tc_name, result)
+
+ step("Deactivate IPv4 and IPv6 neighbor configured from R4 ( R4-R3)")
+
+ configure_bgp_on_r1 = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {"deactivate": "ipv4"}}}
+ }
+ },
+
+ },"ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {"deactivate": "ipv6"}}}
+ }
+ },
+
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, configure_bgp_on_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("After deactivating the BGP neighbor , verify default route removed on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= False)
+ assert result is not True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is NOT expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= False)
+ assert result is not True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is NOT expected but found in FIB -> {}".format( tc_name, result)
+
+ step("Activate IPv4 and IPv6 neighbor configured from R4 ( R4-R3)")
+
+ configure_bgp_on_r1 = {
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {"activate": "ipv4"}}}
+ }
+ },
+
+ },"ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {"activate": "ipv6"}}}
+ }
+ },
+
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, updated_topo, configure_bgp_on_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify bgp convergence.")
+ bgp_convergence = verify_bgp_convergence(tgen, updated_topo)
+ assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, bgp_convergence
+ )
+ step("After Activating the BGP neighbor , verify default route learned on R2")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= True)
+ assert result is True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is expected but found in RIB -> {}".format( tc_name, result)
+
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3,
+ expected= True)
+ assert result is True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is expected but found in FIB -> {}".format( tc_name, result)
+ write_test_footer(tc_name)
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in
index 3344ff4954..6eb3223faa 100755
--- a/tools/frrcommon.sh.in
+++ b/tools/frrcommon.sh.in
@@ -208,7 +208,7 @@ daemon_stop() {
[ -r "$pidfile" ] || fail="pid file not found"
$all && [ -n "$fail" ] && return 0
- [ -z "$fail" ] && pid="$(cat \"$pidfile\")"
+ [ -z "$fail" ] && pid="$(cat "$pidfile")"
[ -z "$fail" -a -z "$pid" ] && fail="pid file is empty"
[ -n "$fail" ] || kill -0 "$pid" 2>/dev/null || fail="pid $pid not running"
@@ -242,7 +242,7 @@ daemon_status() {
pidfile="$V_PATH/$daemon${inst:+-$inst}.pid"
[ -r "$pidfile" ] || return 3
- pid="$(cat \"$pidfile\")"
+ pid="$(cat "$pidfile")"
[ -z "$pid" ] && return 1
kill -0 "$pid" 2>/dev/null || return 1
return 0
diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c
index d463411dea..6d90a603f7 100644
--- a/zebra/zebra_evpn_neigh.c
+++ b/zebra/zebra_evpn_neigh.c
@@ -702,11 +702,6 @@ struct zebra_neigh *zebra_evpn_proc_sync_neigh_update(
n->flags |= ZEBRA_NEIGH_LOCAL_INACTIVE;
}
- if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
- SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
- else
- SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
-
if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
/* if the neigh was peer-active previously we