diff options
68 files changed, 1208 insertions, 920 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 4ea81216bf..2e2248cd72 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1231,6 +1231,46 @@ bool aspath_private_as_check(struct aspath *aspath) return true; } +/* Replace all ASN instances of the regex rule with our own ASN */ +struct aspath *aspath_replace_regex_asn(struct aspath *aspath, + struct as_list *acl_list, as_t our_asn) +{ + struct aspath *new; + struct assegment *cur_seg; + struct as_list *cur_as_list; + struct as_filter *cur_as_filter; + char str_buf[ASPATH_STR_DEFAULT_LEN]; + uint32_t i; + + new = aspath_dup(aspath); + cur_seg = new->segments; + + while (cur_seg) { + cur_as_list = acl_list; + while (cur_as_list) { + cur_as_filter = cur_as_list->head; + while (cur_as_filter) { + for (i = 0; i < cur_seg->length; i++) { + snprintfrr(str_buf, + ASPATH_STR_DEFAULT_LEN, + ASN_FORMAT(new->asnotation), + &cur_seg->as[i]); + if (!regexec(cur_as_filter->reg, + str_buf, 0, NULL, 0)) + cur_seg->as[i] = our_asn; + } + cur_as_filter = cur_as_filter->next; + } + cur_as_list = cur_as_list->next; + } + cur_seg = cur_seg->next; + } + + aspath_str_update(new, false); + return new; +} + + /* Replace all instances of the target ASN with our own ASN */ struct aspath *aspath_replace_specific_asn(struct aspath *aspath, as_t target_asn, as_t our_asn) diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index b1a61d5b99..ebfc7d087d 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -107,6 +107,9 @@ extern unsigned int aspath_get_last_as(struct aspath *aspath); extern int aspath_loop_check(struct aspath *aspath, as_t asno); extern int aspath_loop_check_confed(struct aspath *aspath, as_t asno); extern bool aspath_private_as_check(struct aspath *aspath); +extern struct aspath *aspath_replace_regex_asn(struct aspath *aspath, + struct as_list *acl_list, + as_t our_asn); extern struct aspath *aspath_replace_specific_asn(struct aspath *aspath, as_t target_asn, as_t our_asn); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index a33f59cf5b..35f2438929 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1924,7 +1924,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, /* Mark route as self type-2 route */ if (flags && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP)) - tmp_pi->extra->af_flags = BGP_EVPN_MACIP_TYPE_SVI_IP; + tmp_pi->extra->evpn->af_flags = + BGP_EVPN_MACIP_TYPE_SVI_IP; bgp_path_info_add(dest, tmp_pi); } else { tmp_pi = local_pi; @@ -2390,7 +2391,8 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, attr.router_flag = 1; } memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t)); - bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr, local_pi->extra->af_flags); + bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr, + local_pi->extra->evpn->af_flags); vni2label(vpn->vni, &(attr.label)); /* Add L3 VNI RTs and RMAC for non IPv6 link-local if * using L3 VNI for type-2 routes also. @@ -2829,7 +2831,11 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi, attr_new, dest); SET_FLAG(pi->flags, BGP_PATH_VALID); bgp_path_info_extra_get(pi); - pi->extra->parent = bgp_path_info_lock(parent_pi); + if (!pi->extra->vrfleak) + pi->extra->vrfleak = + XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VRFLEAK, + sizeof(struct bgp_path_info_extra_vrfleak)); + pi->extra->vrfleak->parent = bgp_path_info_lock(parent_pi); bgp_dest_lock_node((struct bgp_dest *)parent_pi->net); if (parent_pi->extra) { memcpy(&pi->extra->label, &parent_pi->extra->label, @@ -2935,8 +2941,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Check if route entry is already present. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) - if (pi->extra - && (struct bgp_path_info *)pi->extra->parent == parent_pi) + if (pi->extra && pi->extra->vrfleak && + (struct bgp_path_info *)pi->extra->vrfleak->parent == + parent_pi) break; if (!pi) { @@ -3031,8 +3038,9 @@ static int install_evpn_route_entry_in_vni_common( /* Check if route entry is already present. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) - if (pi->extra - && (struct bgp_path_info *)pi->extra->parent == parent_pi) + if (pi->extra && pi->extra->vrfleak && + (struct bgp_path_info *)pi->extra->vrfleak->parent == + parent_pi) break; if (!pi) { @@ -3127,8 +3135,9 @@ static int uninstall_evpn_route_entry_in_vni_common( /* Find matching route entry. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) - if (pi->extra && - (struct bgp_path_info *)pi->extra->parent == parent_pi) + if (pi->extra && pi->extra->vrfleak && + (struct bgp_path_info *)pi->extra->vrfleak->parent == + parent_pi) break; if (!pi) @@ -3305,8 +3314,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Find matching route entry. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) - if (pi->extra - && (struct bgp_path_info *)pi->extra->parent == parent_pi) + if (pi->extra && pi->extra->vrfleak && + (struct bgp_path_info *)pi->extra->vrfleak->parent == + parent_pi) break; if (!pi) { diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 076248c9f7..55474464e5 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -51,15 +51,15 @@ get_route_parent_evpn(struct bgp_path_info *ri) struct bgp_path_info *parent_ri; /* If not imported (or doesn't have a parent), bail. */ - if (ri->sub_type != BGP_ROUTE_IMPORTED || - !ri->extra || - !ri->extra->parent) + if (ri->sub_type != BGP_ROUTE_IMPORTED || !ri->extra || + !ri->extra->vrfleak || !ri->extra->vrfleak->parent) return NULL; /* Determine parent recursively */ - for (parent_ri = ri->extra->parent; - parent_ri->extra && parent_ri->extra->parent; - parent_ri = parent_ri->extra->parent) + for (parent_ri = ri->extra->vrfleak->parent; + parent_ri->extra && parent_ri->extra->vrfleak && + parent_ri->extra->vrfleak->parent; + parent_ri = parent_ri->extra->vrfleak->parent) ; return parent_ri; @@ -103,12 +103,11 @@ static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi) struct bgp_table *table; struct bgp_dest *dest; - if (pi->sub_type != BGP_ROUTE_IMPORTED || - !pi->extra || - !pi->extra->parent) + if (pi->sub_type != BGP_ROUTE_IMPORTED || !pi->extra || + !pi->extra->vrfleak || !pi->extra->vrfleak->parent) return true; - parent_pi = (struct bgp_path_info *)pi->extra->parent; + parent_pi = (struct bgp_path_info *)pi->extra->vrfleak->parent; dest = parent_pi->net; if (!dest) return true; diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index efadda17b8..36bf752d48 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -185,8 +185,9 @@ static int bgp_evpn_es_route_install(struct bgp *bgp, /* Check if route entry is already present. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) - if (pi->extra && - (struct bgp_path_info *)pi->extra->parent == parent_pi) + if (pi->extra && pi->extra->vrfleak && + (struct bgp_path_info *)pi->extra->vrfleak->parent == + parent_pi) break; if (!pi) { @@ -198,7 +199,11 @@ static int bgp_evpn_es_route_install(struct bgp *bgp, parent_pi->peer, attr_new, dest); SET_FLAG(pi->flags, BGP_PATH_VALID); bgp_path_info_extra_get(pi); - pi->extra->parent = bgp_path_info_lock(parent_pi); + if (!pi->extra->vrfleak) + pi->extra->vrfleak = + XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VRFLEAK, + sizeof(struct bgp_path_info_extra_vrfleak)); + pi->extra->vrfleak->parent = bgp_path_info_lock(parent_pi); bgp_dest_lock_node((struct bgp_dest *)parent_pi->net); bgp_path_info_add(dest, pi); } else { @@ -253,9 +258,9 @@ static int bgp_evpn_es_route_uninstall(struct bgp *bgp, struct bgp_evpn_es *es, /* Find matching route entry. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) - if (pi->extra - && (struct bgp_path_info *)pi->extra->parent == - parent_pi) + if (pi->extra && pi->extra->vrfleak && + (struct bgp_path_info *)pi->extra->vrfleak->parent == + parent_pi) break; if (!pi) { @@ -1548,10 +1553,11 @@ bgp_evpn_path_es_info_new(struct bgp_path_info *pi, vni_t vni) e = bgp_path_info_extra_get(pi); /* If mh_info doesn't exist allocate it */ - mh_info = e->mh_info; + mh_info = e->evpn->mh_info; if (!mh_info) - e->mh_info = mh_info = XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO, - sizeof(struct bgp_path_mh_info)); + e->evpn->mh_info = mh_info = + XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO, + sizeof(struct bgp_path_mh_info)); /* If es_info doesn't exist allocate it */ es_info = mh_info->es_info; @@ -1604,8 +1610,8 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi) struct bgp_evpn_es *es; struct bgp *bgp_evpn; - es_info = (pi->extra && pi->extra->mh_info) - ? pi->extra->mh_info->es_info + es_info = (pi->extra && pi->extra->evpn && pi->extra->evpn->mh_info) + ? pi->extra->evpn->mh_info->es_info : NULL; /* if the esi is zero just unlink the path from the old es */ if (!esi || !memcmp(esi, zero_esi, sizeof(*esi))) { @@ -3163,7 +3169,7 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi, *nhg_p = 0; /* we don't support NHG for routes leaked from another VRF yet */ - if (pi->extra && pi->extra->bgp_orig) + if (pi->extra && pi->extra->vrfleak && pi->extra->vrfleak->bgp_orig) return false; parent_pi = get_route_parent_evpn(pi); @@ -4670,10 +4676,11 @@ bgp_evpn_path_nh_info_new(struct bgp_path_info *pi) e = bgp_path_info_extra_get(pi); /* If mh_info doesn't exist allocate it */ - mh_info = e->mh_info; + mh_info = e->evpn->mh_info; if (!mh_info) - e->mh_info = mh_info = XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO, - sizeof(struct bgp_path_mh_info)); + e->evpn->mh_info = mh_info = + XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO, + sizeof(struct bgp_path_mh_info)); /* If nh_info doesn't exist allocate it */ nh_info = mh_info->nh_info; @@ -4738,8 +4745,8 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi) return; } - nh_info = (pi->extra && pi->extra->mh_info) - ? pi->extra->mh_info->nh_info + nh_info = (pi->extra && pi->extra->evpn && pi->extra->evpn->mh_info) + ? pi->extra->evpn->mh_info->nh_info : NULL; /* if NHG is not being used for this path we don't need to manage the @@ -4805,8 +4812,8 @@ void bgp_evpn_path_nh_del(struct bgp *bgp_vrf, struct bgp_path_info *pi) { struct bgp_path_evpn_nh_info *nh_info; - nh_info = (pi->extra && pi->extra->mh_info) - ? pi->extra->mh_info->nh_info + nh_info = (pi->extra && pi->extra->evpn && pi->extra->evpn->mh_info) + ? pi->extra->evpn->mh_info->nh_info : NULL; if (!nh_info) diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 8cee048b69..f141ddd6ef 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -581,32 +581,32 @@ evpn_type2_prefix_vni_mac_copy(struct prefix_evpn *vni_p, static inline struct ethaddr * evpn_type2_path_info_get_mac(const struct bgp_path_info *local_pi) { - assert(local_pi->extra); - return &local_pi->extra->vni_info.mac; + assert(local_pi->extra && local_pi->extra->evpn); + return &local_pi->extra->evpn->vni_info.mac; } /* Get IP of path_info prefix */ static inline struct ipaddr * evpn_type2_path_info_get_ip(const struct bgp_path_info *local_pi) { - assert(local_pi->extra); - return &local_pi->extra->vni_info.ip; + assert(local_pi->extra && local_pi->extra->evpn); + return &local_pi->extra->evpn->vni_info.ip; } /* Set MAC of path_info prefix */ static inline void evpn_type2_path_info_set_mac(struct bgp_path_info *local_pi, const struct ethaddr mac) { - assert(local_pi->extra); - local_pi->extra->vni_info.mac = mac; + assert(local_pi->extra && local_pi->extra->evpn); + local_pi->extra->evpn->vni_info.mac = mac; } /* Set IP of path_info prefix */ static inline void evpn_type2_path_info_set_ip(struct bgp_path_info *local_pi, const struct ipaddr ip) { - assert(local_pi->extra); - local_pi->extra->vni_info.ip = ip; + assert(local_pi->extra && local_pi->extra->evpn); + local_pi->extra->evpn->vni_info.ip = ip; } /* Is the IP empty for the RT's dest? */ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 442dd6ff3b..8b4f4509ae 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -389,7 +389,7 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf, } json_object_string_add(json, "advertiseGatewayMacip", "n/a"); json_object_string_add(json, "advertiseSviMacIp", "n/a"); - if (bgp_vrf && bgp_vrf->evpn_info) { + if (bgp_vrf->evpn_info) { json_object_string_add(json, "advertisePip", bgp_vrf->evpn_info->advertise_pip ? "Enabled" diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 7df1423e59..a295ec5a14 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -355,7 +355,8 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, bgp_path_info_extra_get(path); bool list_began = false; - if (extra->bgp_fs_pbr && listcount(extra->bgp_fs_pbr)) { + if (extra->flowspec && extra->flowspec->bgp_fs_pbr && + listcount(extra->flowspec->bgp_fs_pbr)) { struct listnode *node; struct bgp_pbr_match_entry *bpme; struct bgp_pbr_match *bpm; @@ -363,8 +364,8 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, list_bpm = list_new(); vty_out(vty, "\tinstalled in PBR"); - for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_pbr, - node, bpme)) { + for (ALL_LIST_ELEMENTS_RO(extra->flowspec->bgp_fs_pbr, node, + bpme)) { bpm = bpme->backpointer; if (listnode_lookup(list_bpm, bpm)) continue; @@ -378,13 +379,14 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, } list_delete(&list_bpm); } - if (extra->bgp_fs_iprule && listcount(extra->bgp_fs_iprule)) { + if (extra->flowspec && extra->flowspec->bgp_fs_iprule && + listcount(extra->flowspec->bgp_fs_iprule)) { struct listnode *node; struct bgp_pbr_rule *bpr; if (!list_began) vty_out(vty, "\tinstalled in PBR"); - for (ALL_LIST_ELEMENTS_RO(extra->bgp_fs_iprule, + for (ALL_LIST_ELEMENTS_RO(extra->flowspec->bgp_fs_iprule, node, bpr)) { if (!bpr->action) continue; diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 074059c146..11917c6c4a 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -57,15 +57,17 @@ /* bgpd options, we use GNU getopt library. */ static const struct option longopts[] = { - {"bgp_port", required_argument, NULL, 'p'}, - {"listenon", required_argument, NULL, 'l'}, - {"no_kernel", no_argument, NULL, 'n'}, - {"skip_runas", no_argument, NULL, 'S'}, - {"ecmp", required_argument, NULL, 'e'}, - {"int_num", required_argument, NULL, 'I'}, - {"no_zebra", no_argument, NULL, 'Z'}, - {"socket_size", required_argument, NULL, 's'}, - {0}}; + { "bgp_port", required_argument, NULL, 'p' }, + { "listenon", required_argument, NULL, 'l' }, + { "no_kernel", no_argument, NULL, 'n' }, + { "skip_runas", no_argument, NULL, 'S' }, + { "ecmp", required_argument, NULL, 'e' }, + { "int_num", required_argument, NULL, 'I' }, + { "no_zebra", no_argument, NULL, 'Z' }, + { "socket_size", required_argument, NULL, 's' }, + { "v6-with-v4-nexthops", no_argument, NULL, 'v' }, + { 0 } +}; /* signal definitions */ void sighup(void); @@ -387,16 +389,16 @@ int main(int argc, char **argv) addresses->cmp = (int (*)(void *, void *))strcmp; frr_preinit(&bgpd_di, argc, argv); - frr_opt_add( - "p:l:SnZe:I:s:" DEPRECATED_OPTIONS, longopts, - " -p, --bgp_port Set BGP listen port number (0 means do not listen).\n" - " -l, --listenon Listen on specified address (implies -n)\n" - " -n, --no_kernel Do not install route to kernel.\n" - " -Z, --no_zebra Do not communicate with Zebra.\n" - " -S, --skip_runas Skip capabilities checks, and changing user and group IDs.\n" - " -e, --ecmp Specify ECMP to use.\n" - " -I, --int_num Set instance number (label-manager)\n" - " -s, --socket_size Set BGP peer socket send buffer size\n"); + frr_opt_add("p:l:SnZe:I:s:" DEPRECATED_OPTIONS, longopts, + " -p, --bgp_port Set BGP listen port number (0 means do not listen).\n" + " -l, --listenon Listen on specified address (implies -n)\n" + " -n, --no_kernel Do not install route to kernel.\n" + " -Z, --no_zebra Do not communicate with Zebra.\n" + " -S, --skip_runas Skip capabilities checks, and changing user and group IDs.\n" + " -e, --ecmp Specify ECMP to use.\n" + " -I, --int_num Set instance number (label-manager)\n" + " -s, --socket_size Set BGP peer socket send buffer size\n" + " , --v6-with-v4-nexthop Allow BGP to form v6 neighbors using v4 nexthops\n"); /* Command line argument treatment. */ while (1) { @@ -458,6 +460,9 @@ int main(int argc, char **argv) case 's': buffer_size = atoi(optarg); break; + case 'v': + bm->v6_with_v4_nexthops = true; + break; default: frr_help_exit(1); } diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index d7b18de676..edaaef6021 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -37,6 +37,9 @@ DEFINE_MTYPE(BGPD, BGP_TABLE, "BGP table"); DEFINE_MTYPE(BGPD, BGP_NODE, "BGP node"); DEFINE_MTYPE(BGPD, BGP_ROUTE, "BGP route"); DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA, "BGP ancillary route info"); +DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_EVPN, "BGP extra info for EVPN"); +DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_FS, "BGP extra info for flowspec"); +DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_VRFLEAK, "BGP extra info for vrf leaking"); DEFINE_MTYPE(BGPD, BGP_CONN, "BGP connected"); DEFINE_MTYPE(BGPD, BGP_STATIC, "BGP static"); DEFINE_MTYPE(BGPD, BGP_ADVERTISE_ATTR, "BGP adv attr"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 7b00497714..1256eafd00 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -33,6 +33,9 @@ DECLARE_MTYPE(BGP_TABLE); DECLARE_MTYPE(BGP_NODE); DECLARE_MTYPE(BGP_ROUTE); DECLARE_MTYPE(BGP_ROUTE_EXTRA); +DECLARE_MTYPE(BGP_ROUTE_EXTRA_EVPN); +DECLARE_MTYPE(BGP_ROUTE_EXTRA_FS); +DECLARE_MTYPE(BGP_ROUTE_EXTRA_VRFLEAK); DECLARE_MTYPE(BGP_CONN); DECLARE_MTYPE(BGP_STATIC); DECLARE_MTYPE(BGP_ADVERTISE_ATTR); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index e920d5753e..f2d1ee0bf3 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -173,10 +173,11 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, * if they belong to same VRF */ if (!compare && bpi1->attr->nh_type != NEXTHOP_TYPE_BLACKHOLE) { - if (bpi1->extra && bpi1->extra->bgp_orig && bpi2->extra - && bpi2->extra->bgp_orig) { - if (bpi1->extra->bgp_orig->vrf_id - != bpi2->extra->bgp_orig->vrf_id) { + if (bpi1->extra && bpi1->extra->vrfleak && + bpi1->extra->vrfleak->bgp_orig && bpi2->extra && + bpi2->extra->vrfleak && bpi2->extra->vrfleak->bgp_orig) { + if (bpi1->extra->vrfleak->bgp_orig->vrf_id != + bpi2->extra->vrfleak->bgp_orig->vrf_id) { compare = 1; } } diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index da599688ea..ad66720512 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -996,41 +996,6 @@ static void setlabels(struct bgp_path_info *bpi, extra->num_labels = num_labels; } -/* - * make encoded route SIDs match specified encoded sid set - */ -static void setsids(struct bgp_path_info *bpi, - struct in6_addr *sid, - uint32_t num_sids) -{ - uint32_t i; - struct bgp_path_info_extra *extra; - - if (num_sids) - assert(sid); - assert(num_sids <= BGP_MAX_SIDS); - - if (!num_sids) { - if (bpi->extra) - bpi->extra->num_sids = 0; - return; - } - - extra = bgp_path_info_extra_get(bpi); - for (i = 0; i < num_sids; i++) - memcpy(&extra->sid[i].sid, &sid[i], sizeof(struct in6_addr)); - extra->num_sids = num_sids; -} - -static void unsetsids(struct bgp_path_info *bpi) -{ - struct bgp_path_info_extra *extra; - - extra = bgp_path_info_extra_get(bpi); - extra->num_sids = 0; - 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, @@ -1045,8 +1010,8 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi); - if (bpi->extra && bpi->extra->bgp_orig) - bgp_nexthop = bpi->extra->bgp_orig; + if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->bgp_orig) + bgp_nexthop = bpi->extra->vrfleak->bgp_orig; else bgp_nexthop = bgp_orig; @@ -1098,12 +1063,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, struct bgp_path_info *bpi; struct bgp_path_info *new; struct bgp_path_info_extra *extra; - uint32_t num_sids = 0; struct bgp_path_info *parent = source_bpi; - if (new_attr->srv6_l3vpn || new_attr->srv6_vpn) - num_sids = 1; - if (debug) zlog_debug( "%s: entry: leak-to=%s, p=%pBD, type=%d, sub_type=%d", @@ -1132,7 +1093,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, * match parent */ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { - if (bpi->extra && bpi->extra->parent == parent) + if (bpi->extra && bpi->extra->vrfleak && + bpi->extra->vrfleak->parent == parent) break; } @@ -1200,34 +1162,6 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, if (!labelssame) setlabels(bpi, label, num_labels); - /* - * rewrite sid - */ - if (num_sids) { - if (new_attr->srv6_l3vpn) { - setsids(bpi, &new_attr->srv6_l3vpn->sid, - num_sids); - - extra = bgp_path_info_extra_get(bpi); - - extra->sid[0].loc_block_len = - new_attr->srv6_l3vpn->loc_block_len; - extra->sid[0].loc_node_len = - new_attr->srv6_l3vpn->loc_node_len; - extra->sid[0].func_len = - new_attr->srv6_l3vpn->func_len; - extra->sid[0].arg_len = - new_attr->srv6_l3vpn->arg_len; - extra->sid[0].transposition_len = - new_attr->srv6_l3vpn->transposition_len; - extra->sid[0].transposition_offset = - new_attr->srv6_l3vpn - ->transposition_offset; - } else if (new_attr->srv6_vpn) - setsids(bpi, &new_attr->srv6_vpn->sid, - num_sids); - } else - unsetsids(bpi); if (nexthop_self_flag) bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF); @@ -1267,9 +1201,15 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0, to_bgp->peer_self, new_attr, bn); + bgp_path_info_extra_get(new); + if (!new->extra->vrfleak) + new->extra->vrfleak = + XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VRFLEAK, + sizeof(struct bgp_path_info_extra_vrfleak)); + if (source_bpi->peer) { extra = bgp_path_info_extra_get(new); - extra->peer_orig = peer_lock(source_bpi->peer); + extra->vrfleak->peer_orig = peer_lock(source_bpi->peer); } if (nexthop_self_flag) @@ -1278,42 +1218,16 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN)) bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN); - bgp_path_info_extra_get(new); - - /* - * rewrite sid - */ - if (num_sids) { - if (new_attr->srv6_l3vpn) { - setsids(new, &new_attr->srv6_l3vpn->sid, num_sids); - - extra = bgp_path_info_extra_get(new); - - extra->sid[0].loc_block_len = - new_attr->srv6_l3vpn->loc_block_len; - extra->sid[0].loc_node_len = - new_attr->srv6_l3vpn->loc_node_len; - extra->sid[0].func_len = new_attr->srv6_l3vpn->func_len; - extra->sid[0].arg_len = new_attr->srv6_l3vpn->arg_len; - extra->sid[0].transposition_len = - new_attr->srv6_l3vpn->transposition_len; - extra->sid[0].transposition_offset = - new_attr->srv6_l3vpn->transposition_offset; - } else if (new_attr->srv6_vpn) - setsids(new, &new_attr->srv6_vpn->sid, num_sids); - } else - unsetsids(new); - if (num_labels) setlabels(new, label, num_labels); - new->extra->parent = bgp_path_info_lock(parent); + new->extra->vrfleak->parent = bgp_path_info_lock(parent); bgp_dest_lock_node( (struct bgp_dest *)parent->net); if (bgp_orig) - new->extra->bgp_orig = bgp_lock(bgp_orig); + new->extra->vrfleak->bgp_orig = bgp_lock(bgp_orig); if (nexthop_orig) - new->extra->nexthop_orig = *nexthop_orig; + new->extra->vrfleak->nexthop_orig = *nexthop_orig; if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi, source_bpi, new, bgp_orig, p, debug)) @@ -1554,8 +1468,8 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi, /* Check the next-hop reachability. * Get the bgp instance where the bgp_path_info originates. */ - if (pi->extra && pi->extra->bgp_orig) - bgp_nexthop = pi->extra->bgp_orig; + if (pi->extra && pi->extra->vrfleak && pi->extra->vrfleak->bgp_orig) + bgp_nexthop = pi->extra->vrfleak->bgp_orig; else bgp_nexthop = from_bgp; @@ -1986,7 +1900,8 @@ void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */ * match original bpi imported from */ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { - if (bpi->extra && bpi->extra->parent == path_vrf) { + if (bpi->extra && bpi->extra->vrfleak && + bpi->extra->vrfleak->parent == path_vrf) { break; } } @@ -2039,9 +1954,9 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp, bpi->sub_type); if (bpi->sub_type != BGP_ROUTE_IMPORTED) continue; - if (!bpi->extra) + if (!bpi->extra || !bpi->extra->vrfleak) continue; - if ((struct bgp *)bpi->extra->bgp_orig == + if ((struct bgp *)bpi->extra->vrfleak->bgp_orig == from_bgp) { /* delete route */ if (debug) @@ -2055,7 +1970,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp, bgp_path_info_delete(bn, bpi); bgp_process(to_bgp, bn, afi, safi); bgp_mplsvpn_path_nh_label_unlink( - bpi->extra->parent); + bpi->extra->vrfleak->parent); } } } @@ -2162,8 +2077,9 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ */ struct bgp *src_bgp = bgp_lookup_by_rd(path_vpn, prd, afi); - if (path_vpn->extra && path_vpn->extra->bgp_orig) - src_vrf = path_vpn->extra->bgp_orig; + if (path_vpn->extra && path_vpn->extra->vrfleak && + path_vpn->extra->vrfleak->bgp_orig) + src_vrf = path_vpn->extra->vrfleak->bgp_orig; else if (src_bgp) src_vrf = src_bgp; else @@ -2429,9 +2345,8 @@ void vpn_leak_to_vrf_update(struct bgp *from_bgp, /* Loop over VRFs */ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { - - if (!path_vpn->extra - || path_vpn->extra->bgp_orig != bgp) { /* no loop */ + if (!path_vpn->extra || !path_vpn->extra->vrfleak || + path_vpn->extra->vrfleak->bgp_orig != bgp) { /* no loop */ vpn_leak_to_vrf_update_onevrf(bgp, from_bgp, path_vpn, prd); } @@ -2504,9 +2419,9 @@ void vpn_leak_to_vrf_withdraw(struct bgp_path_info *path_vpn) for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { - if (bpi->extra - && (struct bgp_path_info *)bpi->extra->parent - == path_vpn) { + if (bpi->extra && bpi->extra->vrfleak && + (struct bgp_path_info *)bpi->extra->vrfleak->parent == + path_vpn) { break; } } @@ -2540,10 +2455,10 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi) for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { - if (bpi->extra && bpi->extra->bgp_orig != to_bgp && - bpi->extra->parent && - is_pi_family_vpn(bpi->extra->parent)) { - + if (bpi->extra && bpi->extra->vrfleak && + bpi->extra->vrfleak->bgp_orig != to_bgp && + bpi->extra->vrfleak->parent && + is_pi_family_vpn(bpi->extra->vrfleak->parent)) { /* delete route */ bgp_aggregate_decrement(to_bgp, bgp_dest_get_prefix(bn), @@ -2580,9 +2495,8 @@ void vpn_leak_no_retain(struct bgp *to_bgp, struct bgp *vpn_from, afi_t afi) for (bn = bgp_table_top(table); 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 == to_bgp) + if (bpi->extra && bpi->extra->vrfleak && + bpi->extra->vrfleak->bgp_orig == to_bgp) continue; if (bpi->sub_type != BGP_ROUTE_NORMAL) @@ -2627,9 +2541,8 @@ void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *vpn_from, for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { - - if (bpi->extra && - bpi->extra->bgp_orig == to_bgp) + if (bpi->extra && bpi->extra->vrfleak && + bpi->extra->vrfleak->bgp_orig == to_bgp) continue; vpn_leak_to_vrf_update_onevrf(to_bgp, vpn_from, diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index dcde42146c..62748a9e56 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -298,12 +298,11 @@ static inline bool is_route_injectable_into_vpn(struct bgp_path_info *pi) struct bgp_table *table; struct bgp_dest *dest; - if (pi->sub_type != BGP_ROUTE_IMPORTED || - !pi->extra || - !pi->extra->parent) + if (pi->sub_type != BGP_ROUTE_IMPORTED || !pi->extra || + !pi->extra->vrfleak || !pi->extra->vrfleak->parent) return true; - parent_pi = (struct bgp_path_info *)pi->extra->parent; + parent_pi = (struct bgp_path_info *)pi->extra->vrfleak->parent; dest = parent_pi->net; if (!dest) return true; diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 02cfd9c2af..bbc30365c7 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -56,10 +56,11 @@ static int bgp_isvalid_nexthop_for_ebgp(struct bgp_nexthop_cache *bnc, struct bgp_interface *iifp; struct peer *peer; - if (!path->extra || !path->extra->peer_orig) + if (!path->extra || !path->extra->vrfleak || + !path->extra->vrfleak->peer_orig) return false; - peer = path->extra->peer_orig; + peer = path->extra->vrfleak->peer_orig; /* only connected ebgp peers are valid */ if (peer->sort != BGP_PEER_EBGP || peer->ttl != BGP_DEFAULT_TTL || diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 7c2c6f616b..327c6b79fd 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1202,6 +1202,13 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, unsigned long cap_len; uint16_t len; + if (!peer_established(peer)) + return; + + if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) && + !CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) + return; + /* Convert AFI, SAFI to values for packet. */ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); @@ -1272,7 +1279,15 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, case CAPABILITY_CODE_FQDN: case CAPABILITY_CODE_ENHE: case CAPABILITY_CODE_EXT_MESSAGE: + break; case CAPABILITY_CODE_ROLE: + if (peer->local_role != ROLE_UNDEFINED) { + SET_FLAG(peer->cap, PEER_CAP_ROLE_ADV); + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_ROLE); + stream_putc(s, CAPABILITY_CODE_ROLE_LEN); + stream_putc(s, peer->local_role); + } break; default: break; @@ -1787,11 +1802,14 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP6][SAFI_ENCAP]) { - if (IN6_IS_ADDR_UNSPECIFIED(&peer->nexthop.v6_global)) { -#if defined(HAVE_CUMULUS) - zlog_warn("%s: No local IPv6 address, BGP routing may not work", - peer->host); -#endif + if (IN6_IS_ADDR_UNSPECIFIED(&peer->nexthop.v6_global) && + !bm->v6_with_v4_nexthops) { + flog_err(EC_BGP_SND_FAIL, +"%s: No local IPv6 address, and zebra does not support V6 routing with v4 nexthops, BGP routing for V6 will not work", + peer->host); + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); + return BGP_Stop; } } peer->rtt = sockopt_tcp_rtt(peer->fd); @@ -2876,7 +2894,22 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, case CAPABILITY_CODE_FQDN: case CAPABILITY_CODE_ENHE: case CAPABILITY_CODE_EXT_MESSAGE: + break; case CAPABILITY_CODE_ROLE: + SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); + if (hdr->length != CAPABILITY_CODE_ROLE_LEN) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Role: Received invalid length %d", + hdr->length); + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); + return BGP_Stop; + } + uint8_t role; + + memcpy(&role, pnt + 3, sizeof(role)); + + peer->remote_role = role; break; default: flog_warn( diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index bc9ecff7d9..43682de413 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -1667,8 +1667,8 @@ static void bgp_pbr_flush_iprule(struct bgp *bgp, struct bgp_pbr_action *bpa, /* unlink path to bpme */ path = (struct bgp_path_info *)bpr->path; extra = bgp_path_info_extra_get(path); - if (extra->bgp_fs_iprule) - listnode_delete(extra->bgp_fs_iprule, bpr); + if (extra->flowspec && extra->flowspec->bgp_fs_iprule) + listnode_delete(extra->flowspec->bgp_fs_iprule, bpr); bpr->path = NULL; } } @@ -1696,8 +1696,8 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa, /* unlink path to bpme */ path = (struct bgp_path_info *)bpme->path; extra = bgp_path_info_extra_get(path); - if (extra->bgp_fs_pbr) - listnode_delete(extra->bgp_fs_pbr, bpme); + if (extra->flowspec && extra->flowspec->bgp_fs_pbr) + listnode_delete(extra->flowspec->bgp_fs_pbr, bpme); bpme->path = NULL; } } @@ -2342,8 +2342,8 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, struct bgp_path_info_extra *extra = bgp_path_info_extra_get(path); - if (extra && - listnode_lookup_nocheck(extra->bgp_fs_iprule, + if (extra && extra->flowspec && + listnode_lookup_nocheck(extra->flowspec->bgp_fs_iprule, bpr)) { if (BGP_DEBUG(pbr, PBR_ERROR)) zlog_err("%s: entry %p/%p already installed in bgp pbr iprule", @@ -2501,8 +2501,8 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, struct bgp_path_info_extra *extra = bgp_path_info_extra_get(path); - if (extra && - listnode_lookup_nocheck(extra->bgp_fs_pbr, bpme)) { + if (extra && extra->flowspec && + listnode_lookup_nocheck(extra->flowspec->bgp_fs_pbr, bpme)) { if (BGP_DEBUG(pbr, PBR_ERROR)) zlog_err( "%s: entry %p/%p already installed in bgp pbr", diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 5f923c598f..e104aac870 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -188,8 +188,7 @@ static struct bgp_path_info_extra *bgp_path_info_extra_new(void) sizeof(struct bgp_path_info_extra)); new->label[0] = MPLS_INVALID_LABEL; new->num_labels = 0; - new->bgp_fs_pbr = NULL; - new->bgp_fs_iprule = NULL; + new->flowspec = NULL; return new; } @@ -206,8 +205,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) e->damp_info->safi); e->damp_info = NULL; - if (e->parent) { - struct bgp_path_info *bpi = (struct bgp_path_info *)e->parent; + if (e->vrfleak && e->vrfleak->parent) { + struct bgp_path_info *bpi = + (struct bgp_path_info *)e->vrfleak->parent; if (bpi->net) { /* FIXME: since multiple e may have the same e->parent @@ -227,26 +227,34 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) bpi->net = NULL; bgp_path_info_unlock(bpi); } - bgp_path_info_unlock(e->parent); - e->parent = NULL; + bgp_path_info_unlock(e->vrfleak->parent); + e->vrfleak->parent = NULL; } - if (e->bgp_orig) - bgp_unlock(e->bgp_orig); + if (e->vrfleak && e->vrfleak->bgp_orig) + bgp_unlock(e->vrfleak->bgp_orig); - if (e->peer_orig) - peer_unlock(e->peer_orig); + if (e->vrfleak && e->vrfleak->peer_orig) + peer_unlock(e->vrfleak->peer_orig); if (e->aggr_suppressors) list_delete(&e->aggr_suppressors); - if (e->mh_info) - bgp_evpn_path_mh_info_free(e->mh_info); + if (e->evpn && e->evpn->mh_info) + bgp_evpn_path_mh_info_free(e->evpn->mh_info); + + if ((*extra)->flowspec && (*extra)->flowspec->bgp_fs_iprule) + list_delete(&((*extra)->flowspec->bgp_fs_iprule)); + if ((*extra)->flowspec && (*extra)->flowspec->bgp_fs_pbr) + list_delete(&((*extra)->flowspec->bgp_fs_pbr)); + + if (e->evpn) + XFREE(MTYPE_BGP_ROUTE_EXTRA_EVPN, e->evpn); + if (e->flowspec) + XFREE(MTYPE_BGP_ROUTE_EXTRA_FS, e->flowspec); + if (e->vrfleak) + XFREE(MTYPE_BGP_ROUTE_EXTRA_VRFLEAK, e->vrfleak); - if ((*extra)->bgp_fs_iprule) - list_delete(&((*extra)->bgp_fs_iprule)); - if ((*extra)->bgp_fs_pbr) - list_delete(&((*extra)->bgp_fs_pbr)); XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra); } @@ -257,6 +265,10 @@ struct bgp_path_info_extra *bgp_path_info_extra_get(struct bgp_path_info *pi) { if (!pi->extra) pi->extra = bgp_path_info_extra_new(); + if (!pi->extra->evpn && pi->net && pi->net->p.family == AF_EVPN) + pi->extra->evpn = + XCALLOC(MTYPE_BGP_ROUTE_EXTRA_EVPN, + sizeof(struct bgp_path_info_extra_evpn)); return pi->extra; } @@ -570,8 +582,9 @@ struct bgp_path_info *bgp_get_imported_bpi_ultimate(struct bgp_path_info *info) return info; for (bpi_ultimate = info; - bpi_ultimate->extra && bpi_ultimate->extra->parent; - bpi_ultimate = bpi_ultimate->extra->parent) + bpi_ultimate->extra && bpi_ultimate->extra->vrfleak && + bpi_ultimate->extra->vrfleak->parent; + bpi_ultimate = bpi_ultimate->extra->vrfleak->parent) ; return bpi_ultimate; @@ -4674,49 +4687,6 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, bgp_set_valid_label(&extra->label[0]); } - /* Update SRv6 SID */ - if (attr->srv6_l3vpn) { - extra = bgp_path_info_extra_get(pi); - if (sid_diff(&extra->sid[0].sid, - &attr->srv6_l3vpn->sid)) { - sid_copy(&extra->sid[0].sid, - &attr->srv6_l3vpn->sid); - extra->num_sids = 1; - - extra->sid[0].loc_block_len = 0; - extra->sid[0].loc_node_len = 0; - extra->sid[0].func_len = 0; - extra->sid[0].arg_len = 0; - extra->sid[0].transposition_len = 0; - extra->sid[0].transposition_offset = 0; - - if (attr->srv6_l3vpn->loc_block_len != 0) { - extra->sid[0].loc_block_len = - attr->srv6_l3vpn->loc_block_len; - extra->sid[0].loc_node_len = - attr->srv6_l3vpn->loc_node_len; - extra->sid[0].func_len = - attr->srv6_l3vpn->func_len; - extra->sid[0].arg_len = - attr->srv6_l3vpn->arg_len; - extra->sid[0].transposition_len = - attr->srv6_l3vpn - ->transposition_len; - extra->sid[0].transposition_offset = - attr->srv6_l3vpn - ->transposition_offset; - } - } - } else if (attr->srv6_vpn) { - extra = bgp_path_info_extra_get(pi); - if (sid_diff(&extra->sid[0].sid, - &attr->srv6_vpn->sid)) { - sid_copy(&extra->sid[0].sid, - &attr->srv6_vpn->sid); - extra->num_sids = 1; - } - } - #ifdef ENABLE_BGP_VNC if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { @@ -4771,8 +4741,9 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct bgp *bgp_nexthop = bgp; - if (pi->extra && pi->extra->bgp_orig) - bgp_nexthop = pi->extra->bgp_orig; + if (pi->extra && pi->extra->vrfleak && + pi->extra->vrfleak->bgp_orig) + bgp_nexthop = pi->extra->vrfleak->bgp_orig; nh_afi = BGP_ATTR_NH_AFI(afi, pi->attr); @@ -4901,29 +4872,6 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, bgp_set_valid_label(&extra->label[0]); } - /* Update SRv6 SID */ - if (safi == SAFI_MPLS_VPN) { - extra = bgp_path_info_extra_get(new); - if (attr->srv6_l3vpn) { - sid_copy(&extra->sid[0].sid, &attr->srv6_l3vpn->sid); - extra->num_sids = 1; - - extra->sid[0].loc_block_len = - attr->srv6_l3vpn->loc_block_len; - extra->sid[0].loc_node_len = - attr->srv6_l3vpn->loc_node_len; - extra->sid[0].func_len = attr->srv6_l3vpn->func_len; - extra->sid[0].arg_len = attr->srv6_l3vpn->arg_len; - extra->sid[0].transposition_len = - attr->srv6_l3vpn->transposition_len; - extra->sid[0].transposition_offset = - attr->srv6_l3vpn->transposition_offset; - } else if (attr->srv6_vpn) { - sid_copy(&extra->sid[0].sid, &attr->srv6_vpn->sid); - extra->num_sids = 1; - } - } - /* Nexthop reachability check. */ if (((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST || @@ -6145,7 +6093,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, addpath_id = 0; addpath_capable = bgp_addpath_encode_rx(peer, afi, safi); - /* RFC4771 6.3 The NLRI field in the UPDATE message is checked for + /* RFC4271 6.3 The NLRI field in the UPDATE message is checked for syntactic validity. If the field is syntactically incorrect, then the Error Subcode is set to Invalid Network Field. */ for (; pnt < lim; pnt += psize) { @@ -9167,26 +9115,27 @@ void route_vty_out(struct vty *vty, const struct prefix *p, * If vrf id of nexthop is different from that of prefix, * set up printable string to append */ - if (path->extra && path->extra->bgp_orig) { + if (path->extra && path->extra->vrfleak && + path->extra->vrfleak->bgp_orig) { const char *self = ""; if (nexthop_self) self = "<"; nexthop_othervrf = true; - nexthop_vrfid = path->extra->bgp_orig->vrf_id; + nexthop_vrfid = path->extra->vrfleak->bgp_orig->vrf_id; - if (path->extra->bgp_orig->vrf_id == VRF_UNKNOWN) + if (path->extra->vrfleak->bgp_orig->vrf_id == VRF_UNKNOWN) snprintf(vrf_id_str, sizeof(vrf_id_str), "@%s%s", VRFID_NONE_STR, self); else snprintf(vrf_id_str, sizeof(vrf_id_str), "@%u%s", - path->extra->bgp_orig->vrf_id, self); + path->extra->vrfleak->bgp_orig->vrf_id, self); - if (path->extra->bgp_orig->inst_type - != BGP_INSTANCE_TYPE_DEFAULT) + if (path->extra->vrfleak->bgp_orig->inst_type != + BGP_INSTANCE_TYPE_DEFAULT) - nexthop_vrfname = path->extra->bgp_orig->name; + nexthop_vrfname = path->extra->vrfleak->bgp_orig->name; } else { const char *self = ""; @@ -10301,11 +10250,13 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, "\n"); - if (path->extra && path->extra->parent && !json_paths) { + if (path->extra && path->extra->vrfleak && + path->extra->vrfleak->parent && !json_paths) { struct bgp_path_info *parent_ri; struct bgp_dest *dest, *pdest; - parent_ri = (struct bgp_path_info *)path->extra->parent; + parent_ri = + (struct bgp_path_info *)path->extra->vrfleak->parent; dest = parent_ri->net; if (dest && dest->pdest) { pdest = dest->pdest; @@ -10608,17 +10559,18 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, /* * Note when vrfid of nexthop is different from that of prefix */ - if (path->extra && path->extra->bgp_orig) { - vrf_id_t nexthop_vrfid = path->extra->bgp_orig->vrf_id; + if (path->extra && path->extra->vrfleak && + path->extra->vrfleak->bgp_orig) { + vrf_id_t nexthop_vrfid = path->extra->vrfleak->bgp_orig->vrf_id; if (json_paths) { const char *vn; - if (path->extra->bgp_orig->inst_type - == BGP_INSTANCE_TYPE_DEFAULT) + if (path->extra->vrfleak->bgp_orig->inst_type == + BGP_INSTANCE_TYPE_DEFAULT) vn = VRF_DEFAULT_NAME; else - vn = path->extra->bgp_orig->name; + vn = path->extra->vrfleak->bgp_orig->name; json_object_string_add(json_path, "nhVrfName", vn); @@ -11013,13 +10965,16 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } /* Remote SID */ - if (path->extra && path->extra->num_sids > 0 && safi != SAFI_EVPN) { + if ((path->attr->srv6_l3vpn || path->attr->srv6_vpn) && + safi != SAFI_EVPN) { + struct in6_addr *sid_tmp = + path->attr->srv6_l3vpn ? (&path->attr->srv6_l3vpn->sid) + : (&path->attr->srv6_vpn->sid); if (json_paths) json_object_string_addf(json_path, "remoteSid", "%pI6", - &path->extra->sid[0].sid); + sid_tmp); else - vty_out(vty, " Remote SID: %pI6\n", - &path->extra->sid[0].sid); + vty_out(vty, " Remote SID: %pI6\n", sid_tmp); } /* Label Index */ diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 265587c424..0a6f535b22 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -145,6 +145,54 @@ struct bgp_sid_info { uint8_t transposition_offset; }; +/* new structure for EVPN */ +struct bgp_path_info_extra_evpn { +#define BGP_EVPN_MACIP_TYPE_SVI_IP (1 << 0) + /* af specific flags */ + uint16_t af_flags; + union { + struct ethaddr mac; /* MAC set here for VNI IP table */ + struct ipaddr ip; /* IP set here for VNI MAC table */ + } vni_info; + /* Destination Ethernet Segment links for EVPN MH */ + struct bgp_path_mh_info *mh_info; +}; + +/* new structure for flowspec*/ +struct bgp_path_info_extra_fs { + /* presence of FS pbr firewall based entry */ + struct list *bgp_fs_pbr; + /* presence of FS pbr iprule based entry */ + struct list *bgp_fs_iprule; +}; + +/* new structure for vrfleak*/ +struct bgp_path_info_extra_vrfleak { + void *parent; /* parent from global table */ + /* + * Original bgp instance for imported routes. Needed for: + * 1. Find all routes from a specific vrf for deletion + * 2. vrf context of original nexthop + * + * Store pointer to bgp instance rather than bgp->vrf_id because + * bgp->vrf_id is not always valid (or may change?). + * + * Set to NULL if route is not imported from another bgp instance. + */ + struct bgp *bgp_orig; + /* + * Original bgp session to know if the session is a + * connected EBGP session or not + */ + struct peer *peer_orig; + /* + * Nexthop in context of original bgp instance. Needed + * for label resolution of core mpls routes exported to a vrf. + * Set nexthop_orig.family to 0 if not valid. + */ + struct prefix nexthop_orig; +}; + /* Ancillary information to struct bgp_path_info, * used for uncommonly used data (aggregation, MPLS, etc.) * and lazily allocated to save memory. @@ -163,13 +211,8 @@ struct bgp_path_info_extra { mpls_label_t label[BGP_MAX_LABELS]; uint32_t num_labels; - /* af specific flags */ - uint16_t af_flags; -#define BGP_EVPN_MACIP_TYPE_SVI_IP (1 << 0) - - /* SRv6 SID(s) for SRv6-VPN */ - struct bgp_sid_info sid[BGP_MAX_SIDS]; - uint32_t num_sids; + /*For EVPN*/ + struct bgp_path_info_extra_evpn *evpn; #ifdef ENABLE_BGP_VNC union { @@ -200,50 +243,11 @@ struct bgp_path_info_extra { } vnc; #endif - /* - * For imported routes into a VNI (or VRF) - */ - void *parent; /* parent from global table */ - union { - struct ethaddr mac; /* MAC set here for VNI IP table */ - struct ipaddr ip; /* IP set here for VNI MAC table */ - } vni_info; - - /* - * Some tunnelish parameters follow. Maybe consolidate into an - * internal tunnel structure? - */ - - /* - * Original bgp instance for imported routes. Needed for: - * 1. Find all routes from a specific vrf for deletion - * 2. vrf context of original nexthop - * - * Store pointer to bgp instance rather than bgp->vrf_id because - * bgp->vrf_id is not always valid (or may change?). - * - * Set to NULL if route is not imported from another bgp instance. - */ - struct bgp *bgp_orig; - - /* - * Original bgp session to know if the session is a - * connected EBGP session or not - */ - struct peer *peer_orig; + /* For flowspec*/ + struct bgp_path_info_extra_fs *flowspec; - /* - * Nexthop in context of original bgp instance. Needed - * for label resolution of core mpls routes exported to a vrf. - * Set nexthop_orig.family to 0 if not valid. - */ - struct prefix nexthop_orig; - /* presence of FS pbr firewall based entry */ - struct list *bgp_fs_pbr; - /* presence of FS pbr iprule based entry */ - struct list *bgp_fs_iprule; - /* Destination Ethernet Segment links for EVPN MH */ - struct bgp_path_mh_info *mh_info; + /* For vrf leaking*/ + struct bgp_path_info_extra_vrfleak *vrfleak; }; struct bgp_mplsvpn_label_nh { diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index b7ac976e23..1c99495e6c 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1313,12 +1313,13 @@ route_match_vrl_source_vrf(void *rule, const struct prefix *prefix, if (strncmp(vrf_name, "n/a", VRF_NAMSIZ) == 0) return RMAP_NOMATCH; - if (path->extra == NULL || path->extra->bgp_orig == NULL) + if (path->extra == NULL || path->extra->vrfleak == NULL || + path->extra->vrfleak->bgp_orig == NULL) return RMAP_NOMATCH; - if (strncmp(vrf_name, vrf_id_to_name(path->extra->bgp_orig->vrf_id), - VRF_NAMSIZ) - == 0) + if (strncmp(vrf_name, + vrf_id_to_name(path->extra->vrfleak->bgp_orig->vrf_id), + VRF_NAMSIZ) == 0) return RMAP_MATCH; return RMAP_NOMATCH; @@ -2410,11 +2411,16 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object) as_t configured_asn; char *buf; char src_asn[ASN_STRING_MAX_SIZE]; + char *acl_list_name = NULL; + uint32_t acl_list_name_len = 0; + char *buf_acl_name = NULL; + static const char asp_acl[] = "as-path-access-list"; + struct as_list *aspath_acl = NULL; if (path->peer->sort != BGP_PEER_EBGP) { zlog_warn( "`set as-path replace` is supported only for EBGP peers"); - return RMAP_NOOP; + goto end_ko; } buf = strchr(replace, ' '); @@ -2422,6 +2428,46 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object) configured_asn = path->peer->change_local_as ? path->peer->change_local_as : path->peer->local_as; + } else if (!strncmp(replace, asp_acl, strlen(asp_acl))) { + /* its as-path-acl-list command get the access list name */ + while (*buf == ' ') + buf++; + buf_acl_name = buf; + buf = strchr(buf_acl_name, ' '); + if (buf) + acl_list_name_len = buf - buf_acl_name; + else + acl_list_name_len = strlen(buf_acl_name); + + buf_acl_name[acl_list_name_len] = 0; + /* get the acl-list */ + aspath_acl = as_list_lookup(buf_acl_name); + if (!aspath_acl) { + zlog_warn("`set as-path replace`, invalid as-path-access-list name: %s", + buf_acl_name); + goto end_ko; + } + acl_list_name = XSTRDUP(MTYPE_TMP, buf_acl_name); + buf_acl_name[acl_list_name_len] = ' '; + + if (!buf) { + configured_asn = path->peer->change_local_as + ? path->peer->change_local_as + : path->peer->local_as; + } else { + while (*buf == ' ') + buf++; + /* get the configured asn */ + if (!asn_str2asn(buf, &configured_asn)) { + zlog_warn( + "`set as-path replace`, invalid configured AS %s", + buf); + goto end_ko; + } + } + + replace = buf; + } else { memcpy(src_asn, replace, (size_t)(buf - replace)); src_asn[(size_t)(buf - replace)] = '\0'; @@ -2431,13 +2477,14 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object) zlog_warn( "`set as-path replace`, invalid configured AS %s", buf); - return RMAP_NOOP; + goto end_ko; } } - if (!strmatch(replace, "any") && !asn_str2asn(replace, &replace_asn)) { + if (replace && !strmatch(replace, "any") && + !asn_str2asn(replace, &replace_asn)) { zlog_warn("`set as-path replace`, invalid AS %s", replace); - return RMAP_NOOP; + goto end_ko; } if (path->attr->aspath->refcnt) @@ -2445,16 +2492,29 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object) else aspath_new = path->attr->aspath; - if (strmatch(replace, "any")) { + if (aspath_acl) { + path->attr->aspath = aspath_replace_regex_asn(aspath_new, + aspath_acl, + configured_asn); + } else if (strmatch(replace, "any")) { path->attr->aspath = aspath_replace_all_asn(aspath_new, configured_asn); - } else + } else { path->attr->aspath = aspath_replace_specific_asn( aspath_new, replace_asn, configured_asn); - + } aspath_free(aspath_new); + + if (acl_list_name) + XFREE(MTYPE_TMP, acl_list_name); return RMAP_OKAY; + +end_ko: + if (acl_list_name) + XFREE(MTYPE_TMP, acl_list_name); + return RMAP_NOOP; + } static const struct route_map_rule_cmd route_set_aspath_replace_cmd = { @@ -6087,6 +6147,61 @@ DEFPY_YANG(no_set_aspath_replace_asn, no_set_aspath_replace_asn_cmd, return nb_cli_apply_changes(vty, NULL); } +DEFPY_YANG( + set_aspath_replace_access_list, set_aspath_replace_access_list_cmd, + "set as-path replace as-path-access-list AS_PATH_FILTER_NAME$aspath_filter_name [<ASNUM>$configured_asn]", + SET_STR + "Transform BGP AS-path attribute\n" + "Replace AS number to local or configured AS number\n" + "Specify an as path access list name\n" + "AS path access list name\n" + "Define the configured AS number\n") +{ + char *str; + const char *xpath = + "./set-action[action='frr-bgp-route-map:as-path-replace']"; + char xpath_value[XPATH_MAXLEN]; + as_t as_configured_value; + char replace_value[ASN_STRING_MAX_SIZE * 2]; + + if (configured_asn_str && + !asn_str2asn(configured_asn_str, &as_configured_value)) { + vty_out(vty, "%% Invalid AS configured value %s\n", + configured_asn_str); + return CMD_WARNING_CONFIG_FAILED; + } + + str = argv_concat(argv, argc, 3); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(replace_value, sizeof(replace_value), "%s %s", aspath_filter_name, str); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:replace-as-path", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_set_aspath_replace_access_list, no_set_aspath_replace_access_list_cmd, + "no set as-path replace as-path-access-list [AS_PATH_FILTER_NAME] [<ASNUM>$configured_asn]", + NO_STR + SET_STR + "Transform BGP AS_PATH attribute\n" + "Replace AS number to local or configured AS number\n" + "Specify an as path access list name\n" + "AS path access list name\n" + "Define the configured AS number\n") +{ + const char *xpath = + "./set-action[action='frr-bgp-route-map:as-path-replace']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + DEFUN_YANG (no_set_aspath_prepend, no_set_aspath_prepend_cmd, "no set as-path prepend [ASNUM]", @@ -7792,12 +7907,14 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &set_aspath_exclude_all_cmd); install_element(RMAP_NODE, &set_aspath_exclude_access_list_cmd); install_element(RMAP_NODE, &set_aspath_replace_asn_cmd); + install_element(RMAP_NODE, &set_aspath_replace_access_list_cmd); install_element(RMAP_NODE, &no_set_aspath_prepend_cmd); install_element(RMAP_NODE, &no_set_aspath_prepend_lastas_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_all_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_access_list_cmd); install_element(RMAP_NODE, &no_set_aspath_replace_asn_cmd); + install_element(RMAP_NODE, &no_set_aspath_replace_access_list_cmd); install_element(RMAP_NODE, &set_origin_cmd); install_element(RMAP_NODE, &no_set_origin_cmd); install_element(RMAP_NODE, &set_atomic_aggregate_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 591e0c3969..573abf0cda 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5738,14 +5738,10 @@ DEFPY(neighbor_capability_software_version, ret = peer_flag_set_vty(vty, neighbor, PEER_FLAG_CAPABILITY_SOFT_VERSION); - if (peer_established(peer)) { - if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) && - CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) - bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, - CAPABILITY_CODE_SOFT_VERSION, - no ? CAPABILITY_ACTION_UNSET - : CAPABILITY_ACTION_SET); - } + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_SOFT_VERSION, + no ? CAPABILITY_ACTION_UNSET + : CAPABILITY_ACTION_SET); return ret; } @@ -6786,14 +6782,9 @@ static uint8_t get_role_by_name(const char *role_str) return ROLE_UNDEFINED; } -static int peer_role_set_vty(struct vty *vty, const char *ip_str, +static int peer_role_set_vty(struct vty *vty, struct peer *peer, const char *role_str, bool strict_mode) { - struct peer *peer; - - peer = peer_and_group_lookup_vty(vty, ip_str); - if (!peer) - return CMD_WARNING_CONFIG_FAILED; uint8_t role = get_role_by_name(role_str); if (role == ROLE_UNDEFINED) @@ -6801,50 +6792,56 @@ static int peer_role_set_vty(struct vty *vty, const char *ip_str, return bgp_vty_return(vty, peer_role_set(peer, role, strict_mode)); } -static int peer_role_unset_vty(struct vty *vty, const char *ip_str) -{ - struct peer *peer; - - peer = peer_and_group_lookup_vty(vty, ip_str); - if (!peer) - return CMD_WARNING_CONFIG_FAILED; - return bgp_vty_return(vty, peer_role_unset(peer)); -} - DEFPY(neighbor_role, neighbor_role_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> local-role <provider|rs-server|rs-client|customer|peer>", + "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor local-role <provider|rs-server|rs-client|customer|peer>$role", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Set session role\n" ROLE_STR) { - int idx_peer = 1; - int idx_role = 3; + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; - return peer_role_set_vty(vty, argv[idx_peer]->arg, argv[idx_role]->arg, - false); + ret = peer_role_set_vty(vty, peer, role, false); + + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, CAPABILITY_CODE_ROLE, + CAPABILITY_ACTION_SET); + + return ret; } DEFPY(neighbor_role_strict, neighbor_role_strict_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> local-role <provider|rs-server|rs-client|customer|peer> strict-mode", + "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor local-role <provider|rs-server|rs-client|customer|peer>$role strict-mode", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Set session role\n" ROLE_STR "Use additional restriction on peer\n") { - int idx_peer = 1; - int idx_role = 3; + int ret; + struct peer *peer; - return peer_role_set_vty(vty, argv[idx_peer]->arg, argv[idx_role]->arg, - true); + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + ret = peer_role_set_vty(vty, peer, role, true); + + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, CAPABILITY_CODE_ROLE, + CAPABILITY_ACTION_SET); + + return ret; } DEFPY(no_neighbor_role, no_neighbor_role_cmd, - "no neighbor <A.B.C.D|X:X::X:X|WORD> local-role <provider|rs-server|rs-client|customer|peer> [strict-mode]", + "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor local-role <provider|rs-server|rs-client|customer|peer> [strict-mode]", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 @@ -6852,9 +6849,19 @@ DEFPY(no_neighbor_role, ROLE_STR "Use additional restriction on peer\n") { - int idx_peer = 2; + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + ret = bgp_vty_return(vty, peer_role_unset(peer)); - return peer_role_unset_vty(vty, argv[idx_peer]->arg); + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, CAPABILITY_CODE_ROLE, + CAPABILITY_ACTION_UNSET); + + return ret; } /* disable-connected-check */ @@ -10971,6 +10978,29 @@ DEFUN (show_bgp_memory, memstrbuf, sizeof(memstrbuf), count * sizeof(struct bgp_path_info_extra))); + count = mtype_stats_alloc(MTYPE_BGP_ROUTE_EXTRA_EVPN); + if (count) + vty_out(vty, "%ld BGP extra info for EVPN, using %s of memory\n", + count, + mtype_memstr(memstrbuf, sizeof(memstrbuf), + count * sizeof(struct bgp_path_info_extra_evpn))); + + count = mtype_stats_alloc(MTYPE_BGP_ROUTE_EXTRA_FS); + if (count) + vty_out(vty, + "%ld BGP extra info for flowspec, using %s of memory\n", + count, + mtype_memstr(memstrbuf, sizeof(memstrbuf), + count * sizeof(struct bgp_path_info_extra_fs))); + + count = mtype_stats_alloc(MTYPE_BGP_ROUTE_EXTRA_VRFLEAK); + if (count) + vty_out(vty, + "%ld BGP extra info for vrf leaking, using %s of memory\n", + count, + mtype_memstr(memstrbuf, sizeof(memstrbuf), + count * sizeof(struct bgp_path_info_extra_vrfleak))); + if ((count = mtype_stats_alloc(MTYPE_BGP_STATIC))) vty_out(vty, "%ld Static routes, using %s of memory\n", count, mtype_memstr(memstrbuf, sizeof(memstrbuf), diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index becd99167f..ea7168f749 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1308,7 +1308,6 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, struct bgp_path_info local_info; struct bgp_path_info *mpinfo_cp = &local_info; route_tag_t tag; - struct bgp_sid_info *sid_info; mpls_label_t *labels; uint32_t num_labels = 0; mpls_label_t nh_label; @@ -1348,7 +1347,8 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, /* * vrf leaking support (will have only one nexthop) */ - if (info->extra && info->extra->bgp_orig) + if (info->extra && info->extra->vrfleak && + info->extra->vrfleak->bgp_orig) nh_othervrf = 1; /* Make Zebra API structure. */ @@ -1364,8 +1364,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, && info->sub_type == BGP_ROUTE_IMPORTED) { /* Obtain peer from parent */ - if (info->extra && info->extra->parent) - peer = ((struct bgp_path_info *)(info->extra->parent)) + if (info->extra && info->extra->vrfleak && + info->extra->vrfleak->parent) + peer = ((struct bgp_path_info *)(info->extra->vrfleak + ->parent)) ->peer; } @@ -1553,15 +1555,21 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, api_nh->weight = nh_weight; - if (mpinfo->extra && !is_evpn && - bgp_is_valid_label(&labels[0]) && - !sid_zero(&mpinfo->extra->sid[0].sid)) { - sid_info = &mpinfo->extra->sid[0]; - - memcpy(&api_nh->seg6_segs, &sid_info->sid, + if (((mpinfo->attr->srv6_l3vpn && + !sid_zero(&mpinfo->attr->srv6_l3vpn->sid)) || + (mpinfo->attr->srv6_vpn && + !sid_zero(&mpinfo->attr->srv6_vpn->sid))) && + !is_evpn && bgp_is_valid_label(&labels[0])) { + struct in6_addr *sid_tmp = + mpinfo->attr->srv6_l3vpn + ? (&mpinfo->attr->srv6_l3vpn->sid) + : (&mpinfo->attr->srv6_vpn->sid); + + memcpy(&api_nh->seg6_segs, sid_tmp, sizeof(api_nh->seg6_segs)); - if (sid_info->transposition_len != 0) { + if (mpinfo->attr->srv6_l3vpn && + mpinfo->attr->srv6_l3vpn->transposition_len != 0) { mpls_lse_decode(labels[0], &nh_label, &ttl, &exp, &bos); @@ -1573,8 +1581,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, } transpose_sid(&api_nh->seg6_segs, nh_label, - sid_info->transposition_offset, - sid_info->transposition_len); + mpinfo->attr->srv6_l3vpn + ->transposition_offset, + mpinfo->attr->srv6_l3vpn + ->transposition_len); } SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6); @@ -2436,8 +2446,14 @@ static int rule_notify_owner(ZAPI_CALLBACK_ARGS) /* link bgp_info to bgp_pbr */ path = (struct bgp_path_info *)bgp_pbr->path; extra = bgp_path_info_extra_get(path); - listnode_add_force(&extra->bgp_fs_iprule, - bgp_pbr); + if (!extra->flowspec) { + extra->flowspec = + XCALLOC(MTYPE_BGP_ROUTE_EXTRA_FS, + sizeof(struct bgp_path_info_extra_fs)); + extra->flowspec->bgp_fs_iprule = NULL; + extra->flowspec->bgp_fs_pbr = NULL; + } + listnode_add_force(&extra->flowspec->bgp_fs_iprule, bgp_pbr); } if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("%s: Received RULE_INSTALLED", __func__); @@ -2539,7 +2555,14 @@ static int ipset_entry_notify_owner(ZAPI_CALLBACK_ARGS) /* link bgp_path_info to bpme */ path = (struct bgp_path_info *)bgp_pbime->path; extra = bgp_path_info_extra_get(path); - listnode_add_force(&extra->bgp_fs_pbr, bgp_pbime); + if (!extra->flowspec) { + extra->flowspec = + XCALLOC(MTYPE_BGP_ROUTE_EXTRA_FS, + sizeof(struct bgp_path_info_extra_fs)); + extra->flowspec->bgp_fs_iprule = NULL; + extra->flowspec->bgp_fs_pbr = NULL; + } + listnode_add_force(&extra->flowspec->bgp_fs_pbr, bgp_pbime); } break; case ZAPI_IPSET_ENTRY_FAIL_REMOVE: @@ -3455,6 +3478,11 @@ static bool bgp_zebra_label_manager_connect(void) return true; } +static void bgp_zebra_capabilities(struct zclient_capabilities *cap) +{ + bm->v6_with_v4_nexthops = cap->v6_with_v4_nexthop; +} + void bgp_zebra_init(struct event_loop *master, unsigned short instance) { struct zclient_options options = zclient_options_default; @@ -3470,6 +3498,7 @@ void bgp_zebra_init(struct event_loop *master, unsigned short instance) array_size(bgp_handlers)); zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs); zclient->zebra_connected = bgp_zebra_connected; + zclient->zebra_capabilities = bgp_zebra_capabilities; zclient->instance = instance; /* Initialize special zclient for synchronous message exchanges. */ diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index a0f7819460..ed2d5e669d 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -10,9 +10,10 @@ /* Macro to update bgp_original based on bpg_path_info */ #define BGP_ORIGINAL_UPDATE(_bgp_orig, _mpinfo, _bgp) \ - ((_mpinfo->extra && _mpinfo->extra->bgp_orig \ - && _mpinfo->sub_type == BGP_ROUTE_IMPORTED) \ - ? (_bgp_orig = _mpinfo->extra->bgp_orig) \ + ((_mpinfo->extra && _mpinfo->extra->vrfleak && \ + _mpinfo->extra->vrfleak->bgp_orig && \ + _mpinfo->sub_type == BGP_ROUTE_IMPORTED) \ + ? (_bgp_orig = _mpinfo->extra->vrfleak->bgp_orig) \ : (_bgp_orig = _bgp)) /* Default weight for next hop, if doing weighted ECMP. */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index b72e75d12e..aaf1f41c4b 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4444,8 +4444,8 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none}, {PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE, 0, peer_change_none}, {PEER_FLAG_EXTENDED_OPT_PARAMS, 0, peer_change_reset}, - {PEER_FLAG_ROLE_STRICT_MODE, 0, peer_change_reset}, - {PEER_FLAG_ROLE, 0, peer_change_reset}, + {PEER_FLAG_ROLE_STRICT_MODE, 0, peer_change_none}, + {PEER_FLAG_ROLE, 0, peer_change_none}, {PEER_FLAG_PORT, 0, peer_change_reset}, {PEER_FLAG_AIGP, 0, peer_change_none}, {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none}, @@ -5167,7 +5167,6 @@ int peer_role_set(struct peer *peer, uint8_t role, bool strict_mode) else UNSET_FLAG(peer->flags, PEER_FLAG_ROLE_STRICT_MODE); - bgp_session_reset(peer); } return CMD_SUCCESS; @@ -5212,7 +5211,6 @@ int peer_role_set(struct peer *peer, uint8_t role, bool strict_mode) UNSET_FLAG(member->flags, PEER_FLAG_ROLE_STRICT_MODE); } - bgp_session_reset(member); } } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 5e467bb873..67ee8aa138 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -168,6 +168,8 @@ struct bgp_master { struct event *t_bgp_sync_label_manager; struct event *t_bgp_start_label_manager; + bool v6_with_v4_nexthops; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bgp_master); diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 29698846c3..252b6d632a 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -420,15 +420,20 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p, vty_out(vty, " label=%u", decode_label(&bpi->extra->label[0])); - if (bpi->extra->num_sids) { - vty_out(vty, " sid=%pI6", &bpi->extra->sid[0].sid); - - if (bpi->extra->sid[0].loc_block_len != 0) { + if (bpi->attr->srv6_l3vpn || bpi->attr->srv6_vpn) { + struct in6_addr *sid_tmp = + bpi->attr->srv6_l3vpn + ? (&bpi->attr->srv6_l3vpn->sid) + : (&bpi->attr->srv6_vpn->sid); + vty_out(vty, " sid=%pI6", sid_tmp); + + if (bpi->attr->srv6_l3vpn && + bpi->attr->srv6_l3vpn->loc_block_len != 0) { vty_out(vty, " sid_structure=[%d,%d,%d,%d]", - bpi->extra->sid[0].loc_block_len, - bpi->extra->sid[0].loc_node_len, - bpi->extra->sid[0].func_len, - bpi->extra->sid[0].arg_len); + bpi->attr->srv6_l3vpn->loc_block_len, + bpi->attr->srv6_l3vpn->loc_node_len, + bpi->attr->srv6_l3vpn->func_len, + bpi->attr->srv6_l3vpn->arg_len); } } } diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index ad8f913355..651aa36d0e 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -86,6 +86,15 @@ be specified (:ref:`common-invocation-options`). be done to see if this is helping or not at the scale you are running at. +.. option:: --v6-with-v4-nexthops + + Allow BGP to peer in the V6 afi, when the interface only has v4 addresses. + This allows bgp to install the v6 routes with a v6 nexthop that has the + v4 address encoded in the nexthop. Zebra's equivalent option currently + overrides the bgp setting. This setting is only really usable when + the operator has turned off communication to zebra and is running bgpd + as a complete standalone process. + LABEL MANAGER ------------- @@ -2133,6 +2142,14 @@ Using AS Path in Route Map ``any`` replaces each AS number in the AS-PATH with either the local AS number or the configured AS number. +.. clicmd:: set as-path replace as-path-access-list WORD [<ASN>] + + Replace some AS numbers from the AS_PATH of the BGP path's NLRI. Substituted + AS numbers are conformant with the regex defined in as-path access-list + WORD. Changed AS numbers are replaced either by the local AS number or the + configured AS number. + The no form of this command removes this set operation from the route-map. + .. clicmd:: set as-path exclude all Remove all AS numbers from the AS_PATH of the BGP path's NLRI. The no form of diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index d7e768b710..32de3e908f 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -87,6 +87,13 @@ Besides the common invocation options (:ref:`common-invocation-options`), the Allow zebra to modify the default receive buffer size to SIZE in bytes. Under \*BSD only the -s option is available. +.. option:: --v6-with-v4-nexthops + + Signal to zebra that v6 routes with v4 nexthops are accepted + by the underlying dataplane. This will be communicated to + the upper level daemons that can install v6 routes with v4 + nexthops. + .. _interface-commands: Configuration Addresses behaviour diff --git a/lib/bitfield.h b/lib/bitfield.h index c4e2cbe4e1..cc8c311416 100644 --- a/lib/bitfield.h +++ b/lib/bitfield.h @@ -114,7 +114,8 @@ DECLARE_MTYPE(BITFIELD); (v).n += ((v).data[w] == WORD_MAX); \ if ((v).n == (v).m) { \ (v).m = (v).m + 1; \ - (v).data = realloc((v).data, (v).m * sizeof(word_t)); \ + (v).data = XREALLOC(MTYPE_BITFIELD, (v).data, \ + (v).m * sizeof(word_t)); \ } \ } while (0) @@ -188,7 +189,8 @@ bf_find_next_clear_bit_wrap(bitfield_t *v, word_t start_index, word_t max_index) * will allocate additional space. */ v->m += 1; - v->data = (word_t *)realloc(v->data, v->m * sizeof(word_t)); + v->data = (word_t *)XREALLOC(MTYPE_BITFIELD, v->data, + v->m * sizeof(word_t)); v->data[v->m - 1] = 0; return v->m * WORD_SIZE; } diff --git a/lib/command.c b/lib/command.c index 8025ab534f..affb551b45 100644 --- a/lib/command.c +++ b/lib/command.c @@ -903,8 +903,7 @@ enum node_type node_parent(enum node_type node) } /* Execute command by argument vline vector. */ -static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter, - struct vty *vty, +static int cmd_execute_command_real(vector vline, struct vty *vty, const struct cmd_element **cmd, unsigned int up_level) { @@ -1041,8 +1040,7 @@ int cmd_execute_command(vector vline, struct vty *vty, vector_set_index(shifted_vline, index - 1, vector_lookup(vline, index)); - ret = cmd_execute_command_real(shifted_vline, FILTER_RELAXED, - vty, cmd, 0); + ret = cmd_execute_command_real(shifted_vline, vty, cmd, 0); vector_free(shifted_vline); vty->node = onode; @@ -1051,7 +1049,7 @@ int cmd_execute_command(vector vline, struct vty *vty, } saved_ret = ret = - cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd, 0); + cmd_execute_command_real(vline, vty, cmd, 0); if (vtysh) return saved_ret; @@ -1069,8 +1067,7 @@ int cmd_execute_command(vector vline, struct vty *vty, if (vty->xpath_index > 0 && !cnode->no_xpath) vty->xpath_index--; - ret = cmd_execute_command_real(vline, FILTER_RELAXED, - vty, cmd, 0); + ret = cmd_execute_command_real(vline, vty, cmd, 0); if (ret == CMD_SUCCESS || ret == CMD_WARNING || ret == CMD_ERR_AMBIGUOUS || ret == CMD_ERR_INCOMPLETE || ret == CMD_NOT_MY_INSTANCE @@ -1102,7 +1099,7 @@ int cmd_execute_command(vector vline, struct vty *vty, int cmd_execute_command_strict(vector vline, struct vty *vty, const struct cmd_element **cmd) { - return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd, 0); + return cmd_execute_command_real(vline, vty, cmd, 0); } /* @@ -1274,8 +1271,7 @@ int command_config_read_one_line(struct vty *vty, && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED && ret != CMD_NO_LEVEL_UP) - ret = cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd, - ++up_level); + ret = cmd_execute_command_real(vline, vty, cmd, ++up_level); if (ret == CMD_NO_LEVEL_UP) ret = CMD_ERR_NO_MATCH; diff --git a/lib/command_match.h b/lib/command_match.h index db2a8535e0..3e7a549e1d 100644 --- a/lib/command_match.h +++ b/lib/command_match.h @@ -17,11 +17,6 @@ extern "C" { #endif -/* These definitions exist in command.c in the current engine but should be - * relocated here in the new engine - */ -enum cmd_filter_type { FILTER_RELAXED, FILTER_STRICT }; - /* matcher result value */ enum matcher_rv { MATCHER_NO_MATCH, diff --git a/lib/zclient.c b/lib/zclient.c index c36bcc6e2e..294a78feb0 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -3876,6 +3876,7 @@ static int zclient_capability_decode(ZAPI_CALLBACK_ARGS) cap.mpls_enabled = !!mpls_enabled; STREAM_GETL(s, cap.ecmp); STREAM_GETC(s, cap.role); + STREAM_GETC(s, cap.v6_with_v4_nexthop); if (zclient->zebra_capabilities) (*zclient->zebra_capabilities)(&cap); diff --git a/lib/zclient.h b/lib/zclient.h index 316dd4cd68..42c5a5fdac 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -274,6 +274,7 @@ struct zclient_capabilities { uint32_t ecmp; bool mpls_enabled; enum mlag_role role; + bool v6_with_v4_nexthop; }; /* Graceful Restart Capabilities message */ diff --git a/ospfd/ospf_ti_lfa.c b/ospfd/ospf_ti_lfa.c index 07fc503947..f9bc2b4dd6 100644 --- a/ospfd/ospf_ti_lfa.c +++ b/ospfd/ospf_ti_lfa.c @@ -64,6 +64,7 @@ ospf_ti_lfa_find_p_node(struct vertex *pc_node, struct p_space *p_space, struct vertex_parent *pc_vertex_parent; curr_node = listnode_lookup(q_space->pc_path, pc_node); + assert(curr_node); pc_node_parent = listgetdata(curr_node->next); q_space->p_node_info->type = OSPF_TI_LFA_UNDEFINED_NODE; @@ -105,6 +106,7 @@ static void ospf_ti_lfa_find_q_node(struct vertex *pc_node, struct vertex_parent *pc_vertex_parent; curr_node = listnode_lookup(q_space->pc_path, pc_node); + assert(curr_node); next_node = curr_node->next; pc_node_parent = listgetdata(next_node); pc_vertex_parent = @@ -219,7 +221,7 @@ static struct list *ospf_ti_lfa_cut_out_pc_path(struct list *pc_vertex_list, current_listnode = listnode_lookup(pc_path, current_vertex); /* Note that the post-convergence paths are reversed. */ - for (;;) { + while (current_listnode) { current_vertex = listgetdata(current_listnode); listnode_add(inner_pc_path, current_vertex); @@ -268,6 +270,7 @@ static void ospf_ti_lfa_generate_inner_label_stack( end_label = MPLS_INVALID_LABEL; if (p_node_info->node->id.s_addr == p_space->root->id.s_addr) { pc_p_node = listnode_lookup(q_space->pc_path, p_space->pc_spf); + assert(pc_p_node); start_vertex = listgetdata(pc_p_node->prev); start_label = ospf_sr_get_adj_sid_by_id(&p_node_info->node->id, &start_vertex->id); @@ -275,6 +278,7 @@ static void ospf_ti_lfa_generate_inner_label_stack( if (q_node_info->node->id.s_addr == q_space->root->id.s_addr) { pc_q_node = listnode_lookup(q_space->pc_path, listnode_head(q_space->pc_path)); + assert(pc_q_node); end_vertex = listgetdata(pc_q_node->next); end_label = ospf_sr_get_adj_sid_by_id(&end_vertex->id, &q_node_info->node->id); diff --git a/tests/topotests/babel_topo1/r3/babeld.conf b/tests/topotests/babel_topo1/r3/babeld.conf index bfda3622dd..e10e5aaacc 100644 --- a/tests/topotests/babel_topo1/r3/babeld.conf +++ b/tests/topotests/babel_topo1/r3/babeld.conf @@ -14,4 +14,3 @@ router babel network r3-eth1 redistribute ipv4 connected redistribute ipv4 static - redistirbute ipv6 connected diff --git a/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf index ce36494604..72238ccd40 100644 --- a/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf @@ -27,6 +27,5 @@ interface eth-rt3 ! router ospf ospf router-id 1.1.1.1 - passive interface lo router-info area 0.0.0.0 ! diff --git a/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf index a8ca564e4e..c5f4262a8f 100644 --- a/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf @@ -25,6 +25,5 @@ interface eth-rt5 ! router ospf ospf router-id 2.2.2.2 - passive interface lo router-info area 0.0.0.0 ! diff --git a/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf index 0404994c09..e487bdd7c0 100644 --- a/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf @@ -25,6 +25,5 @@ interface eth-rt4 ! router ospf ospf router-id 3.3.3.3 - passive interface lo router-info area 0.0.0.0 ! diff --git a/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf index 6b8ab3704f..560904e75d 100644 --- a/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf @@ -24,6 +24,5 @@ interface eth-rt5 ! router ospf ospf router-id 4.4.4.4 - passive interface lo router-info area 0.0.0.0 ! diff --git a/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf index 043432ec3d..77f5445286 100644 --- a/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf @@ -24,6 +24,5 @@ interface eth-rt4 ! router ospf ospf router-id 5.5.5.5 - passive interface lo router-info area 0.0.0.0 ! diff --git a/tests/topotests/bgp_addpath_best_selected/r2/bgpd.conf b/tests/topotests/bgp_addpath_best_selected/r2/bgpd.conf index 0c13824323..cdef611286 100644 --- a/tests/topotests/bgp_addpath_best_selected/r2/bgpd.conf +++ b/tests/topotests/bgp_addpath_best_selected/r2/bgpd.conf @@ -2,7 +2,6 @@ router bgp 65002 timers bgp 3 10 no bgp ebgp-requires-policy neighbor 192.168.1.1 remote-as external - neighbor 192.168.1.1 remote-as external neighbor 192.168.7.7 remote-as external neighbor 192.168.7.7 timers connect 5 neighbor 192.168.2.3 remote-as external diff --git a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py index dfd538f1c6..2a610c901e 100644 --- a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py +++ b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py @@ -75,6 +75,42 @@ def test_bgp_addpath_best_selected(): r2 = tgen.gears["r2"] + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 172.16.16.254/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "65006", + }, + "weight": 6, + }, + { + "aspath": { + "string": "65005", + }, + "weight": 5, + }, + { + "aspath": { + "string": "65004", + }, + "weight": 4, + }, + { + "aspath": { + "string": "65003", + }, + "weight": 3, + }, + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge initially" + def check_bgp_advertised_routes_to_r1(): output = json.loads( r2.vtysh_cmd( @@ -104,7 +140,7 @@ def test_bgp_addpath_best_selected(): return topotest.json_cmp(output, expected) test_func = functools.partial(check_bgp_advertised_routes_to_r1) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None ), "Received more/less Add-Path best paths, but should be only 1+1 (real best path)" @@ -143,7 +179,7 @@ def test_bgp_addpath_best_selected(): return topotest.json_cmp(output, expected) test_func = functools.partial(check_bgp_advertised_routes_to_r7) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None ), "Received more/less Add-Path best paths, but should be only 2+1 (real best path)" diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py new file mode 100644 index 0000000000..9f37440566 --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +""" +Test if role capability is exchanged dynamically. +""" + +import os +import re +import sys +import json +import pytest +import functools + +pytestmark = pytest.mark.bgpd + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_dynamic_capability_role(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "localRole": "undefined", + "remoteRole": "undefined", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + }, + "connectionsEstablished": 1, + "connectionsDropped": 0, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + step("Set local-role and check if it's exchanged dynamically") + + r1.vtysh_cmd( + """ + configure terminal + router bgp + neighbor 192.168.1.2 local-role customer + """ + ) + + r2.vtysh_cmd( + """ + configure terminal + router bgp + neighbor 192.168.1.1 local-role provider + """ + ) + + def _bgp_check_if_session_not_reset(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "localRole": "customer", + "remoteRole": "provider", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "role": "advertisedAndReceived", + }, + "connectionsEstablished": 1, + "connectionsDropped": 0, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_session_not_reset, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Session was reset after setting role capability" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py index a375993af4..eb81ffeb69 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py @@ -52,7 +52,7 @@ def teardown_module(mod): tgen.stop_topology() -def test_bgp_dynamic_capability(): +def test_bgp_dynamic_capability_software_version(): tgen = get_topogen() if tgen.routers_have_failure(): diff --git a/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py b/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py index 0433c15e0a..c0e19fa356 100644 --- a/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py +++ b/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py @@ -120,6 +120,82 @@ def test_bgp_set_aspath_replace_test2(): ), "Failed overriding incoming AS-PATH with route-map replace with configured ASN" +def test_bgp_set_aspath_replace_access_list(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + rname = "r1" + r1 = tgen.gears[rname] + + r1.vtysh_cmd( + """ +conf + bgp as-path access-list FIRST permit ^65 + route-map r2 permit 20 + set as-path replace as-path-access-list FIRST 65002 + """ + ) + + expected = { + "routes": { + "172.16.255.31/32": [{"path": "65002 65500"}], + "172.16.255.32/32": [{"path": "65002 65002"}], + } + } + + def _bgp_regexp_1(router): + output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json")) + + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_regexp_1, tgen.gears["r1"]) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, "Failed overriding incoming AS-PATH with regex 1 route-map" + r1.vtysh_cmd( + """ +conf + bgp as-path access-list SECOND permit 2 + route-map r2 permit 10 + set as-path replace as-path-access-list SECOND 65001 + """ + ) + + expected = { + "routes": { + "172.16.255.31/32": [{"path": "65001 65003"}], + "172.16.255.32/32": [{"path": "65002 65002"}], + } + } + + test_func = functools.partial(_bgp_regexp_1, tgen.gears["r1"]) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, "Failed overriding incoming AS-PATH with regex 2 route-map" + + r1.vtysh_cmd( + """ +conf + bgp as-path access-list TER permit 3 + route-map r2 permit 10 + set as-path replace as-path-access-list TER + """ + ) + expected = { + "routes": { + "172.16.255.31/32": [{"path": "65002 65001"}], + "172.16.255.32/32": [{"path": "65002 65002"}], + } + } + + test_func = functools.partial(_bgp_regexp_1, tgen.gears["r1"]) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, "Failed overriding incoming AS-PATH with regex 3 route-map" + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py b/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py index 9e529059e7..14b9ba8498 100755 --- a/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py +++ b/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py @@ -24,6 +24,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.common_config import required_linux_kernel_version +from lib.checkping import check_ping pytestmark = [pytest.mark.bgpd] @@ -101,31 +102,15 @@ def teardown_module(mod): tgen.stop_topology() -def check_ping4(name, dest_addr, expected): - def _check(name, dest_addr, match): - tgen = get_topogen() - output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr)) - logger.info(output) - if match not in output: - return "ping fail" - - match = ", {} packet loss".format("0%" if expected else "100%") - logger.info("[+] check {} {} {}".format(name, dest_addr, match)) - tgen = get_topogen() - func = functools.partial(_check, name, dest_addr, match) - success, result = topotest.run_and_expect(func, None, count=10, wait=1) - assert result is None, "Failed" - - def test_ping(): tgen = get_topogen() - check_ping4("c11", "192.168.2.1", True) - check_ping4("c11", "192.168.3.1", True) - check_ping4("c12", "192.168.2.1", True) - check_ping4("c12", "192.168.3.1", True) - check_ping4("c21", "192.168.3.1", True) - check_ping4("c22", "192.168.3.1", True) + check_ping("c11", "192.168.2.1", True, 10, 1) + check_ping("c11", "192.168.3.1", True, 10, 1) + check_ping("c12", "192.168.2.1", True, 10, 1) + check_ping("c12", "192.168.3.1", True, 10, 1) + check_ping("c21", "192.168.3.1", True, 10, 1) + check_ping("c22", "192.168.3.1", True, 10, 1) if __name__ == "__main__": diff --git a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py index cddcf6a9a1..189d2baf17 100755 --- a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py +++ b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py @@ -35,6 +35,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.common_config import required_linux_kernel_version +from lib.checkping import check_ping def build_topo(tgen): @@ -167,22 +168,6 @@ def open_json_file(filename): assert False, "Could not read file {}".format(filename) -def check_ping(name, dest_addr, expect_connected): - def _check(name, dest_addr, match): - tgen = get_topogen() - output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr)) - logger.info(output) - if match not in output: - return True - - match = ", {} packet loss".format("0%" if expect_connected else "100%") - logger.info("[+] check {} {} {}".format(name, dest_addr, match)) - tgen = get_topogen() - func = functools.partial(_check, name, dest_addr, match) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) - assert result is None, "Failed" - - def check_rib(name, cmd, expected_file): def _check(name, cmd, expected_file): logger.info("polling") @@ -215,21 +200,21 @@ def test_rib(): def test_ping(): - check_ping("ce1", "2001:2::2", True) - check_ping("ce1", "2001:3::2", True) - check_ping("ce1", "2001:4::2", False) - check_ping("ce1", "2001:5::2", False) - check_ping("ce1", "2001:6::2", False) - check_ping("ce4", "2001:1::2", False) - check_ping("ce4", "2001:2::2", False) - check_ping("ce4", "2001:3::2", False) - check_ping("ce4", "2001:5::2", True) - check_ping("ce4", "2001:6::2", True) + check_ping("ce1", "2001:2::2", True, 10, 0.5) + check_ping("ce1", "2001:3::2", True, 10, 0.5) + check_ping("ce1", "2001:4::2", False, 10, 0.5) + check_ping("ce1", "2001:5::2", False, 10, 0.5) + check_ping("ce1", "2001:6::2", False, 10, 0.5) + check_ping("ce4", "2001:1::2", False, 10, 0.5) + check_ping("ce4", "2001:2::2", False, 10, 0.5) + check_ping("ce4", "2001:3::2", False, 10, 0.5) + check_ping("ce4", "2001:5::2", True, 10, 0.5) + check_ping("ce4", "2001:6::2", True, 10, 0.5) def test_sid_per_afv6_auto(): check_rib("r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_afv6_auto_sid_rib.json") - check_ping("ce1", "2001:2::2", True) + check_ping("ce1", "2001:2::2", True, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ configure terminal @@ -241,7 +226,7 @@ def test_sid_per_afv6_auto(): check_rib( "r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_afv6_auto_no_sid_rib.json" ) - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ @@ -252,7 +237,7 @@ def test_sid_per_afv6_auto(): """ ) check_rib("r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_afv6_auto_sid_rib.json") - check_ping("ce1", "2001:2::2", True) + check_ping("ce1", "2001:2::2", True, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ @@ -265,14 +250,14 @@ def test_sid_per_afv6_auto(): check_rib( "r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_afv6_auto_no_sid_rib.json" ) - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 0.5) def test_sid_per_afv6_manual(): check_rib( "r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_afv6_manual_no_sid_rib.json" ) - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ @@ -286,7 +271,7 @@ def test_sid_per_afv6_manual(): check_rib( "r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_afv6_manual_sid_rib.json" ) - check_ping("ce1", "2001:2::2", True) + check_ping("ce1", "2001:2::2", True, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ @@ -299,12 +284,12 @@ def test_sid_per_afv6_manual(): check_rib( "r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_afv6_manual_no_sid_rib.json" ) - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 0.5) def test_sid_per_afv4_auto(): check_rib("r1", "show ip route vrf vrf10 json", "r1/vrf10_afv4_auto_sid_rib.json") - check_ping("ce1", "192.168.2.2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ configure terminal @@ -317,7 +302,7 @@ def test_sid_per_afv4_auto(): check_rib( "r1", "show ip route vrf vrf10 json", "r1/vrf10_afv4_auto_no_sid_rib.json" ) - check_ping("ce1", "192.168.2.2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ @@ -329,7 +314,7 @@ def test_sid_per_afv4_auto(): ) check_rib("r1", "show ip route vrf vrf10 json", "r1/vrf10_afv4_auto_sid_rib.json") - check_ping("ce1", "192.168.2.2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ @@ -342,14 +327,14 @@ def test_sid_per_afv4_auto(): check_rib( "r1", "show ip route vrf vrf10 json", "r1/vrf10_afv4_auto_no_sid_rib.json" ) - check_ping("ce1", "192.168.2.2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) def test_sid_per_afv4_manual(): check_rib( "r1", "show ip route vrf vrf10 json", "r1/vrf10_afv4_manual_no_sid_rib.json" ) - check_ping("ce1", "192.168.2.2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ configure terminal @@ -360,7 +345,7 @@ def test_sid_per_afv4_manual(): ) check_rib("r1", "show ip route vrf vrf10 json", "r1/vrf10_afv4_manual_sid_rib.json") - check_ping("ce1", "192.168.2.2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ @@ -370,7 +355,7 @@ def test_sid_per_afv4_manual(): no sid vpn export 8 """ ) - check_ping("ce1", "192.168.2.2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) check_rib( "r1", "show ip route vrf vrf10 json", "r1/vrf10_afv4_manual_no_sid_rib.json" ) @@ -380,7 +365,7 @@ def test_sid_per_vrf_auto(): check_rib( "r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_pervrf_auto_no_sid_rib.json" ) - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ configure terminal @@ -392,11 +377,11 @@ def test_sid_per_vrf_auto(): check_rib( "r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_pervrf6_auto_sid_rib.json" ) - check_ping("ce1", "2001:2::2", True) + check_ping("ce1", "2001:2::2", True, 10, 0.5) check_rib( "r1", "show ip route vrf vrf10 json", "r1/vrf10_pervrf4_auto_sid_rib.json" ) - check_ping("ce1", "192.168.2.2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ @@ -409,14 +394,14 @@ def test_sid_per_vrf_auto(): check_rib( "r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_pervrf_auto_no_sid_rib.json" ) - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 0.5) def test_sid_per_vrf_manual(): check_rib( "r1", "show ip route vrf vrf10 json", "r1/vrf10_pervrf_manual_no_sid_rib.json" ) - check_ping("ce1", "192.168.2.2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ configure terminal @@ -428,11 +413,11 @@ def test_sid_per_vrf_manual(): check_rib( "r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_pervrf6_manual_sid_rib.json" ) - check_ping("ce1", "2001:2::2", True) + check_ping("ce1", "2001:2::2", True, 10, 0.5) check_rib( "r1", "show ip route vrf vrf10 json", "r1/vrf10_pervrf4_manual_sid_rib.json" ) - check_ping("ce1", "192.168.2.2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) get_topogen().gears["r2"].vtysh_cmd( """ @@ -445,7 +430,7 @@ def test_sid_per_vrf_manual(): check_rib( "r1", "show ip route vrf vrf10 json", "r1/vrf10_pervrf_manual_no_sid_rib.json" ) - check_ping("ce1", "192.168.2.2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) if __name__ == "__main__": diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py index fdc1f4eec3..4afaeaf78a 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py @@ -23,6 +23,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.common_config import required_linux_kernel_version +from lib.checkping import check_ping pytestmark = [pytest.mark.bgpd] @@ -134,22 +135,6 @@ def open_json_file(filename): assert False, "Could not read file {}".format(filename) -def check_ping(name, dest_addr, expect_connected): - def _check(name, dest_addr, match): - tgen = get_topogen() - output = tgen.gears[name].run("ping6 {} -c 1 -w 1".format(dest_addr)) - logger.info(output) - if match not in output: - return "ping fail" - - match = ", {} packet loss".format("0%" if expect_connected else "100%") - logger.info("[+] check {} {} {}".format(name, dest_addr, match)) - tgen = get_topogen() - func = functools.partial(_check, name, dest_addr, match) - success, result = topotest.run_and_expect(func, None, count=10, wait=1) - assert result is None, "Failed" - - def check_rib(name, cmd, expected_file): def _check(name, cmd, expected_file): logger.info("polling") @@ -182,20 +167,20 @@ def test_rib(): def test_ping(): - check_ping("ce1", "2001:2::2", True) - check_ping("ce1", "2001:3::2", True) - check_ping("ce1", "2001:4::2", False) - check_ping("ce1", "2001:5::2", False) - check_ping("ce1", "2001:6::2", False) - check_ping("ce4", "2001:1::2", False) - check_ping("ce4", "2001:2::2", False) - check_ping("ce4", "2001:3::2", False) - check_ping("ce4", "2001:5::2", True) - check_ping("ce4", "2001:6::2", True) + check_ping("ce1", "2001:2::2", True, 10, 1) + check_ping("ce1", "2001:3::2", True, 10, 1) + check_ping("ce1", "2001:4::2", False, 10, 1) + check_ping("ce1", "2001:5::2", False, 10, 1) + check_ping("ce1", "2001:6::2", False, 10, 1) + check_ping("ce4", "2001:1::2", False, 10, 1) + check_ping("ce4", "2001:2::2", False, 10, 1) + check_ping("ce4", "2001:3::2", False, 10, 1) + check_ping("ce4", "2001:5::2", True, 10, 1) + check_ping("ce4", "2001:6::2", True, 10, 1) def test_locator_delete(): - check_ping("ce1", "2001:2::2", True) + check_ping("ce1", "2001:2::2", True, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -207,11 +192,11 @@ def test_locator_delete(): ) check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json") - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 1) def test_locator_recreate(): - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -224,11 +209,11 @@ def test_locator_recreate(): ) check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json") - check_ping("ce1", "2001:2::2", True) + check_ping("ce1", "2001:2::2", True, 10, 1) def test_bgp_locator_unset(): - check_ping("ce1", "2001:2::2", True) + check_ping("ce1", "2001:2::2", True, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -239,11 +224,11 @@ def test_bgp_locator_unset(): ) check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json") - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 1) def test_bgp_locator_reset(): - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -254,11 +239,11 @@ def test_bgp_locator_reset(): ) check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json") - check_ping("ce1", "2001:2::2", True) + check_ping("ce1", "2001:2::2", True, 10, 1) def test_bgp_srv6_unset(): - check_ping("ce1", "2001:2::2", True) + check_ping("ce1", "2001:2::2", True, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -268,11 +253,11 @@ def test_bgp_srv6_unset(): ) check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json") - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 1) def test_bgp_srv6_reset(): - check_ping("ce1", "2001:2::2", False) + check_ping("ce1", "2001:2::2", False, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -283,7 +268,7 @@ def test_bgp_srv6_reset(): ) check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json") - check_ping("ce1", "2001:2::2", True) + check_ping("ce1", "2001:2::2", True, 10, 1) if __name__ == "__main__": diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py index a1202f5d93..914c29f0c1 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py @@ -24,6 +24,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.common_config import required_linux_kernel_version +from lib.checkping import check_ping pytestmark = [pytest.mark.bgpd] @@ -96,21 +97,6 @@ def open_json_file(filename): assert False, "Could not read file {}".format(filename) -def check_ping(name, dest_addr, expect_connected): - def _check(name, dest_addr, match): - tgen = get_topogen() - output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr)) - logger.info(output) - assert match in output, "ping fail" - - match = ", {} packet loss".format("0%" if expect_connected else "100%") - logger.info("[+] check {} {} {}".format(name, dest_addr, match)) - tgen = get_topogen() - func = functools.partial(_check, name, dest_addr, match) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) - assert result is None, "Failed" - - def check_rib(name, cmd, expected_file): def _check(name, dest_addr, match): logger.info("polling") @@ -143,16 +129,16 @@ def test_rib(): def test_ping(): - check_ping("ce1", "192.168.2.2", True) - check_ping("ce1", "192.168.3.2", True) - check_ping("ce1", "192.168.4.2", False) - check_ping("ce1", "192.168.5.2", False) - check_ping("ce1", "192.168.6.2", False) - check_ping("ce4", "192.168.1.2", False) - check_ping("ce4", "192.168.2.2", False) - check_ping("ce4", "192.168.3.2", False) - check_ping("ce4", "192.168.5.2", True) - check_ping("ce4", "192.168.6.2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) + check_ping("ce1", "192.168.3.2", True, 10, 0.5) + check_ping("ce1", "192.168.4.2", False, 10, 0.5) + check_ping("ce1", "192.168.5.2", False, 10, 0.5) + check_ping("ce1", "192.168.6.2", False, 10, 0.5) + check_ping("ce4", "192.168.1.2", False, 10, 0.5) + check_ping("ce4", "192.168.2.2", False, 10, 0.5) + check_ping("ce4", "192.168.3.2", False, 10, 0.5) + check_ping("ce4", "192.168.5.2", True, 10, 0.5) + check_ping("ce4", "192.168.6.2", True, 10, 0.5) if __name__ == "__main__": diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py index 7c2c7cfdaa..8a7b558be3 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py @@ -21,6 +21,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.common_config import required_linux_kernel_version +from lib.checkping import check_ping, check_ping pytestmark = [pytest.mark.bgpd] @@ -93,38 +94,6 @@ def open_json_file(filename): assert False, "Could not read file {}".format(filename) -def check_ping4(name, dest_addr, expect_connected): - def _check(name, dest_addr, match): - tgen = get_topogen() - output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr)) - logger.info(output) - if match not in output: - return "ping fail" - - match = ", {} packet loss".format("0%" if expect_connected else "100%") - logger.info("[+] check {} {} {}".format(name, dest_addr, match)) - tgen = get_topogen() - func = functools.partial(_check, name, dest_addr, match) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) - assert result is None, "Failed" - - -def check_ping6(name, dest_addr, expect_connected): - def _check(name, dest_addr, match): - tgen = get_topogen() - output = tgen.gears[name].run("ping6 {} -c 1 -w 1".format(dest_addr)) - logger.info(output) - if match not in output: - return "ping fail" - - match = "{} packet loss".format("0%" if expect_connected else "100%") - logger.info("[+] check {} {} {}".format(name, dest_addr, match)) - tgen = get_topogen() - func = functools.partial(_check, name, dest_addr, match) - success, result = topotest.run_and_expect(func, None, count=10, wait=1) - assert result is None, "Failed" - - def check_rib(name, cmd, expected_file): def _check(name, dest_addr, match): logger.info("polling") @@ -170,32 +139,32 @@ def test_rib(): def test_ping(): - check_ping4("ce1", "192.168.2.2", True) - check_ping4("ce1", "192.168.3.2", True) - check_ping4("ce1", "192.168.4.2", False) - check_ping4("ce1", "192.168.5.2", False) - check_ping4("ce1", "192.168.6.2", False) - check_ping4("ce4", "192.168.1.2", False) - check_ping4("ce4", "192.168.2.2", False) - check_ping4("ce4", "192.168.3.2", False) - check_ping4("ce4", "192.168.5.2", True) - check_ping4("ce4", "192.168.6.2", True) - - check_ping6("ce1", "2001:2::2", True) - check_ping6("ce1", "2001:3::2", True) - check_ping6("ce1", "2001:4::2", False) - check_ping6("ce1", "2001:5::2", False) - check_ping6("ce1", "2001:6::2", False) - check_ping6("ce4", "2001:1::2", False) - check_ping6("ce4", "2001:2::2", False) - check_ping6("ce4", "2001:3::2", False) - check_ping6("ce4", "2001:5::2", True) - check_ping6("ce4", "2001:6::2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) + check_ping("ce1", "192.168.3.2", True, 10, 0.5) + check_ping("ce1", "192.168.4.2", False, 10, 0.5) + check_ping("ce1", "192.168.5.2", False, 10, 0.5) + check_ping("ce1", "192.168.6.2", False, 10, 0.5) + check_ping("ce4", "192.168.1.2", False, 10, 0.5) + check_ping("ce4", "192.168.2.2", False, 10, 0.5) + check_ping("ce4", "192.168.3.2", False, 10, 0.5) + check_ping("ce4", "192.168.5.2", True, 10, 0.5) + check_ping("ce4", "192.168.6.2", True, 10, 0.5) + + check_ping("ce1", "2001:2::2", True, 10, 1) + check_ping("ce1", "2001:3::2", True, 10, 1) + check_ping("ce1", "2001:4::2", False, 10, 1) + check_ping("ce1", "2001:5::2", False, 10, 1) + check_ping("ce1", "2001:6::2", False, 10, 1) + check_ping("ce4", "2001:1::2", False, 10, 1) + check_ping("ce4", "2001:2::2", False, 10, 1) + check_ping("ce4", "2001:3::2", False, 10, 1) + check_ping("ce4", "2001:5::2", True, 10, 1) + check_ping("ce4", "2001:6::2", True, 10, 1) def test_bgp_sid_vpn_export_disable(): - check_ping4("ce1", "192.168.2.2", True) - check_ping6("ce1", "2001:2::2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) + check_ping("ce1", "2001:2::2", True, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -216,13 +185,13 @@ def test_bgp_sid_vpn_export_disable(): check_rib( "r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_disabled.json" ) - check_ping4("ce1", "192.168.2.2", False) - check_ping6("ce1", "2001:2::2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) + check_ping("ce1", "2001:2::2", False, 10, 1) def test_bgp_sid_vpn_export_reenable(): - check_ping4("ce1", "192.168.2.2", False) - check_ping6("ce1", "2001:2::2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) + check_ping("ce1", "2001:2::2", False, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -243,13 +212,13 @@ def test_bgp_sid_vpn_export_reenable(): check_rib( "r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_reenabled.json" ) - check_ping4("ce1", "192.168.2.2", True) - check_ping6("ce1", "2001:2::2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) + check_ping("ce1", "2001:2::2", True, 10, 1) def test_locator_delete(): - check_ping4("ce1", "192.168.2.2", True) - check_ping6("ce1", "2001:2::2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) + check_ping("ce1", "2001:2::2", True, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -263,13 +232,13 @@ def test_locator_delete(): check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_deleted.json") check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json") - check_ping4("ce1", "192.168.2.2", False) - check_ping6("ce1", "2001:2::2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) + check_ping("ce1", "2001:2::2", False, 10, 1) def test_locator_recreate(): - check_ping4("ce1", "192.168.2.2", False) - check_ping6("ce1", "2001:2::2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) + check_ping("ce1", "2001:2::2", False, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -284,13 +253,13 @@ def test_locator_recreate(): check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_recreated.json") check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json") - check_ping4("ce1", "192.168.2.2", True) - check_ping6("ce1", "2001:2::2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) + check_ping("ce1", "2001:2::2", True, 10, 1) def test_bgp_locator_unset(): - check_ping4("ce1", "192.168.2.2", True) - check_ping6("ce1", "2001:2::2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) + check_ping("ce1", "2001:2::2", True, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -303,13 +272,13 @@ def test_bgp_locator_unset(): check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_deleted.json") check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json") - check_ping4("ce1", "192.168.2.2", False) - check_ping6("ce1", "2001:2::2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) + check_ping("ce1", "2001:2::2", False, 10, 1) def test_bgp_locator_reset(): - check_ping4("ce1", "192.168.2.2", False) - check_ping6("ce1", "2001:2::2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) + check_ping("ce1", "2001:2::2", False, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -322,13 +291,13 @@ def test_bgp_locator_reset(): check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_recreated.json") check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json") - check_ping4("ce1", "192.168.2.2", True) - check_ping6("ce1", "2001:2::2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) + check_ping("ce1", "2001:2::2", True, 10, 1) def test_bgp_srv6_unset(): - check_ping4("ce1", "192.168.2.2", True) - check_ping6("ce1", "2001:2::2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) + check_ping("ce1", "2001:2::2", True, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -340,13 +309,13 @@ def test_bgp_srv6_unset(): check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_deleted.json") check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json") - check_ping4("ce1", "192.168.2.2", False) - check_ping6("ce1", "2001:2::2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) + check_ping("ce1", "2001:2::2", False, 10, 1) def test_bgp_srv6_reset(): - check_ping4("ce1", "192.168.2.2", False) - check_ping6("ce1", "2001:2::2", False) + check_ping("ce1", "192.168.2.2", False, 10, 0.5) + check_ping("ce1", "2001:2::2", False, 10, 1) get_topogen().gears["r1"].vtysh_cmd( """ configure terminal @@ -359,8 +328,8 @@ def test_bgp_srv6_reset(): check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_recreated.json") check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json") check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json") - check_ping4("ce1", "192.168.2.2", True) - check_ping6("ce1", "2001:2::2", True) + check_ping("ce1", "192.168.2.2", True, 10, 0.5) + check_ping("ce1", "2001:2::2", True, 10, 1) if __name__ == "__main__": diff --git a/tests/topotests/bgp_update_delay/r2/zebra.conf b/tests/topotests/bgp_update_delay/r2/zebra.conf index 420f00d974..1fcedaaf72 100644 --- a/tests/topotests/bgp_update_delay/r2/zebra.conf +++ b/tests/topotests/bgp_update_delay/r2/zebra.conf @@ -12,9 +12,5 @@ interface r2-eth3 ip address 192.168.252.1/30 vrf vrf1 ! -auto vrf1 -iface vrf1 - vrf-table auto -! ip forwarding ! diff --git a/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py index c0e57930a3..a908e74cc6 100644 --- a/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py +++ b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py @@ -50,6 +50,8 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger +from lib.checkping import check_ping + # Required to instantiate the topology builder class. @@ -257,29 +259,6 @@ def mpls_table_check_entry(router, out_label, out_nexthop): ) -def check_ping(name, dest_addr, expect_connected): - """ - Assert that ping to dest_addr is expected - * 'name': the router to set the ping from - * 'dest_addr': The destination ip address to ping - * 'expect_connected': True if ping is expected to pass - """ - - def _check(name, dest_addr, match): - tgen = get_topogen() - output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr)) - logger.info(output) - if match not in output: - return "ping fail" - - match = ", {} packet loss".format("0%" if expect_connected else "100%") - logger.info("[+] check {} {} {}".format(name, dest_addr, match)) - tgen = get_topogen() - func = functools.partial(_check, name, dest_addr, match) - success, result = topotest.run_and_expect(func, None, count=20, wait=0.5) - assert result is None, "Failed" - - def check_show_bgp_vpn_prefix_found( router, ipversion, prefix, rd, label=None, nexthop=None ): @@ -493,8 +472,8 @@ def test_mpls_setup_ok(): check_show_bgp_vpn_ok(router, vpnv4_checks) logger.info("h1, check that ping from h1 to (h2,h3) is ok") - check_ping("h1", "172.31.1.10", True) - check_ping("h1", "172.31.2.10", True) + check_ping("h1", "172.31.1.10", True, 20, 0.5) + check_ping("h1", "172.31.2.10", True, 20, 0.5) def test_r3_prefixes_removed(): @@ -751,8 +730,8 @@ def test_reconfigure_nexthop_change_nexthop_self(): check_show_bgp_vpn_ok(router, vpnv4_checks) logger.info("h1, check that ping from h1 to (h2,h3) is ok") - check_ping("h1", "172.31.1.10", True) - check_ping("h1", "172.31.2.10", True) + check_ping("h1", "172.31.1.10", True, 20, 0.5) + check_ping("h1", "172.31.2.10", True, 20, 0.5) # diagnostic logger.info("Dumping mplsvpn nexthop table") router.vtysh_cmd("show bgp mplsvpn-nh-label-bind detail", isjson=False) diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/isisd.conf b/tests/topotests/bgp_vpnv4_noretain/r1/isisd.conf deleted file mode 100644 index 233a6473b3..0000000000 --- a/tests/topotests/bgp_vpnv4_noretain/r1/isisd.conf +++ /dev/null @@ -1,14 +0,0 @@ -interface r1-eth0 - ip router isis 1 - isis circuit-type level-1 -! -interface lo - ip router isis 1 - isis passive -! -router isis 1 - is-type level-1 - net 49.0002.0000.1994.00 - segment-routing on - segment-routing prefix 192.0.2.1/32 index 11 -! diff --git a/tests/topotests/bgp_vpnv4_noretain/r2/isisd.conf b/tests/topotests/bgp_vpnv4_noretain/r2/isisd.conf deleted file mode 100644 index 547d10f2bc..0000000000 --- a/tests/topotests/bgp_vpnv4_noretain/r2/isisd.conf +++ /dev/null @@ -1,14 +0,0 @@ -interface r2-eth0 - ip router isis 1 - isis circuit-type level-1 -! -interface lo - ip router isis 1 - isis passive -! -router isis 1 - is-type level-1 - net 49.0002.0000.1995.00 - segment-routing on - segment-routing prefix 192.0.2.2/32 index 22 -! diff --git a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py index f665040f7f..f2865fec9e 100644 --- a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py +++ b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py @@ -120,9 +120,6 @@ def setup_module(mod): router.load_config( TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) ) - router.load_config( - TopoRouter.RD_ISIS, os.path.join(CWD, "{}/bgpd.conf".format(rname)) - ) # Initialize all routers. tgen.start_router() diff --git a/tests/topotests/config_timing/r1/zebra.conf b/tests/topotests/config_timing/r1/zebra.conf index 46fd965034..b4dc338b8d 100644 --- a/tests/topotests/config_timing/r1/zebra.conf +++ b/tests/topotests/config_timing/r1/zebra.conf @@ -4,10 +4,8 @@ ip prefix-list ANY permit 0.0.0.0/0 le 32 ipv6 prefix-list ANY seq 10 permit any route-map RM-NONE4 deny 10 -exit-route-map route-map RM-NONE6 deny 10 -exit-route-map interface r1-eth0 ip address 100.0.0.1/24 diff --git a/tests/topotests/cspf_topo1/r1/sharpd.conf b/tests/topotests/cspf_topo1/r1/sharpd.conf index 272eac944e..465034f150 100644 --- a/tests/topotests/cspf_topo1/r1/sharpd.conf +++ b/tests/topotests/cspf_topo1/r1/sharpd.conf @@ -1,3 +1,2 @@ ! -import-te ! diff --git a/tests/topotests/isis_snmp/r1/ldpd.conf b/tests/topotests/isis_snmp/r1/ldpd.conf index 5b1cbfebc9..64f51fce27 100644 --- a/tests/topotests/isis_snmp/r1/ldpd.conf +++ b/tests/topotests/isis_snmp/r1/ldpd.conf @@ -5,7 +5,6 @@ log file ldpd.log ! debug mpls ldp event ! debug mpls ldp errors ! debug mpls ldp sync -agentx ! mpls ldp router-id 1.1.1.1 diff --git a/tests/topotests/lib/checkping.py b/tests/topotests/lib/checkping.py new file mode 100644 index 0000000000..aaa6164dd4 --- /dev/null +++ b/tests/topotests/lib/checkping.py @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright 2023 Quentin Young + +import functools +from lib.topogen import get_topogen +from lib.topolog import logger +from lib import topotest + + +def check_ping(name, dest_addr, expect_connected, count, wait): + """ + Assert that ping to dest_addr is expected + * 'name': the router to set the ping from + * 'dest_addr': The destination ip address to ping + * 'expect_connected': True if ping is expected to pass + * 'count': how many echos to send + * 'wait': how long ping should wait to receive all replies + """ + + def _check(name, dest_addr, match): + tgen = get_topogen() + output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr)) + logger.info(output) + if match not in output: + return "ping fail" + + match = ", {} packet loss".format("0%" if expect_connected else "100%") + logger.info("[+] check {} {} {}".format(name, dest_addr, match)) + tgen = get_topogen() + func = functools.partial(_check, name, dest_addr, match) + success, result = topotest.run_and_expect(func, None, count=count, wait=wait) + assert result is None, "Failed" diff --git a/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf index 8a9b4eb124..aa9438b78e 100644 --- a/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf +++ b/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf @@ -1,4 +1,3 @@ -:assword 1 hostname rt1 log file ospf6d.log log commands diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 593de7ffbc..6254a93766 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -548,9 +548,7 @@ static void configvec_dump(vector vec, bool nested) * are not under the VRF node. */ if (config->index == INTERFACE_NODE - && (listcount(config->line) == 1) - && (line = listnode_head(config->line)) - && strmatch(line, "exit")) { + && list_isempty(config->line)) { config_del(config); continue; } diff --git a/zebra/main.c b/zebra/main.c index bd4623be55..aeb9739c13 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -71,22 +71,25 @@ uint32_t rcvbufsize = 128 * 1024; #define OPTION_V6_RR_SEMANTICS 2000 #define OPTION_ASIC_OFFLOAD 2001 +#define OPTION_V6_WITH_V4_NEXTHOP 2002 /* Command line options. */ const struct option longopts[] = { - {"batch", no_argument, NULL, 'b'}, - {"allow_delete", no_argument, NULL, 'a'}, - {"socket", required_argument, NULL, 'z'}, - {"ecmp", required_argument, NULL, 'e'}, - {"retain", no_argument, NULL, 'r'}, - {"graceful_restart", required_argument, NULL, 'K'}, - {"asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD}, + { "batch", no_argument, NULL, 'b' }, + { "allow_delete", no_argument, NULL, 'a' }, + { "socket", required_argument, NULL, 'z' }, + { "ecmp", required_argument, NULL, 'e' }, + { "retain", no_argument, NULL, 'r' }, + { "graceful_restart", required_argument, NULL, 'K' }, + { "asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD }, + { "v6-with-v4-nexthops", no_argument, NULL, OPTION_V6_WITH_V4_NEXTHOP }, #ifdef HAVE_NETLINK - {"vrfwnetns", no_argument, NULL, 'n'}, - {"nl-bufsize", required_argument, NULL, 's'}, - {"v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS}, + { "vrfwnetns", no_argument, NULL, 'n' }, + { "nl-bufsize", required_argument, NULL, 's' }, + { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, #endif /* HAVE_NETLINK */ - {0}}; + { 0 } +}; zebra_capabilities_t _caps_p[] = {ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW, @@ -287,6 +290,7 @@ int main(int argc, char **argv) struct sockaddr_storage dummy; socklen_t dummylen; bool asic_offload = false; + bool v6_with_v4_nexthop = false; bool notify_on_ack = true; graceful_restart = 0; @@ -294,26 +298,26 @@ int main(int argc, char **argv) frr_preinit(&zebra_di, argc, argv); - frr_opt_add( - "baz:e:rK:s:" + frr_opt_add("baz:e:rK:s:" #ifdef HAVE_NETLINK - "n" + "n" #endif - , - longopts, - " -b, --batch Runs in batch mode\n" - " -a, --allow_delete Allow other processes to delete zebra routes\n" - " -z, --socket Set path of zebra socket\n" - " -e, --ecmp Specify ECMP to use.\n" - " -r, --retain When program terminates, retain added route by zebra.\n" - " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" - " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" + , + longopts, + " -b, --batch Runs in batch mode\n" + " -a, --allow_delete Allow other processes to delete zebra routes\n" + " -z, --socket Set path of zebra socket\n" + " -e, --ecmp Specify ECMP to use.\n" + " -r, --retain When program terminates, retain added route by zebra.\n" + " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" + " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" + " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops" #ifdef HAVE_NETLINK - " -s, --nl-bufsize Set netlink receive buffer size\n" - " -n, --vrfwnetns Use NetNS as VRF backend\n" - " --v6-rr-semantics Use v6 RR semantics\n" + " -s, --nl-bufsize Set netlink receive buffer size\n" + " -n, --vrfwnetns Use NetNS as VRF backend\n" + " --v6-rr-semantics Use v6 RR semantics\n" #else - " -s, Set kernel socket receive buffer size\n" + " -s, Set kernel socket receive buffer size\n" #endif /* HAVE_NETLINK */ ); @@ -383,6 +387,9 @@ int main(int argc, char **argv) notify_on_ack = true; asic_offload = true; break; + case OPTION_V6_WITH_V4_NEXTHOP: + v6_with_v4_nexthop = true; + break; #endif /* HAVE_NETLINK */ default: frr_help_exit(1); @@ -392,7 +399,7 @@ int main(int argc, char **argv) zrouter.master = frr_init(); /* Zebra related initialize. */ - zebra_router_init(asic_offload, notify_on_ack); + zebra_router_init(asic_offload, notify_on_ack, v6_with_v4_nexthop); zserv_init(); rib_init(); zebra_if_init(); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 2fc696c4e1..e9c243217a 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2319,7 +2319,7 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) stream_putc(s, mpls_enabled); stream_putl(s, zrouter.multipath_num); stream_putc(s, zebra_mlag_get_role()); - + stream_putc(s, zrouter.v6_with_v4_nexthop); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index c5dc0e1829..e527d93610 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -280,34 +280,8 @@ struct dplane_neigh_table { * Policy based routing rule info for the dataplane */ struct dplane_ctx_rule { - uint32_t seq; - uint32_t priority; - uint32_t unique; + struct pbr_rule prule; - /* The route table pointed by this rule */ - uint32_t table; - - /* Filter criteria */ - uint32_t filter_bm; - uint32_t fwmark; - uint8_t dsfield; - struct prefix src_ip; - struct prefix dst_ip; - uint8_t ip_proto; - uint16_t src_port; - uint16_t dst_port; - - uint8_t action_pcp; - uint16_t action_vlan_id; - uint16_t action_vlan_flags; - - uint32_t action_queue_id; - - uint8_t filter_pcp; - uint16_t filter_vlan_id; - uint16_t filter_vlan_flags; - - char ifname[INTERFACE_NAMSIZ + 1]; struct ethaddr smac; struct ethaddr dmac; int out_ifindex; @@ -2774,6 +2748,25 @@ dplane_ctx_gre_get_info(const struct zebra_dplane_ctx *ctx) return &ctx->u.gre.info; } +/*********************************************************************** + * PBR RULE ACCESSORS - start + **********************************************************************/ + +/* + * This accessor fills one or two lib/pbr structs from the PBR context. + * New dataplane modules should use this interface where possible instead + * of adding more accessors that return fields from 'struct pbr_rule'. + */ +void dplane_ctx_rule_get(const struct zebra_dplane_ctx *ctx, + struct pbr_rule *pNew, struct pbr_rule *pOld) +{ + DPLANE_CTX_VALID(ctx); + if (pNew) + *pNew = ctx->u.rule.new.prule; + if (pOld) + *pOld = ctx->u.rule.old.prule; +} + /* Accessors for PBR rule information */ int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx) { @@ -2786,7 +2779,7 @@ const char *dplane_ctx_rule_get_ifname(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.ifname; + return ctx->u.rule.new.prule.ifname; } int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx) @@ -2807,112 +2800,112 @@ uint32_t dplane_ctx_rule_get_priority(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.priority; + return ctx->u.rule.new.prule.priority; } uint32_t dplane_ctx_rule_get_old_priority(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.priority; + return ctx->u.rule.old.prule.priority; } uint32_t dplane_ctx_rule_get_table(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.table; + return ctx->u.rule.new.prule.action.table; } uint32_t dplane_ctx_rule_get_old_table(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.table; + return ctx->u.rule.old.prule.action.table; } uint32_t dplane_ctx_rule_get_filter_bm(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.filter_bm; + return ctx->u.rule.new.prule.filter.filter_bm; } uint32_t dplane_ctx_rule_get_old_filter_bm(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.filter_bm; + return ctx->u.rule.old.prule.filter.filter_bm; } uint32_t dplane_ctx_rule_get_fwmark(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.fwmark; + return ctx->u.rule.new.prule.filter.fwmark; } uint32_t dplane_ctx_rule_get_old_fwmark(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.fwmark; + return ctx->u.rule.old.prule.filter.fwmark; } uint8_t dplane_ctx_rule_get_ipproto(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.ip_proto; + return ctx->u.rule.new.prule.filter.ip_proto; } uint8_t dplane_ctx_rule_get_old_ipproto(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.ip_proto; + return ctx->u.rule.old.prule.filter.ip_proto; } uint16_t dplane_ctx_rule_get_src_port(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.src_port; + return ctx->u.rule.new.prule.filter.src_port; } uint16_t dplane_ctx_rule_get_old_src_port(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.src_port; + return ctx->u.rule.old.prule.filter.src_port; } uint16_t dplane_ctx_rule_get_dst_port(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.dst_port; + return ctx->u.rule.new.prule.filter.dst_port; } uint16_t dplane_ctx_rule_get_old_dst_port(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.dst_port; + return ctx->u.rule.old.prule.filter.dst_port; } uint8_t dplane_ctx_rule_get_dsfield(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.dsfield; + return ctx->u.rule.new.prule.filter.dsfield; } uint8_t dplane_ctx_rule_get_old_dsfield(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.dsfield; + return ctx->u.rule.old.prule.filter.dsfield; } const struct prefix * @@ -2920,7 +2913,7 @@ dplane_ctx_rule_get_src_ip(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.rule.new.src_ip); + return &(ctx->u.rule.new.prule.filter.src_ip); } const struct prefix * @@ -2928,7 +2921,7 @@ dplane_ctx_rule_get_old_src_ip(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.rule.old.src_ip); + return &(ctx->u.rule.old.prule.filter.src_ip); } const struct prefix * @@ -2936,7 +2929,7 @@ dplane_ctx_rule_get_dst_ip(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.rule.new.dst_ip); + return &(ctx->u.rule.new.prule.filter.dst_ip); } const struct prefix * @@ -2944,9 +2937,58 @@ dplane_ctx_rule_get_old_dst_ip(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.rule.old.dst_ip); + return &(ctx->u.rule.old.prule.filter.dst_ip); +} + +const struct ethaddr * +dplane_ctx_rule_get_smac(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.rule.new.smac); +} + +const struct ethaddr * +dplane_ctx_rule_get_dmac(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.rule.new.dmac); +} + +int dplane_ctx_rule_get_out_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rule.new.out_ifindex; +} + +intptr_t dplane_ctx_rule_get_old_dp_flow_ptr(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rule.old.dp_flow_ptr; +} + +intptr_t dplane_ctx_rule_get_dp_flow_ptr(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rule.new.dp_flow_ptr; +} + +void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx, + intptr_t dp_flow_ptr) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.rule.new.dp_flow_ptr = dp_flow_ptr; } +/*********************************************************************** + * PBR RULE ACCESSORS - end + **********************************************************************/ + uint32_t dplane_ctx_get_br_port_flags(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -3015,55 +3057,6 @@ void dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx, memcpy(entry, &ctx->u.ipset_entry.entry, sizeof(struct zebra_pbr_ipset_entry)); } -const struct ethaddr * -dplane_ctx_rule_get_smac(const struct zebra_dplane_ctx *ctx) -{ - DPLANE_CTX_VALID(ctx); - - return &(ctx->u.rule.new.smac); -} - -const struct ethaddr * -dplane_ctx_rule_get_dmac(const struct zebra_dplane_ctx *ctx) -{ - DPLANE_CTX_VALID(ctx); - - return &(ctx->u.rule.new.dmac); -} - -int dplane_ctx_rule_get_out_ifindex(const struct zebra_dplane_ctx *ctx) -{ - DPLANE_CTX_VALID(ctx); - - return ctx->u.rule.new.out_ifindex; -} - -intptr_t dplane_ctx_rule_get_old_dp_flow_ptr(const struct zebra_dplane_ctx *ctx) -{ - DPLANE_CTX_VALID(ctx); - - return ctx->u.rule.old.dp_flow_ptr; -} - -intptr_t dplane_ctx_rule_get_dp_flow_ptr(const struct zebra_dplane_ctx *ctx) -{ - DPLANE_CTX_VALID(ctx); - - return ctx->u.rule.new.dp_flow_ptr; -} - -void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx, - intptr_t dp_flow_ptr) -{ - DPLANE_CTX_VALID(ctx); - - ctx->u.rule.new.dp_flow_ptr = dp_flow_ptr; -} - -/* - * End of dplane context accessors - */ - /* Optional extra info about interfaces in nexthops - a plugin must enable * this extra info. */ @@ -3898,27 +3891,8 @@ static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule, { struct zebra_neigh_ent *n; - dplane_rule->priority = rule->rule.priority; - dplane_rule->table = rule->rule.action.table; - - dplane_rule->filter_bm = rule->rule.filter.filter_bm; - dplane_rule->fwmark = rule->rule.filter.fwmark; - dplane_rule->dsfield = rule->rule.filter.dsfield; - dplane_rule->ip_proto = rule->rule.filter.ip_proto; - dplane_rule->src_port = rule->rule.filter.src_port; - dplane_rule->dst_port = rule->rule.filter.dst_port; - dplane_rule->filter_pcp = rule->rule.filter.pcp; - dplane_rule->filter_vlan_id = rule->rule.filter.vlan_id; - dplane_rule->filter_vlan_flags = rule->rule.filter.vlan_flags; - prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip); - prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip); - - dplane_rule->action_pcp = rule->rule.action.pcp; - dplane_rule->action_vlan_flags = rule->rule.action.vlan_flags; - dplane_rule->action_vlan_id = rule->rule.action.vlan_id; - dplane_rule->action_queue_id = rule->rule.action.queue_id; - - strlcpy(dplane_rule->ifname, rule->ifname, INTERFACE_NAMSIZ); + dplane_rule->prule = rule->rule; + dplane_rule->dp_flow_ptr = rule->action.dp_flow_ptr; n = rule->action.neigh; if (n && (n->flags & ZEBRA_NEIGH_ENT_ACTIVE)) { diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 4be3f28874..79248a4ae4 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -11,6 +11,7 @@ #include "lib/prefix.h" #include "lib/nexthop.h" #include "lib/nexthop_group.h" +#include "lib/pbr.h" #include "lib/vlan.h" #include "zebra/zebra_ns.h" #include "zebra/rib.h" @@ -693,6 +694,8 @@ uint16_t dplane_ctx_neigh_get_state(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx); /* Accessors for policy based routing rule information */ +void dplane_ctx_rule_get(const struct zebra_dplane_ctx *ctx, + struct pbr_rule *pNew, struct pbr_rule *pOld); int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx); int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx); int dplane_ctx_rule_get_seq(const struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 1b3e31ee42..4caaf8a9e2 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -255,7 +255,8 @@ bool zebra_router_notify_on_ack(void) return !zrouter.asic_offloaded || zrouter.notify_on_ack; } -void zebra_router_init(bool asic_offload, bool notify_on_ack) +void zebra_router_init(bool asic_offload, bool notify_on_ack, + bool v6_with_v4_nexthop) { zrouter.sequence_num = 0; @@ -310,7 +311,7 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) zrouter.asic_offloaded = asic_offload; zrouter.notify_on_ack = notify_on_ack; - + zrouter.v6_with_v4_nexthop = v6_with_v4_nexthop; /* * If you start using asic_notification_nexthop_control * come talk to the FRR community about what you are doing diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index a7f0f135f9..bd86cfb495 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -207,6 +207,7 @@ struct zebra_router { */ bool asic_offloaded; bool notify_on_ack; + bool v6_with_v4_nexthop; /* * If the asic is notifying us about successful nexthop @@ -237,7 +238,8 @@ struct zebra_router { extern struct zebra_router zrouter; extern uint32_t rcvbufsize; -extern void zebra_router_init(bool asic_offload, bool notify_on_ack); +extern void zebra_router_init(bool asic_offload, bool notify_on_ack, + bool v6_with_v4_nexthop); extern void zebra_router_cleanup(void); extern void zebra_router_terminate(void); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 291c2eb7e0..1a123ba5c2 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -4033,6 +4033,9 @@ DEFUN (show_zebra, ttable_add_row(table, "VRF|Not Available"); #endif + ttable_add_row(table, "v6 with v4 nexthop|%s", + zrouter.v6_with_v4_nexthop ? "Used" : "Unavaliable"); + ttable_add_row(table, "ASIC offload|%s", zrouter.asic_offloaded ? "Used" : "Unavailable"); |
