diff options
102 files changed, 2917 insertions, 614 deletions
diff --git a/babeld/neighbour.c b/babeld/neighbour.c index 51e595a84b..65e613cc8b 100644 --- a/babeld/neighbour.c +++ b/babeld/neighbour.c @@ -34,15 +34,13 @@ find_neighbour_nocreate(const unsigned char *address, struct interface *ifp) { struct neighbour *neigh; FOR_ALL_NEIGHBOURS(neigh) { - if(memcmp(address, neigh->address, 16) == 0 && - neigh->ifp == ifp) + if(memcmp(address, neigh->address, 16) == 0 && neigh->ifp == ifp) return neigh; } return NULL; } -void -flush_neighbour(struct neighbour *neigh) +void flush_neighbour(struct neighbour *neigh) { debugf(BABEL_DEBUG_COMMON,"Flushing neighbour %s (reach 0x%04x)", format_address(neigh->address), neigh->reach); @@ -102,8 +100,7 @@ find_neighbour(const unsigned char *address, struct interface *ifp) } /* Recompute a neighbour's rxcost. Return true if anything changed. */ -int -update_neighbour(struct neighbour *neigh, int hello, int hello_interval) +int update_neighbour(struct neighbour *neigh, int hello, int hello_interval) { int missed_hellos; int rc = 0; @@ -160,26 +157,26 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval) if(hello >= 0) { neigh->hello_seqno = hello; neigh->reach >>= 1; - neigh->reach |= 0x8000; - if((neigh->reach & 0xFC00) != 0xFC00) + SET_FLAG(neigh->reach, 0x8000); + if(CHECK_FLAG(neigh->reach, 0xFC00) != 0xFC00) rc = 1; } /* Make sure to give neighbours some feedback early after association */ - if((neigh->reach & 0xBF00) == 0x8000) { + if(CHECK_FLAG(neigh->reach, 0xBF00) == 0x8000) { /* A new neighbour */ send_hello(neigh->ifp); } else { /* Don't send hellos, in order to avoid a positive feedback loop. */ - int a = (neigh->reach & 0xC000); - int b = (neigh->reach & 0x3000); + int a = CHECK_FLAG(neigh->reach, 0xC000); + int b = CHECK_FLAG(neigh->reach, 0x3000); if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) { /* Reachability is either 1100 or 0011 */ send_self_update(neigh->ifp); } } - if((neigh->reach & 0xFC00) == 0xC000) { + if(CHECK_FLAG(neigh->reach, 0xFC00) == 0xC000) { /* This is a newish neighbour, let's request a full route dump. We ought to avoid this when the network is dense */ send_unicast_request(neigh, NULL, 0); @@ -188,8 +185,7 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval) return rc; } -static int -reset_txcost(struct neighbour *neigh) +static int reset_txcost(struct neighbour *neigh) { unsigned delay; @@ -199,9 +195,8 @@ reset_txcost(struct neighbour *neigh) return 0; /* If we're losing a lot of packets, we probably lost an IHU too */ - if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 || - (neigh->ihu_interval > 0 && - delay >= neigh->ihu_interval * 10U * 10U)) { + if (delay >= 180000 || CHECK_FLAG(neigh->reach, 0xFFF0) == 0 || + (neigh->ihu_interval > 0 && delay >= neigh->ihu_interval * 10U * 10U)) { neigh->txcost = INFINITY; neigh->ihu_time = babel_now; return 1; @@ -210,14 +205,12 @@ reset_txcost(struct neighbour *neigh) return 0; } -unsigned -neighbour_txcost(struct neighbour *neigh) +unsigned neighbour_txcost(struct neighbour *neigh) { return neigh->txcost; } -unsigned -check_neighbours(void) +unsigned check_neighbours(void) { struct neighbour *neigh; int changed, rc; @@ -253,21 +246,20 @@ check_neighbours(void) return msecs; } -unsigned -neighbour_rxcost(struct neighbour *neigh) +unsigned neighbour_rxcost(struct neighbour *neigh) { unsigned delay; unsigned short reach = neigh->reach; delay = timeval_minus_msec(&babel_now, &neigh->hello_time); - if((reach & 0xFFF0) == 0 || delay >= 180000) { + if(CHECK_FLAG(reach, 0xFFF0) == 0 || delay >= 180000) { return INFINITY; - } else if(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) { + } else if (CHECK_FLAG(babel_get_if_nfo(neigh->ifp)->flags, BABEL_IF_LQ)) { int sreach = - ((reach & 0x8000) >> 2) + - ((reach & 0x4000) >> 1) + - (reach & 0x3FFF); + (CHECK_FLAG(reach, 0x8000) >> 2) + + (CHECK_FLAG(reach, 0x4000) >> 1) + + CHECK_FLAG(reach, 0x3FFF); /* 0 <= sreach <= 0x7FFF */ int cost = (0x8000 * babel_get_if_nfo(neigh->ifp)->cost) / (sreach + 1); /* cost >= interface->cost */ @@ -276,19 +268,18 @@ neighbour_rxcost(struct neighbour *neigh) return MIN(cost, INFINITY); } else { /* To lose one hello is a misfortune, to lose two is carelessness. */ - if((reach & 0xC000) == 0xC000) + if (CHECK_FLAG(reach, 0xC000) == 0xC000) return babel_get_if_nfo(neigh->ifp)->cost; - else if((reach & 0xC000) == 0) + else if (CHECK_FLAG(reach, 0xC000) == 0) return INFINITY; - else if((reach & 0x2000)) + else if (CHECK_FLAG(reach, 0x2000)) return babel_get_if_nfo(neigh->ifp)->cost; else return INFINITY; } } -unsigned -neighbour_rttcost(struct neighbour *neigh) +unsigned neighbour_rttcost(struct neighbour *neigh) { struct interface *ifp = neigh->ifp; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); @@ -304,15 +295,14 @@ neighbour_rttcost(struct neighbour *neigh) (unsigned long long)babel_ifp->max_rtt_penalty * (neigh->rtt - babel_ifp->rtt_min) / (babel_ifp->rtt_max - babel_ifp->rtt_min); - assert((tmp & 0x7FFFFFFF) == tmp); + assert(CHECK_FLAG(tmp, 0x7FFFFFFF) == tmp); return tmp; } else { return babel_ifp->max_rtt_penalty; } } -unsigned -neighbour_cost(struct neighbour *neigh) +unsigned neighbour_cost(struct neighbour *neigh) { unsigned a, b, cost; @@ -328,7 +318,7 @@ neighbour_cost(struct neighbour *neigh) if(b >= INFINITY) return INFINITY; - if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) + if (!CHECK_FLAG(babel_get_if_nfo(neigh->ifp)->flags, BABEL_IF_LQ) || (a < 256 && b < 256)) { cost = a; } else { @@ -347,8 +337,7 @@ neighbour_cost(struct neighbour *neigh) return MIN(cost, INFINITY); } -int -valid_rtt(struct neighbour *neigh) +int valid_rtt(struct neighbour *neigh) { return (timeval_minus_msec(&babel_now, &neigh->rtt_time) < 180000) ? 1 : 0; } diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h index d562000e30..b19e63c946 100644 --- a/bgpd/bgp_addpath.h +++ b/bgpd/bgp_addpath.h @@ -21,6 +21,12 @@ struct bgp_addpath_capability { uint8_t flags; }; +struct bgp_paths_limit_capability { + uint16_t afi; + uint8_t safi; + uint16_t paths_limit; +}; + #define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1 void bgp_addpath_init_bgp_data(struct bgp_addpath_bgp_data *d); diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index ebfc7d087d..2a831c3a55 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -65,6 +65,14 @@ struct aspath { #define ASPATH_STR_DEFAULT_LEN 32 +/* `set as-path exclude ASn' */ +struct aspath_exclude { + struct aspath *aspath; + bool exclude_all; + char *exclude_aspath_acl_name; + struct as_list *exclude_aspath_acl; +}; + /* Prototypes. */ extern void aspath_init(void); extern void aspath_finish(void); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index edfbc6c835..0dec8ea4e4 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2347,6 +2347,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_ifindex = peer->nexthop.ifp->ifindex; + if (if_is_operative(peer->nexthop.ifp)) + SET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); } break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: @@ -2364,6 +2370,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_ifindex = peer->nexthop.ifp->ifindex; + if (if_is_operative(peer->nexthop.ifp)) + SET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); } if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index d78f04c6dd..5386f24a0b 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -158,6 +158,8 @@ struct attr { uint8_t nh_flags; #define BGP_ATTR_NH_VALID 0x01 +#define BGP_ATTR_NH_IF_OPERSTATE 0x02 +#define BGP_ATTR_NH_MP_PREFER_GLOBAL 0x04 /* MP Nexthop preference */ /* Path origin attribute */ uint8_t origin; @@ -254,9 +256,6 @@ struct attr { /* MP Nexthop length */ uint8_t mp_nexthop_len; - /* MP Nexthop preference */ - uint8_t mp_nexthop_prefer_global; - /* Static MAC for EVPN */ uint8_t sticky; diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index ad541b67ad..a85117965a 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -205,8 +205,17 @@ static struct as_list *as_list_new(void) static void as_list_free(struct as_list *aslist) { - XFREE(MTYPE_AS_STR, aslist->name); - XFREE(MTYPE_AS_LIST, aslist); + struct aspath_exclude_list *cur_bp = aslist->exclude_list; + struct aspath_exclude_list *next_bp = NULL; + + while (cur_bp) { + next_bp = cur_bp->next; + XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_bp); + cur_bp = next_bp; + } + + XFREE (MTYPE_AS_STR, aslist->name); + XFREE (MTYPE_AS_LIST, aslist); } /* Insert new AS list to list of as_list. Each as_list is sorted by @@ -290,6 +299,7 @@ static void as_list_delete(struct as_list *aslist) { struct as_list_list *list; struct as_filter *filter, *next; + struct aspath_exclude_list *cur_bp; for (filter = aslist->head; filter; filter = next) { next = filter->next; @@ -308,6 +318,12 @@ static void as_list_delete(struct as_list *aslist) else list->head = aslist->next; + cur_bp = aslist->exclude_list; + while (cur_bp) { + cur_bp->bp_as_excl->exclude_aspath_acl = NULL; + cur_bp = cur_bp->next; + } + as_list_free(aslist); } diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h index 1890fd3d96..2d9f07ce84 100644 --- a/bgpd/bgp_filter.h +++ b/bgpd/bgp_filter.h @@ -25,6 +25,11 @@ struct as_filter { int64_t seq; }; +struct aspath_exclude_list { + struct aspath_exclude_list *next; + struct aspath_exclude *bp_as_excl; +}; + /* AS path filter list. */ struct as_list { char *name; @@ -34,6 +39,7 @@ struct as_list { struct as_filter *head; struct as_filter *tail; + struct aspath_exclude_list *exclude_list; }; diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 234dbb0715..657c7e22d7 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -260,6 +260,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) peer->afc_recv[afi][safi] = from_peer->afc_recv[afi][safi]; peer->orf_plist[afi][safi] = from_peer->orf_plist[afi][safi]; peer->llgr[afi][safi] = from_peer->llgr[afi][safi]; + peer->addpath_paths_limit[afi][safi] = + from_peer->addpath_paths_limit[afi][safi]; } if (bgp_getsockname(peer) < 0) { diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index c773c21fb7..296e64003d 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -129,15 +129,19 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, &bpi2->attr->mp_nexthop_global); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - addr1 = (bpi1->attr->mp_nexthop_prefer_global) + addr1 = (CHECK_FLAG(bpi1->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) ? bpi1->attr->mp_nexthop_global : bpi1->attr->mp_nexthop_local; - addr2 = (bpi2->attr->mp_nexthop_prefer_global) + addr2 = (CHECK_FLAG(bpi2->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) ? bpi2->attr->mp_nexthop_global : bpi2->attr->mp_nexthop_local; - if (!bpi1->attr->mp_nexthop_prefer_global - && !bpi2->attr->mp_nexthop_prefer_global) + if (!CHECK_FLAG(bpi1->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL) && + !CHECK_FLAG(bpi2->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) compare = !bgp_interface_same( bpi1->peer->ifp, bpi2->peer->ifp); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index cd5cf5be54..91bc3b1a88 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -2093,8 +2093,9 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ struct bgp_path_info *bpi; int origin_local = 0; struct bgp *src_vrf; - struct interface *ifp; + struct interface *ifp = NULL; char rd_buf[RD_ADDRSTRLEN]; + int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) { @@ -2260,6 +2261,15 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ break; } + if (!ifp && static_attr.nh_ifindex) + ifp = if_lookup_by_index(static_attr.nh_ifindex, + src_vrf->vrf_id); + + if (ifp && if_is_operative(ifp)) + SET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + /* * route map handling */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index e2c103bb52..884fabf077 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -116,24 +116,36 @@ static int bgp_isvalid_nexthop_for_mplsovergre(struct bgp_nexthop_cache *bnc, static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc, struct bgp_path_info *path) { + return (bnc && (bnc->nexthop_num > 0 && + (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) || + CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) || + bgp_isvalid_nexthop_for_ebgp(bnc, path) || + bgp_isvalid_nexthop_for_mplsovergre(bnc, path)))); +} + +static bool bgp_isvalid_nexthop_for_l3vpn(struct bgp_nexthop_cache *bnc, + struct bgp_path_info *path) +{ + if (bgp_zebra_num_connects() == 0) + return 1; + + if (path->attr->srv6_l3vpn || path->attr->srv6_vpn) { + /* In the case of SRv6-VPN, we need to track the reachability to the + * SID (in other words, IPv6 address). We check that the SID is + * available in the BGP update; then if it is available, we check + * for the nexthop reachability. + */ + if (bnc && (bnc->nexthop_num > 0 && bgp_isvalid_nexthop(bnc))) + return 1; + return 0; + } /* - * - In the case of MPLS-VPN, the label is learned from LDP or other + * In the case of MPLS-VPN, the label is learned from LDP or other * protocols, and nexthop tracking is enabled for the label. * The value is recorded as BGP_NEXTHOP_LABELED_VALID. - * - In the case of SRv6-VPN, we need to track the reachability to the - * SID (in other words, IPv6 address). As in MPLS, we need to record - * the value as BGP_NEXTHOP_SID_VALID. However, this function is - * currently not implemented, and this function assumes that all - * Transit routes for SRv6-VPN are valid. * - Otherwise check for mpls-gre acceptance */ - return (bgp_zebra_num_connects() == 0 || - (bnc && (bnc->nexthop_num > 0 && - (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) || - CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) || - bnc->bgp->srv6_enabled || - bgp_isvalid_nexthop_for_ebgp(bnc, path) || - bgp_isvalid_nexthop_for_mplsovergre(bnc, path))))); + return bgp_isvalid_nexthop_for_mpls(bnc, path); } static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) @@ -496,7 +508,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, else if (safi == SAFI_UNICAST && pi && pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra && pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop) - return bgp_isvalid_nexthop_for_mpls(bnc, pi); + return bgp_isvalid_nexthop_for_l3vpn(bnc, pi); else if (safi == SAFI_MPLS_VPN && pi && pi->sub_type != BGP_ROUTE_IMPORTED) /* avoid not redistributing mpls vpn routes */ @@ -1045,8 +1057,11 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) break; case AFI_IP6: p->family = AF_INET6; - - if (is_bgp_static) { + if (pi->attr && pi->attr->srv6_l3vpn) { + IPV6_ADDR_COPY(&(p->u.prefix6), + &(pi->attr->srv6_l3vpn->sid)); + p->prefixlen = IPV6_MAX_BITLEN; + } else if (is_bgp_static) { p->u.prefix6 = p_orig->u.prefix6; p->prefixlen = p_orig->prefixlen; } else { @@ -1065,7 +1080,8 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) */ else if (pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { - if (pi->attr->mp_nexthop_prefer_global) + if (CHECK_FLAG(pi->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) p->u.prefix6 = pi->attr->mp_nexthop_global; else @@ -1294,8 +1310,9 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc) && (path->attr->evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP)) { bnc_is_valid_nexthop = - bgp_isvalid_nexthop_for_mpls(bnc, path) ? true - : false; + bgp_isvalid_nexthop_for_l3vpn(bnc, path) + ? true + : false; } else if (safi == SAFI_MPLS_VPN && path->sub_type != BGP_ROUTE_IMPORTED) { /* avoid not redistributing mpls vpn routes */ diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 43a59e2448..aa1d81362b 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -42,6 +42,7 @@ const struct message capcode_str[] = { { CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart" }, { CAPABILITY_CODE_ROLE, "Role" }, { CAPABILITY_CODE_SOFT_VERSION, "Software Version" }, + { CAPABILITY_CODE_PATHS_LIMIT, "Paths-Limit" }, { 0 } }; @@ -61,6 +62,7 @@ static const size_t cap_minsizes[] = { [CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN, [CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN, [CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN, + [CAPABILITY_CODE_PATHS_LIMIT] = CAPABILITY_CODE_PATHS_LIMIT_LEN, }; /* value the capability must be a multiple of. @@ -83,6 +85,7 @@ static const size_t cap_modsizes[] = { [CAPABILITY_CODE_LLGR] = 1, [CAPABILITY_CODE_ROLE] = 1, [CAPABILITY_CODE_SOFT_VERSION] = 1, + [CAPABILITY_CODE_PATHS_LIMIT] = 5, }; /* BGP-4 Multiprotocol Extentions lead us to the complex world. We can @@ -739,6 +742,62 @@ static int bgp_capability_addpath(struct peer *peer, return 0; } +static int bgp_capability_paths_limit(struct peer *peer, + struct capability_header *hdr) +{ + struct stream *s = BGP_INPUT(peer); + size_t end = stream_get_getp(s) + hdr->length; + + if (hdr->length % CAPABILITY_CODE_PATHS_LIMIT_LEN) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Paths-Limit: Received invalid length %d, non-multiple of %d", + hdr->length, CAPABILITY_CODE_PATHS_LIMIT_LEN); + return -1; + } + + if (!CHECK_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV)) { + flog_warn(EC_BGP_CAPABILITY_INVALID_DATA, + "Paths-Limit: Received Paths-Limit capability without Add-Path capability"); + return -1; + } + + SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV); + + while (stream_get_getp(s) + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) { + afi_t afi; + safi_t safi; + iana_afi_t pkt_afi = stream_getw(s); + iana_safi_t pkt_safi = stream_getc(s); + uint16_t paths_limit = stream_getw(s); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u", + peer->host, + lookup_msg(capcode_str, hdr->code, NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), paths_limit); + + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + continue; + } else if (!peer->afc[afi][safi]) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + continue; + } + + SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_RCV); + peer->addpath_paths_limit[afi][safi].receive = paths_limit; + } + + return 0; +} + static int bgp_capability_enhe(struct peer *peer, struct capability_header *hdr) { struct stream *s = BGP_INPUT(peer); @@ -1012,6 +1071,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_EXT_MESSAGE: case CAPABILITY_CODE_ROLE: case CAPABILITY_CODE_SOFT_VERSION: + case CAPABILITY_CODE_PATHS_LIMIT: /* Check length. */ if (caphdr.length < cap_minsizes[caphdr.code]) { zlog_info( @@ -1113,6 +1173,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_SOFT_VERSION: ret = bgp_capability_software_version(peer, &caphdr); break; + case CAPABILITY_CODE_PATHS_LIMIT: + ret = bgp_capability_paths_limit(peer, &caphdr); + break; default: if (caphdr.code > 128) { /* We don't send Notification for unknown vendor @@ -1874,6 +1937,31 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, } } + /* Paths-Limit capability */ + SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV); + stream_putc(s, BGP_OPEN_OPT_CAP); + ext_opt_params ? stream_putw(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN * + afi_safi_count) + + 2) + : stream_putc(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN * + afi_safi_count) + + 2); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN * afi_safi_count); + + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); + + stream_putw(s, pkt_afi); + stream_putc(s, pkt_safi); + stream_putw(s, peer->addpath_paths_limit[afi][safi].send); + + SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_ADV); + } + /* ORF capability. */ FOREACH_AFI_SAFI (afi, safi) { if (CHECK_FLAG(peer->af_flags[afi][safi], diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 34f4b7619e..a01e49ceba 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -53,6 +53,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */ #define CAPABILITY_CODE_EXT_MESSAGE 6 /* Extended Message Support */ #define CAPABILITY_CODE_ROLE 9 /* Role Capability */ +#define CAPABILITY_CODE_PATHS_LIMIT 76 /* Paths Limit Capability */ /* Capability Length */ #define CAPABILITY_CODE_MP_LEN 4 @@ -61,6 +62,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_RESTART_LEN 2 /* Receiving only case */ #define CAPABILITY_CODE_AS4_LEN 4 #define CAPABILITY_CODE_ADDPATH_LEN 4 +#define CAPABILITY_CODE_PATHS_LIMIT_LEN 5 #define CAPABILITY_CODE_ENHE_LEN 6 /* NRLI AFI = 2, SAFI = 2, Nexthop AFI = 2 */ #define CAPABILITY_CODE_MIN_FQDN_LEN 2 #define CAPABILITY_CODE_ENHANCED_LEN 0 diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 9d484d901a..da352a8441 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1224,7 +1224,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, if (!peer_established(peer->connection)) return; - if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) && + if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) || !CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) return; @@ -1462,6 +1462,49 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, iana_safi2str(pkt_safi)); break; + case CAPABILITY_CODE_PATHS_LIMIT: + SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV); + + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + addpath_afi_safi_count++; + } + + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN * + addpath_afi_safi_count); + + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, + &pkt_safi); + + stream_putw(s, pkt_afi); + stream_putc(s, pkt_safi); + stream_putw(s, + peer->addpath_paths_limit[afi][safi].send); + + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s, limit: %u", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), + peer->addpath_paths_limit[afi][safi] + .send); + } + + break; case CAPABILITY_CODE_ORF: /* Convert AFI, SAFI to values for packet. */ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); @@ -3170,6 +3213,85 @@ ignore: } } +static void bgp_dynamic_capability_paths_limit(uint8_t *pnt, int action, + struct capability_header *hdr, + struct peer *peer) +{ + uint8_t *data = pnt + 3; + uint8_t *end = data + hdr->length; + size_t len = end - data; + afi_t afi; + safi_t safi; + + if (action == CAPABILITY_ACTION_SET) { + if (len % CAPABILITY_CODE_PATHS_LIMIT_LEN) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Paths-Limit: Received invalid length %zu, non-multiple of %d", + len, CAPABILITY_CODE_PATHS_LIMIT_LEN); + return; + } + + if (!CHECK_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV)) { + flog_warn(EC_BGP_CAPABILITY_INVALID_DATA, + "Paths-Limit: Received Paths-Limit capability without Add-Path capability"); + goto ignore; + } + + SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV); + + while (data + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) { + afi_t afi; + safi_t safi; + iana_afi_t pkt_afi; + iana_safi_t pkt_safi; + struct bgp_paths_limit_capability bpl = {}; + + memcpy(&bpl, data, sizeof(bpl)); + pkt_afi = ntohs(bpl.afi); + pkt_safi = safi_int2iana(bpl.safi); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u", + peer->host, + lookup_msg(capcode_str, hdr->code, + NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), + bpl.paths_limit); + + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, + &safi)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + goto ignore; + } else if (!peer->afc[afi][safi]) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + goto ignore; + } + + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV); + peer->addpath_paths_limit[afi][safi].receive = + bpl.paths_limit; +ignore: + data += CAPABILITY_CODE_PATHS_LIMIT_LEN; + } + } else { + FOREACH_AFI_SAFI (afi, safi) + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV); + + UNSET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV); + } +} + static void bgp_dynamic_capability_orf(uint8_t *pnt, int action, struct capability_header *hdr, struct peer *peer) @@ -3723,6 +3845,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, case CAPABILITY_CODE_ADDPATH: bgp_dynamic_capability_addpath(pnt, action, hdr, peer); break; + case CAPABILITY_CODE_PATHS_LIMIT: + bgp_dynamic_capability_paths_limit(pnt, action, hdr, + peer); + break; case CAPABILITY_CODE_ORF: bgp_dynamic_capability_orf(pnt, action, hdr, peer); break; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f0c5de074d..c61ffbd558 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8569,6 +8569,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, afi_t afi; route_map_result_t ret; struct bgp_redist *red; + struct interface *ifp; if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) || bgp->peer_self == NULL) @@ -8628,6 +8629,11 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, } attr.nh_type = nhtype; attr.nh_ifindex = ifindex; + ifp = if_lookup_by_index(ifindex, bgp->vrf_id); + if (ifp && if_is_operative(ifp)) + SET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); attr.med = metric; attr.distance = distance; @@ -9317,9 +9323,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, "link-local"); if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global, - &attr->mp_nexthop_local) - != 0) - && !attr->mp_nexthop_prefer_global) + &attr->mp_nexthop_local) != + 0) && + !CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) json_object_boolean_true_add( json_nexthop_ll, "used"); else @@ -9331,10 +9338,11 @@ void route_vty_out(struct vty *vty, const struct prefix *p, } else { /* Display LL if LL/Global both in table unless * prefer-global is set */ - if (((attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - && !attr->mp_nexthop_prefer_global) - || (path->peer->conf_if)) { + if (((attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) && + !CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) || + (path->peer->conf_if)) { if (path->peer->conf_if) { len = vty_out(vty, "%s", path->peer->conf_if); @@ -10582,7 +10590,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object_boolean_true_add(json_nexthop_ll, "accessible"); - if (!attr->mp_nexthop_prefer_global) + if (!CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) json_object_boolean_true_add(json_nexthop_ll, "used"); else @@ -10592,7 +10601,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, " (%s) %s\n", inet_ntop(AF_INET6, &attr->mp_nexthop_local, buf, INET6_ADDRSTRLEN), - attr->mp_nexthop_prefer_global + CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL) ? "(prefer-global)" : "(used)"); } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 36e04c5e68..a091b67680 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2323,17 +2323,10 @@ static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = { route_set_aspath_prepend_free, }; -/* `set as-path exclude ASn' */ -struct aspath_exclude { - struct aspath *aspath; - bool exclude_all; - char *exclude_aspath_acl_name; - struct as_list *exclude_aspath_acl; -}; - static void *route_aspath_exclude_compile(const char *arg) { struct aspath_exclude *ase; + struct aspath_exclude_list *ael; const char *str = arg; static const char asp_acl[] = "as-path-access-list"; @@ -2348,16 +2341,41 @@ static void *route_aspath_exclude_compile(const char *arg) ase->exclude_aspath_acl = as_list_lookup(str); } else ase->aspath = aspath_str2aspath(str, bgp_get_asnotation(NULL)); + + if (ase->exclude_aspath_acl) { + ael = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, + sizeof(struct aspath_exclude_list)); + ael->bp_as_excl = ase; + ael->next = ase->exclude_aspath_acl->exclude_list; + ase->exclude_aspath_acl->exclude_list = ael; + } + return ase; } static void route_aspath_exclude_free(void *rule) { struct aspath_exclude *ase = rule; + struct aspath_exclude_list *cur_ael = NULL; + struct aspath_exclude_list *prev_ael = NULL; aspath_free(ase->aspath); if (ase->exclude_aspath_acl_name) XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name); + if (ase->exclude_aspath_acl) + cur_ael = ase->exclude_aspath_acl->exclude_list; + while (cur_ael) { + if (cur_ael->bp_as_excl == ase) { + if (prev_ael) + prev_ael->next = cur_ael->next; + else + ase->exclude_aspath_acl->exclude_list = NULL; + XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_ael); + break; + } + prev_ael = cur_ael; + cur_ael = cur_ael->next; + } XFREE(MTYPE_ROUTE_MAP_COMPILED, ase); } @@ -3935,11 +3953,11 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix, if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN) || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) { /* Set next hop preference to global */ - path->attr->mp_nexthop_prefer_global = true; + SET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL); SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); } else { - path->attr->mp_nexthop_prefer_global = false; + UNSET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL); SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); } diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c index abebfe5155..096502aaa9 100644 --- a/bgpd/bgp_routemap_nb.c +++ b/bgpd/bgp_routemap_nb.c @@ -147,6 +147,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list", .cbs = { + .create = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy, .apply_finish = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish, } }, @@ -154,7 +156,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name", .cbs = { .modify = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify, - .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy, } }, { @@ -356,6 +357,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator", .cbs = { + .create = lib_route_map_entry_set_action_rmap_set_action_aggregator_create, + .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy, .apply_finish = lib_route_map_entry_set_action_rmap_set_action_aggregator_finish, } }, @@ -363,14 +366,12 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-asn", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy, } }, { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy, } }, { @@ -390,6 +391,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb", .cbs = { + .create = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create, + .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy, .apply_finish = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish, } }, @@ -397,7 +400,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/lb-type", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy, } }, { @@ -418,7 +420,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/two-octet-as-specific", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy, } }, { diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h index 28e4188026..d7f0cea30e 100644 --- a/bgpd/bgp_routemap_nb.h +++ b/bgpd/bgp_routemap_nb.h @@ -60,9 +60,12 @@ int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_mod int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create( + struct nb_cb_create_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy( + struct nb_cb_destroy_args *args); void lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish(struct nb_cb_apply_finish_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify( @@ -127,24 +130,28 @@ int lib_route_map_entry_set_action_rmap_set_action_large_community_none_modify(s int lib_route_map_entry_set_action_rmap_set_action_large_community_none_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_large_community_string_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_aggregator_create( + struct nb_cb_create_args *args); +int lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy( + struct nb_cb_destroy_args *args); void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish(struct nb_cb_apply_finish_args *args); int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create( + struct nb_cb_create_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy( + struct nb_cb_destroy_args *args); void lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(struct nb_cb_apply_finish_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_modify( struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_destroy( diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index d6fcb6b8dc..c1d6ee12e1 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -1121,6 +1121,27 @@ lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_des /* * XPath = /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list */ +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create( + struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + void lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish( struct nb_cb_apply_finish_args *args) @@ -1211,23 +1232,6 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam return NB_OK; } -int -lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy( - struct nb_cb_destroy_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); - } - - return NB_OK; - -} - /* * XPath: * /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any @@ -1253,9 +1257,8 @@ int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: - break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + break; } return NB_OK; @@ -1287,9 +1290,8 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: - break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + break; } return NB_OK; @@ -2735,6 +2737,27 @@ lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy( * xpath = * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator */ +int lib_route_map_entry_set_action_rmap_set_action_aggregator_create( + struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish( struct nb_cb_apply_finish_args *args) { @@ -2799,22 +2822,6 @@ lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify( return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy( - struct nb_cb_destroy_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - return lib_route_map_entry_set_destroy(args); - } - - return NB_OK; -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address @@ -2834,22 +2841,6 @@ lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_mod return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy( - struct nb_cb_destroy_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - return lib_route_map_entry_set_destroy(args); - } - - return NB_OK; -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:comm-list-name @@ -2918,6 +2909,27 @@ lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy( * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb */ +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create( + struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + void lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish( struct nb_cb_apply_finish_args *args) @@ -2973,13 +2985,6 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify( return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_set_destroy(args); -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/bandwidth @@ -2995,7 +3000,7 @@ int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy( struct nb_cb_destroy_args *args) { - return lib_route_map_entry_set_destroy(args); + return NB_OK; } /* @@ -3061,13 +3066,6 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_spec return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_set_destroy(args); -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-none diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c index 0c8ed33d43..70369104a2 100644 --- a/bgpd/bgp_snmp_bgp4v2.c +++ b/bgpd/bgp_snmp_bgp4v2.c @@ -853,7 +853,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], case BGP_ATTR_NHLEN_IPV6_GLOBAL: return SNMP_INTEGER(2); case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - if (path->attr->mp_nexthop_prefer_global) + if (CHECK_FLAG(path->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) return SNMP_INTEGER(2); else return SNMP_INTEGER(4); @@ -867,7 +868,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], case BGP_ATTR_NHLEN_IPV6_GLOBAL: return SNMP_IP6ADDRESS(path->attr->mp_nexthop_global); case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - if (path->attr->mp_nexthop_prefer_global) + if (CHECK_FLAG(path->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) return SNMP_IP6ADDRESS( path->attr->mp_nexthop_global); else diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index d13515af6f..c522865eba 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -145,6 +145,8 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, dst->addpath_type[afi][safi] = src->addpath_type[afi][safi]; dst->addpath_best_selected[afi][safi] = src->addpath_best_selected[afi][safi]; + dst->addpath_paths_limit[afi][safi] = + src->addpath_paths_limit[afi][safi]; dst->local_as = src->local_as; dst->change_local_as = src->change_local_as; dst->shared_network = src->shared_network; @@ -348,6 +350,8 @@ static unsigned int updgrp_hash_key_make(const void *p) key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key); key = jhash_1word((uint32_t)peer->addpath_type[afi][safi], key); key = jhash_1word(peer->addpath_best_selected[afi][safi], key); + key = jhash_1word(peer->addpath_paths_limit[afi][safi].receive, key); + key = jhash_1word(peer->addpath_paths_limit[afi][safi].send, key); key = jhash_1word((peer->cap & PEER_UPDGRP_CAP_FLAGS), key); key = jhash_1word((peer->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS), key); @@ -461,6 +465,9 @@ static unsigned int updgrp_hash_key_make(const void *p) PEER_UPDGRP_AF_CAP_FLAGS), peer->v_routeadv, peer->change_local_as, peer->as_path_loop_detection); + zlog_debug("%pBP Update Group Hash: addpath paths-limit: (send %u, receive %u)", + peer, peer->addpath_paths_limit[afi][safi].send, + peer->addpath_paths_limit[afi][safi].receive); zlog_debug( "%pBP Update Group Hash: max packet size: %u pmax_out: %u Peer Group: %s rmap out: %s", peer, peer->max_packet_size, peer->pmax_out[afi][safi], diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 7ecebe3020..cc039e3e11 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -97,13 +97,19 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest, enum bgp_path_selection_reason reason; char pfx_buf[PREFIX2STR_BUFFER] = {}; int paths_eq = 0; - int best_path_count = 0; struct list *list = list_new(); struct bgp_path_info *pi = NULL; + uint16_t paths_count = 0; + uint16_t paths_limit = peer->addpath_paths_limit[afi][safi].receive; if (peer->addpath_type[afi][safi] == BGP_ADDPATH_BEST_SELECTED) { - while (best_path_count++ < - peer->addpath_best_selected[afi][safi]) { + paths_limit = + paths_limit + ? MIN(paths_limit, + peer->addpath_best_selected[afi][safi]) + : peer->addpath_best_selected[afi][safi]; + + while (paths_count++ < paths_limit) { struct bgp_path_info *exist = NULL; for (pi = bgp_dest_get_bgp_path_info(dest); pi; @@ -139,8 +145,26 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest, subgroup_process_announce_selected( subgrp, NULL, dest, afi, safi, id); } else { - subgroup_process_announce_selected(subgrp, pi, dest, - afi, safi, id); + /* No Paths-Limit involved */ + if (!paths_limit) { + subgroup_process_announce_selected(subgrp, pi, + dest, afi, + safi, id); + continue; + } + + /* If we have Paths-Limit capability, we MUST + * not send more than the number of paths expected + * by the peer. + */ + if (paths_count++ < paths_limit) + subgroup_process_announce_selected(subgrp, pi, + dest, afi, + safi, id); + else + subgroup_process_announce_selected(subgrp, NULL, + dest, afi, + safi, id); } } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 31524e2221..efc71bc8a7 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9198,6 +9198,63 @@ DEFPY( return CMD_SUCCESS; } +DEFPY (neighbor_addpath_paths_limit, + neighbor_addpath_paths_limit_cmd, + "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-rx-paths-limit (1-65535)$paths_limit", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Paths Limit for Addpath to receive from the peer\n" + "Maximum number of paths\n") +{ + struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); + int ret; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + ret = peer_af_flag_set_vty(vty, neighbor, afi, safi, + PEER_FLAG_ADDPATH_RX_PATHS_LIMIT); + + peer->addpath_paths_limit[afi][safi].send = paths_limit; + + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT, + CAPABILITY_ACTION_SET); + + return ret; +} + +DEFPY (no_neighbor_addpath_paths_limit, + no_neighbor_addpath_paths_limit_cmd, + "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-rx-paths-limit [(1-65535)]", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Paths Limit for Addpath to receive from the peer\n" + "Maximum number of paths\n") +{ + struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); + int ret; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + ret = peer_af_flag_unset_vty(vty, neighbor, afi, safi, + PEER_FLAG_ADDPATH_RX_PATHS_LIMIT); + + peer->addpath_paths_limit[afi][safi].send = 0; + + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT, + CAPABILITY_ACTION_UNSET); + + return ret; +} + DEFPY( no_neighbor_aspath_loop_detection, no_neighbor_aspath_loop_detection_cmd, @@ -14146,6 +14203,86 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_add); } + /* Paths-Limit */ + if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) { + json_object *json_add = NULL; + const char *print_store; + + json_add = json_object_new_object(); + + FOREACH_AFI_SAFI (afi, safi) { + json_object *json_sub = NULL; + + json_sub = json_object_new_object(); + print_store = get_afi_safi_str(afi, safi, + true); + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) && + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + json_object_boolean_true_add( + json_sub, + "advertisedAndReceived"); + json_object_int_add( + json_sub, + "advertisedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .send); + json_object_int_add( + json_sub, + "receivedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .receive); + } else if (CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_PATHS_LIMIT_AF_ADV)) { + json_object_boolean_true_add( + json_sub, + "advertised"); + json_object_int_add( + json_sub, + "advertisedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .send); + } else if (CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + json_object_boolean_true_add( + json_sub, + "received"); + json_object_int_add( + json_sub, + "receivedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .receive); + } + } + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) + json_object_object_add(json_add, + print_store, + json_sub); + else + json_object_free(json_sub); + } + + json_object_object_add(json_cap, "pathsLimit", + json_add); + } + /* Dynamic */ if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) || CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) { @@ -14599,6 +14736,47 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, } } + /* Paths-Limit */ + if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) { + vty_out(vty, " Paths-Limit:\n"); + + FOREACH_AFI_SAFI (afi, safi) { + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + vty_out(vty, " %s: ", + get_afi_safi_str(afi, + safi, + false)); + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV)) + vty_out(vty, + "advertised (%u)", + p->addpath_paths_limit + [afi][safi] + .send); + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) + vty_out(vty, + "%sreceived (%u)", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) + ? " and " + : "", + p->addpath_paths_limit + [afi][safi] + .receive); + + vty_out(vty, "\n"); + } + } + } + /* Dynamic */ if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) || CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) { @@ -18383,6 +18561,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DISABLE_ADDPATH_RX)) vty_out(vty, " neighbor %s disable-addpath-rx\n", addr); + if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ADDPATH_RX_PATHS_LIMIT)) + vty_out(vty, " neighbor %s addpath-rx-paths-limit %u\n", addr, + peer->addpath_paths_limit[afi][safi].send); + /* ORF capability. */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) || peergroup_af_flag_check(peer, afi, safi, @@ -20544,6 +20727,26 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd); + /* "neighbor addpath-rx-paths-limit" commands.*/ + install_element(BGP_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4M_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4M_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4L_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4L_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6M_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6M_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6L_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6L_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV4_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV4_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV6_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_paths_limit_cmd); + /* "neighbor sender-as-path-loop-detection" commands. */ install_element(BGP_NODE, &neighbor_aspath_loop_detection_cmd); install_element(BGP_NODE, &no_neighbor_aspath_loop_detection_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 1172514e52..26194f8601 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -235,6 +235,14 @@ static int bgp_ifp_up(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_up(ifp); + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -282,6 +290,14 @@ static int bgp_ifp_down(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_down(ifp); + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -927,7 +943,8 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex) || path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { /* Check if route-map is set to prefer global over link-local */ - if (path->attr->mp_nexthop_prefer_global) { + if (CHECK_FLAG(path->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) { nexthop = &path->attr->mp_nexthop_global; if (IN6_IS_ADDR_LINKLOCAL(nexthop)) *ifindex = path->attr->nh_ifindex; @@ -3144,6 +3161,15 @@ static int bgp_ifp_create(struct interface *ifp) bgp_update_interface_nbrs(bgp, ifp, ifp); hook_call(bgp_vrf_status_changed, bgp, ifp); + + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 8fc52652a2..e7712f0f3e 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1527,6 +1527,8 @@ struct peer *peer_new(struct bgp *bgp) PEER_FLAG_SEND_LARGE_COMMUNITY); peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE; peer->addpath_best_selected[afi][safi] = 0; + peer->addpath_paths_limit[afi][safi].receive = 0; + peer->addpath_paths_limit[afi][safi].send = 0; peer->soo[afi][safi] = NULL; } @@ -1620,6 +1622,8 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) peer_dst->weight[afi][safi] = peer_src->weight[afi][safi]; peer_dst->addpath_type[afi][safi] = peer_src->addpath_type[afi][safi]; + peer_dst->addpath_paths_limit[afi][safi] = + peer_src->addpath_paths_limit[afi][safi]; } for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) { @@ -4614,6 +4618,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = { {PEER_FLAG_SOO, 0, peer_change_reset}, {PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset}, {PEER_FLAG_SEND_EXT_COMMUNITY_RPKI, 1, peer_change_reset_out}, + {PEER_FLAG_ADDPATH_RX_PATHS_LIMIT, 0, peer_change_none}, {0, 0, 0}}; /* Proper action set. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 0f69095323..cf333e07cc 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1140,6 +1140,11 @@ struct llgr_info { uint8_t flags; }; +struct addpath_paths_limit { + uint16_t send; + uint16_t receive; +}; + struct peer_connection { struct peer *peer; @@ -1333,6 +1338,8 @@ struct peer { #define PEER_CAP_ROLE_RCV (1ULL << 26) /* role received */ #define PEER_CAP_SOFT_VERSION_ADV (1ULL << 27) #define PEER_CAP_SOFT_VERSION_RCV (1ULL << 28) +#define PEER_CAP_PATHS_LIMIT_ADV (1U << 29) +#define PEER_CAP_PATHS_LIMIT_RCV (1U << 30) /* Capability flags (reset in bgp_stop) */ uint32_t af_cap[AFI_MAX][SAFI_MAX]; @@ -1351,6 +1358,8 @@ struct peer { #define PEER_CAP_ENHE_AF_NEGO (1U << 14) /* Extended nexthop afi/safi negotiated */ #define PEER_CAP_LLGR_AF_ADV (1U << 15) #define PEER_CAP_LLGR_AF_RCV (1U << 16) +#define PEER_CAP_PATHS_LIMIT_AF_ADV (1U << 17) +#define PEER_CAP_PATHS_LIMIT_AF_RCV (1U << 18) /* Global configuration flags. */ /* @@ -1528,6 +1537,7 @@ struct peer { #define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 27) #define PEER_FLAG_SOO (1ULL << 28) #define PEER_FLAG_SEND_EXT_COMMUNITY_RPKI (1ULL << 29) +#define PEER_FLAG_ADDPATH_RX_PATHS_LIMIT (1ULL << 30) #define PEER_FLAG_ACCEPT_OWN (1ULL << 63) enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX]; @@ -1845,6 +1855,9 @@ struct peer { /* Add-Path Best selected paths number to advertise */ uint8_t addpath_best_selected[AFI_MAX][SAFI_MAX]; + /* Add-Path Paths-Limit */ + struct addpath_paths_limit addpath_paths_limit[AFI_MAX][SAFI_MAX]; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(peer); diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 53dc551ca3..9ae9508b02 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1780,6 +1780,17 @@ Configuring Peers Do not accept additional paths from this neighbor. +.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> addpath-rx-paths-limit (1-65535) + + Limit the maximum number of paths a BGP speaker can receive from a peer, optimizing + the transmission of BGP routes by selectively relaying pertinent routes instead of + the entire set. + + If this command is configured, the sender will only send the number of paths specified + in PATHS-LIMIT capability. + + To exchange this limit, both peers must support the PATHS-LIMIT capability. + .. clicmd:: neighbor PEER ttl-security hops NUMBER This command enforces Generalized TTL Security Mechanism (GTSM), as @@ -3196,6 +3207,31 @@ L3VPN SRv6 Specify the SRv6 locator to be used for SRv6 L3VPN. The Locator name must be set in zebra, but user can set it in any order. +L3VPN SRv6 SID reachability +--------------------------- + +In the context of IPv4 L3VPN over SRv6 specific usecase, 2001:db8:12::2 +is the peer IPv6 address of r2, and 2001:db8:2:2:: is the SRv6 SID +advertised by router r2 for prefix P. On r1, the SID reachability is +checked in order to install the prefix P. The below output indicates +that the 2001:db8:2:2:: prefix is valid. + + +.. code-block:: frr + + r1# show bgp nexthop detail + Current BGP nexthop cache: + 2001:db8:2:2:: valid [IGP metric 0], #paths 4 + gate 2001:db8:12::2, if eth0 + Last update: Tue Nov 14 10:36:28 2023 + Paths: + 1/1 192.168.2.0/24 VRF vrf10 flags 0x4018 + 1/3 192.168.2.0/24 RD 65002:10 VRF default flags 0x418 + 2001:db8:12::2 valid [IGP metric 0], #paths 0, peer 2001:db8:12::2 + if eth0 + Last update: Tue Nov 14 10:36:26 2023 + Paths: + General configuration ^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index d37dfa64c6..6e4e42b811 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -320,12 +320,12 @@ Showing ISIS information Show the ISIS database globally, for a specific LSP id without or with details. -.. clicmd:: show isis topology [level-1|level-2] [algorithm (128-255)] +.. clicmd:: show isis topology [level-1|level-2] [algorithm [(128-255)]] Show topology IS-IS paths to Intermediate Systems, globally, in area (level-1) or domain (level-2). -.. clicmd:: show isis route [level-1|level-2] [prefix-sid|backup] [algorithm (128-255)] +.. clicmd:: show isis route [level-1|level-2] [prefix-sid|backup] [algorithm [(128-255)]] Show the ISIS routing table, as determined by the most recent SPF calculation. @@ -435,7 +435,7 @@ Known limitations: clear the Node flag that is set by default for Prefix-SIDs associated to loopback addresses. This option is necessary to configure Anycast-SIDs. -.. clicmd:: show isis segment-routing node [algorithm (128-255)] +.. clicmd:: show isis segment-routing node [algorithm [(128-255)]] Show detailed information about all learned Segment Routing Nodes. diff --git a/fpm/fpm.proto b/fpm/fpm.proto index 9f0917feae..beaa5d635c 100644 --- a/fpm/fpm.proto +++ b/fpm/fpm.proto @@ -6,6 +6,9 @@ // // @author Avneesh Sachdev <avneesh@sproute.com> // +// Portions: +// Copyright (C) 2024 Carmine Scarpitta (for SRv6) +// // Permission to use, copy, modify, and/or distribute this software // for any purpose with or without fee is hereby granted, provided // that the above copyright notice and this permission notice appear @@ -72,6 +75,141 @@ message AddRoute { required int32 metric = 8; repeated Nexthop nexthops = 9; + + /* Source Address of outer encapsulating IPv6 header */ + optional qpb.Ipv6Address srv6_encap_source_address = 10; + /* SRv6 SID for VPN use cases */ + optional qpb.Ipv6Address srv6_vpn_sid = 11; +} + +/* SID Format - as per RFC 8986 section #3.1 */ +message SRv6SIDFormat +{ + /* Locator block length */ + required uint32 locator_block_length = 1; + /* Locator node length */ + required uint32 locator_node_length = 2; + /* Function length */ + required uint32 function_length = 3; + /* Argument length */ + required uint32 argument_length = 4; +} + +/* SRv6 Local SID */ +message SRv6LocalSID +{ + /* SRv6 SID value */ + required qpb.Ipv6Address sid = 1; + + /* SID Format - as per RFC 8986 section #3.1 */ + optional SRv6SIDFormat sid_format = 2; + + /* SRv6 Endpoint Behavior associated with the SID */ + oneof end_behavior + { + /* Endpoint */ + End end = 3; + /* Endpoint with L3 cross-connect */ + EndX end_x = 4; + /* Endpoint with specific IPv6 table lookup */ + EndT end_t = 5; + /* Endpoint with decapsulation and IPv6 cross-connect */ + EndDX6 end_dx6 = 7; + /* Endpoint with decapsulation and IPv4 cross-connect */ + EndDX4 end_dx4 = 8; + /* Endpoint with decapsulation and specific IPv6 table lookup */ + EndDT6 end_dt6 = 9; + /* Endpoint with decapsulation and specific IPv4 table lookup */ + EndDT4 end_dt4 = 10; + /* Endpoint with decapsulation and specific IP table lookup */ + EndDT46 end_dt46 = 11; + /* Endpoint behavior with NEXT-CSID, PSP and USD flavors */ + UN un = 12; + /* End.X behavior with NEXT-CSID, PSP and USD flavors */ + UA ua = 13; + /* End.DT6 behavior with NEXT-CSID flavor */ + UDT6 udt6 = 14; + /* End.DT4 behavior with NEXT-CSID flavor */ + UDT4 udt4 = 15; + /* End.DT46 behavior with NEXT-CSID flavor */ + UDT46 udt46 = 16; + } + + /* Endpoint */ + message End + { + } + + /* Endpoint with L3 cross-connect */ + message EndX + { + required Nexthop nexthop = 1; + } + + /* Endpoint with specific IPv6 table lookup */ + message EndT + { + required uint32 vrf_id = 1; + } + + /* Endpoint with decapsulation and IPv6 cross-connect */ + message EndDX6 + { + required Nexthop nexthop = 1; + } + + /* Endpoint with decapsulation and IPv4 cross-connect */ + message EndDX4 + { + required Nexthop nexthop = 1; + } + + /* Endpoint with decapsulation and specific IPv6 table lookup */ + message EndDT6 + { + required uint32 vrf_id = 1; + } + + /* Endpoint with decapsulation and specific IPv4 table lookup */ + message EndDT4 + { + required uint32 vrf_id = 1; + } + + /* Endpoint with decapsulation and specific IP table lookup */ + message EndDT46 + { + required uint32 vrf_id = 1; + } + + /* Endpoint behavior with NEXT-CSID, PSP and USD flavors */ + message UN + { + } + + /* End.X behavior with NEXT-CSID, PSP and USD flavors */ + message UA + { + required Nexthop nexthop = 1; + } + + /* End.DT6 behavior with NEXT-CSID flavor */ + message UDT6 + { + required uint32 vrf_id = 1; + } + + /* End.DT4 behavior with NEXT-CSID flavor */ + message UDT4 + { + required uint32 vrf_id = 1; + } + + /* End.DT46 behavior with NEXT-CSID flavor */ + message UDT46 + { + required uint32 vrf_id = 1; + } } // @@ -82,10 +220,17 @@ message Message { UNKNOWN_MSG = 0; ADD_ROUTE = 1; DELETE_ROUTE = 2; + /* Install an SRv6 Local SID */ + ADD_SRV6_LOCALSID = 3; + /* Remove an SRv6 Local SID */ + DELETE_SRV6_LOCALSID = 4; }; optional Type type = 1; optional AddRoute add_route = 2; optional DeleteRoute delete_route = 3; + + /* SRv6 Local SID */ + optional SRv6LocalSID srv6_localsid = 4; } diff --git a/fpm/fpm_pb.h b/fpm/fpm_pb.h index 7e39054d19..23d7e43993 100644 --- a/fpm/fpm_pb.h +++ b/fpm/fpm_pb.h @@ -5,6 +5,9 @@ * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev <avneesh@sproute.com> + * + * Portions: + * Copyright (C) 2024 Carmine Scarpitta (for SRv6) */ /* @@ -15,6 +18,7 @@ #define _FPM_PB_H #include "lib/route_types.h" +#include "lib/vrf.h" #include "qpb/qpb.h" #include "fpm/fpm.pb-c.h" @@ -42,4 +46,400 @@ static inline Fpm__RouteKey *fpm__route_key__create(qpb_allocator_t *allocator, return key; } +/* + * fpm__nexthop__create + */ +#define fpm_nexthop_create fpm__nexthop__create +static inline Fpm__Nexthop * +fpm__nexthop__create(qpb_allocator_t *allocator, struct nexthop *nh) +{ + Fpm__Nexthop *nexthop; + uint8_t family; + + nexthop = QPB_ALLOC(allocator, typeof(*nexthop)); + if (!nexthop) + return NULL; + + fpm__nexthop__init(nexthop); + + if (nh->type == NEXTHOP_TYPE_IPV4 || + nh->type == NEXTHOP_TYPE_IPV4_IFINDEX) + family = AF_INET; + else if (nh->type == NEXTHOP_TYPE_IPV6 || + nh->type == NEXTHOP_TYPE_IPV6_IFINDEX) + family = AF_INET6; + else + return NULL; + + nexthop->if_id = qpb__if_identifier__create(allocator, nh->ifindex); + if (!nexthop->if_id) + return NULL; + + nexthop->address = qpb__l3_address__create(allocator, &nh->gate, family); + if (!nexthop->address) + return NULL; + + + return nexthop; +} + +/* + * fpm__nexthop__get + * + * Read out information from a protobuf nexthop structure. + */ +#define fpm_nexthop_get fpm__nexthop__get +static inline int fpm__nexthop__get(const Fpm__Nexthop *nh, + struct nexthop *nexthop) +{ + struct in_addr ipv4; + struct in6_addr ipv6; + uint32_t ifindex; + char *ifname; + + if (!nh) + return 0; + + if (!qpb_if_identifier_get(nh->if_id, &ifindex, &ifname)) + return 0; + + if (nh->address) { + if (nh->address->v4) { + memset(&ipv4, 0, sizeof(ipv4)); + if (!qpb__ipv4_address__get(nh->address->v4, &ipv4)) + return 0; + + nexthop->vrf_id = VRF_DEFAULT; + nexthop->type = NEXTHOP_TYPE_IPV4; + nexthop->gate.ipv4 = ipv4; + if (ifindex) { + nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + nexthop->ifindex = ifindex; + } + return 1; + } + + if (nh->address->v6) { + memset(&ipv6, 0, sizeof(ipv6)); + if (!qpb__ipv6_address__get(nh->address->v6, &ipv6)) + return 0; + nexthop->vrf_id = VRF_DEFAULT; + nexthop->type = NEXTHOP_TYPE_IPV6; + nexthop->gate.ipv6 = ipv6; + if (ifindex) { + nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + nexthop->ifindex = ifindex; + } + return 1; + } + } + + return 0; +} + +/* + * fpm__srv6_sid_format__create + */ +#define fpm_srv6_sid_format_create fpm__srv6_sid_format__create +static inline Fpm__SRv6SIDFormat * +fpm__srv6_sid_format__create(qpb_allocator_t *allocator, + uint8_t locator_block_length, + uint8_t locator_node_length, + uint8_t function_length, uint8_t argument_length) +{ + Fpm__SRv6SIDFormat *sid_format; + + sid_format = QPB_ALLOC(allocator, typeof(*sid_format)); + if (!sid_format) + return NULL; + fpm__srv6_sidformat__init(sid_format); + + sid_format->locator_block_length = locator_block_length; + sid_format->locator_node_length = locator_node_length; + sid_format->function_length = function_length; + sid_format->argument_length = argument_length; + + return sid_format; +} + +/* + * fpm__srv6_local_sid_end_behavior__create + */ +#define fpm_srv6_local_sid_end_behavior_create \ + fpm__srv6_local_sid_end_behavior__create +static inline Fpm__SRv6LocalSID__End * +fpm__srv6_local_sid_end_behavior__create(qpb_allocator_t *allocator) +{ + Fpm__SRv6LocalSID__End *end; + + end = QPB_ALLOC(allocator, typeof(*end)); + if (!end) + return NULL; + + fpm__srv6_local_sid__end__init(end); + + return end; +} + +/* + * fpm__srv6_local_sid_end_x_behavior__create + */ +#define fpm_srv6_local_sid_end_x_behavior_create \ + fpm__srv6_local_sid_end_x_behavior__create +static inline Fpm__SRv6LocalSID__EndX * +fpm__srv6_local_sid_end_x_behavior__create(qpb_allocator_t *allocator, + struct nexthop *nexthop) +{ + Fpm__SRv6LocalSID__EndX *end_x; + + end_x = QPB_ALLOC(allocator, typeof(*end_x)); + if (!end_x) + return NULL; + + fpm__srv6_local_sid__end_x__init(end_x); + + end_x->nexthop = fpm_nexthop_create(allocator, nexthop); + + return end_x; +} + +/* + * fpm__srv6_local_sid_end_t_behavior__create + */ +#define fpm_srv6_local_sid_end_t_behavior_create \ + fpm__srv6_local_sid_end_t_behavior__create +static inline Fpm__SRv6LocalSID__EndT * +fpm__srv6_local_sid_end_t_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__EndT *end_t; + + end_t = QPB_ALLOC(allocator, typeof(*end_t)); + if (!end_t) + return NULL; + + fpm__srv6_local_sid__end_t__init(end_t); + + end_t->vrf_id = vrf_id; + + return end_t; +} + +/* + * fpm__srv6_local_sid_end_dx6_behavior__create + */ +#define fpm_srv6_local_sid_end_dx6_behavior_create \ + fpm__srv6_local_sid_end_dx6_behavior__create +static inline Fpm__SRv6LocalSID__EndDX6 * +fpm__srv6_local_sid_end_dx6_behavior__create(qpb_allocator_t *allocator, + struct nexthop *nexthop) +{ + Fpm__SRv6LocalSID__EndDX6 *end_dx6; + + end_dx6 = QPB_ALLOC(allocator, typeof(*end_dx6)); + if (!end_dx6) + return NULL; + + fpm__srv6_local_sid__end_dx6__init(end_dx6); + + end_dx6->nexthop = fpm_nexthop_create(allocator, nexthop); + + return end_dx6; +} + +/* + * fpm__srv6_local_sid_end_dx4_behavior__create + */ +#define fpm_srv6_local_sid_end_dx4_behavior_create \ + fpm__srv6_local_sid_end_dx4_behavior__create +static inline Fpm__SRv6LocalSID__EndDX4 * +fpm__srv6_local_sid_end_dx4_behavior__create(qpb_allocator_t *allocator, + struct nexthop *nexthop) +{ + Fpm__SRv6LocalSID__EndDX4 *end_dx4; + + end_dx4 = QPB_ALLOC(allocator, typeof(*end_dx4)); + if (!end_dx4) + return NULL; + + fpm__srv6_local_sid__end_dx4__init(end_dx4); + + end_dx4->nexthop = fpm_nexthop_create(allocator, nexthop); + + return end_dx4; +} + +/* + * fpm__srv6_local_sid_end_dt6_behavior__create + */ +#define fpm_srv6_local_sid_end_dt6_behavior_create \ + fpm__srv6_local_sid_end_dt6_behavior__create +static inline Fpm__SRv6LocalSID__EndDT6 * +fpm__srv6_local_sid_end_dt6_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__EndDT6 *end_dt6; + + end_dt6 = QPB_ALLOC(allocator, typeof(*end_dt6)); + if (!end_dt6) + return NULL; + + fpm__srv6_local_sid__end_dt6__init(end_dt6); + + end_dt6->vrf_id = vrf_id; + + return end_dt6; +} + +/* + * fpm__srv6_local_sid_end_dt4_behavior__create + */ +#define fpm_srv6_local_sid_end_dt4_behavior_create \ + fpm__srv6_local_sid_end_dt4_behavior__create +static inline Fpm__SRv6LocalSID__EndDT4 * +fpm__srv6_local_sid_end_dt4_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__EndDT4 *end_dt4; + + end_dt4 = QPB_ALLOC(allocator, typeof(*end_dt4)); + if (!end_dt4) + return NULL; + + fpm__srv6_local_sid__end_dt4__init(end_dt4); + + end_dt4->vrf_id = vrf_id; + + return end_dt4; +} + +/* + * fpm__srv6_local_sid_end_dt46_behavior__create + */ +#define fpm_srv6_local_sid_end_dt46_behavior_create \ + fpm__srv6_local_sid_end_dt46_behavior__create +static inline Fpm__SRv6LocalSID__EndDT46 * +fpm__srv6_local_sid_end_dt46_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__EndDT46 *end_dt46; + + end_dt46 = QPB_ALLOC(allocator, typeof(*end_dt46)); + if (!end_dt46) + return NULL; + + fpm__srv6_local_sid__end_dt46__init(end_dt46); + + end_dt46->vrf_id = vrf_id; + + return end_dt46; +} + +/* + * fpm__srv6_local_sid_un_behavior__create + */ +#define fpm_srv6_local_sid_un_behavior_create \ + fpm__srv6_local_sid_un_behavior__create +static inline Fpm__SRv6LocalSID__UN * +fpm__srv6_local_sid_un_behavior__create(qpb_allocator_t *allocator) +{ + Fpm__SRv6LocalSID__UN *un; + + un = QPB_ALLOC(allocator, typeof(*un)); + if (!un) + return NULL; + + fpm__srv6_local_sid__un__init(un); + + return un; +} + +/* + * fpm__srv6_local_sid_ua_behavior__create + */ +#define fpm_srv6_local_sid_ua_behavior_create \ + fpm__srv6_local_sid_ua_behavior__create +static inline Fpm__SRv6LocalSID__UA * +fpm__srv6_local_sid_ua_behavior__create(qpb_allocator_t *allocator, + struct nexthop *nexthop) +{ + Fpm__SRv6LocalSID__UA *ua; + + ua = QPB_ALLOC(allocator, typeof(*ua)); + if (!ua) + return NULL; + + fpm__srv6_local_sid__ua__init(ua); + + ua->nexthop = fpm_nexthop_create(allocator, nexthop); + + return ua; +} + +/* + * fpm__srv6_local_sid_udt6_behavior__create + */ +#define fpm_srv6_local_sid_udt6_behavior_create \ + fpm__srv6_local_sid_udt6_behavior__create +static inline Fpm__SRv6LocalSID__UDT6 * +fpm__srv6_local_sid_udt6_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__UDT6 *udt6; + + udt6 = QPB_ALLOC(allocator, typeof(*udt6)); + if (!udt6) + return NULL; + + fpm__srv6_local_sid__udt6__init(udt6); + + udt6->vrf_id = vrf_id; + + return udt6; +} + +/* + * fpm__srv6_local_sid_udt4_behavior__create + */ +#define fpm_srv6_local_sid_udt4_behavior_create \ + fpm__srv6_local_sid_udt4_behavior__create +static inline Fpm__SRv6LocalSID__UDT4 * +fpm__srv6_local_sid_udt4_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__UDT4 *udt4; + + udt4 = QPB_ALLOC(allocator, typeof(*udt4)); + if (!udt4) + return NULL; + + fpm__srv6_local_sid__udt4__init(udt4); + + udt4->vrf_id = vrf_id; + + return udt4; +} + +/* + * fpm__srv6_local_sid_udt46_behavior__create + */ +#define fpm_srv6_local_sid_udt46_behavior_create \ + fpm__srv6_local_sid_udt46_behavior__create +static inline Fpm__SRv6LocalSID__UDT46 * +fpm__srv6_local_sid_udt46_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__UDT46 *udt46; + + udt46 = QPB_ALLOC(allocator, typeof(*udt46)); + if (!udt46) + return NULL; + + fpm__srv6_local_sid__udt46__init(udt46); + + udt46->vrf_id = vrf_id; + + return udt46; +} + #endif diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 7a4b45a0de..36986a19c5 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -2424,7 +2424,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, " [vrf <NAME|all>] topology" #ifndef FABRICD " [<level-1|level-2>]" - " [algorithm (128-255)]" + " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ , SHOW_STR PROTO_HELP VRF_CMD_HELP_STR @@ -2443,8 +2443,10 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, struct isis *isis = NULL; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; + bool all_algorithm = false; int idx_vrf = 0; - uint8_t algorithm = SR_ALGORITHM_SPF; + uint16_t algorithm = SR_ALGORITHM_SPF; + #ifndef FABRICD int idx = 0; @@ -2453,8 +2455,12 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, levels = ISIS_LEVEL1; if (argv_find(argv, argc, "level-2", &idx)) levels = ISIS_LEVEL2; - if (argv_find(argv, argc, "algorithm", &idx)) - algorithm = (uint8_t)strtoul(argv[idx + 1]->arg, NULL, 10); + if (argv_find(argv, argc, "algorithm", &idx)) { + if (argv_find(argv, argc, "(128-255)", &idx)) + algorithm = (uint16_t)strtoul(argv[idx]->arg, NULL, 10); + else + all_algorithm = true; + } #endif /* ifndef FABRICD */ if (!im) { @@ -2465,14 +2471,34 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, if (vrf_name) { if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) - show_isis_topology_common(vty, levels, isis, - algorithm); + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { + if (all_algorithm) { + for (algorithm = SR_ALGORITHM_FLEX_MIN; + algorithm <= SR_ALGORITHM_FLEX_MAX; + algorithm++) + show_isis_topology_common( + vty, levels, isis, + (uint8_t)algorithm); + } else { + show_isis_topology_common( + vty, levels, isis, + (uint8_t)algorithm); + } + } return CMD_SUCCESS; } isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) - show_isis_topology_common(vty, levels, isis, algorithm); + if (isis == NULL) + return CMD_SUCCESS; + if (all_algorithm) { + for (algorithm = SR_ALGORITHM_FLEX_MIN; + algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) { + show_isis_topology_common(vty, levels, isis, + (uint8_t)algorithm); + } + } else + show_isis_topology_common(vty, levels, isis, + (uint8_t)algorithm); } return CMD_SUCCESS; @@ -2912,6 +2938,7 @@ static void show_isis_route_common(struct vty *vty, int levels, jstr = json_object_new_string( area->area_tag ? area->area_tag : "null"); json_object_object_add(*json, "area", jstr); + json_object_int_add(*json, "algorithm", algo); } else { vty_out(vty, "Area %s:", area->area_tag ? area->area_tag : "null"); @@ -3011,6 +3038,39 @@ static void show_isis_route_common(struct vty *vty, int levels, } } +static void show_isis_route_all_algos(struct vty *vty, int levels, + struct isis *isis, bool prefix_sid, + bool backup, json_object **json) +{ + uint16_t algo; + + json_object *json_algo = NULL, *json_algos = NULL; + + if (json) { + *json = json_object_new_object(); + json_algos = json_object_new_array(); + } + + for (algo = SR_ALGORITHM_FLEX_MIN; algo <= SR_ALGORITHM_FLEX_MAX; + algo++) { + show_isis_route_common(vty, levels, isis, prefix_sid, backup, + (uint8_t)algo, json ? &json_algo : NULL); + if (!json) + continue; + if (json_object_object_length(json_algo) == 0) { + json_object_free(json_algo); + continue; + } + json_object_object_add(json_algo, "algorithm", + json_object_new_int(algo)); + json_object_array_add(json_algos, json_algo); + } + + if (json) + json_object_object_add(*json, "algorithms", json_algos); +} + + DEFUN(show_isis_route, show_isis_route_cmd, "show " PROTO_NAME " [vrf <NAME|all>] route" @@ -3019,7 +3079,7 @@ DEFUN(show_isis_route, show_isis_route_cmd, #endif /* ifndef FABRICD */ " [<prefix-sid|backup>]" #ifndef FABRICD - " [algorithm (128-255)]" + " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ " [json$uj]", SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR @@ -3041,6 +3101,7 @@ DEFUN(show_isis_route, show_isis_route_cmd, struct listnode *node; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; + bool all_algorithm = false; bool prefix_sid = false; bool backup = false; bool uj = use_json(argc, argv); @@ -3067,8 +3128,13 @@ DEFUN(show_isis_route, show_isis_route_cmd, backup = true; #ifndef FABRICD - if (argv_find(argv, argc, "algorithm", &idx)) - algorithm = (uint8_t)strtoul(argv[idx + 1]->arg, NULL, 10); + if (argv_find(argv, argc, "algorithm", &idx)) { + if (argv_find(argv, argc, "(128-255)", &idx)) + algorithm = (uint8_t)strtoul(argv[idx + 1]->arg, NULL, + 10); + else + all_algorithm = true; + } #endif /* ifndef FABRICD */ if (uj) @@ -3077,9 +3143,19 @@ DEFUN(show_isis_route, show_isis_route_cmd, if (vrf_name) { if (all_vrf) { for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { - show_isis_route_common( - vty, levels, isis, prefix_sid, backup, - algorithm, uj ? &json_vrf : NULL); + if (all_algorithm) + show_isis_route_all_algos(vty, levels, + isis, + prefix_sid, + backup, + uj ? &json_vrf + : NULL); + else + show_isis_route_common(vty, levels, + isis, prefix_sid, + backup, algorithm, + uj ? &json_vrf + : NULL); if (uj) { json_object_object_add( json_vrf, "vrf_id", @@ -3092,9 +3168,15 @@ DEFUN(show_isis_route, show_isis_route_cmd, } isis = isis_lookup_by_vrfname(vrf_name); if (isis != NULL) { - show_isis_route_common(vty, levels, isis, prefix_sid, - backup, algorithm, - uj ? &json_vrf : NULL); + if (all_algorithm) + show_isis_route_all_algos(vty, levels, isis, + prefix_sid, backup, + uj ? &json_vrf : NULL); + else + show_isis_route_common(vty, levels, isis, + prefix_sid, backup, + algorithm, + uj ? &json_vrf : NULL); if (uj) { json_object_object_add( json_vrf, "vrf_id", diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index 1d69dbbbfa..e8354fdf92 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -1074,7 +1074,7 @@ DEFUN(show_sr_node, show_sr_node_cmd, "show " PROTO_NAME " segment-routing node" #ifndef FABRICD - " [algorithm (128-255)]" + " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ , SHOW_STR PROTO_HELP @@ -1088,13 +1088,18 @@ DEFUN(show_sr_node, show_sr_node_cmd, { struct listnode *node, *inode; struct isis_area *area; - uint8_t algorithm = SR_ALGORITHM_SPF; + uint16_t algorithm = SR_ALGORITHM_SPF; + bool all_algorithm = false; struct isis *isis; #ifndef FABRICD int idx = 0; - if (argv_find(argv, argc, "algorithm", &idx)) - algorithm = (uint8_t)strtoul(argv[idx + 1]->arg, NULL, 10); + if (argv_find(argv, argc, "algorithm", &idx)) { + if (argv_find(argv, argc, "(128-255)", &idx)) + algorithm = (uint16_t)strtoul(argv[idx]->arg, NULL, 10); + else + all_algorithm = true; + } #endif /* ifndef FABRICD */ for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { @@ -1106,8 +1111,17 @@ DEFUN(show_sr_node, show_sr_node_cmd, continue; } for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; - level++) - show_node(vty, area, level, algorithm); + level++) { + if (all_algorithm) { + for (algorithm = SR_ALGORITHM_FLEX_MIN; + algorithm <= SR_ALGORITHM_FLEX_MAX; + algorithm++) + show_node(vty, area, level, + (uint8_t)algorithm); + } else + show_node(vty, area, level, + (uint8_t)algorithm); + } } } diff --git a/lib/affinitymap_northbound.c b/lib/affinitymap_northbound.c index 8e84d36f2f..003e0c11b9 100644 --- a/lib/affinitymap_northbound.c +++ b/lib/affinitymap_northbound.c @@ -94,7 +94,8 @@ const struct frr_yang_module_info frr_affinity_map_info = { .cbs = { .create = lib_affinity_map_create, .destroy = lib_affinity_map_destroy, - } + }, + .priority = NB_DFLT_PRIORITY - 1, }, { .xpath = "/frr-affinity-map:lib/affinity-maps/affinity-map/value", diff --git a/lib/base64.c b/lib/base64.c index ee2e838c01..00dd35ffb5 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -11,7 +11,6 @@ #include "base64.h" #include "compiler.h" -static const int CHARS_PER_LINE = 72; static const char *ENCODING = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -19,7 +18,6 @@ void base64_init_encodestate(struct base64_encodestate *state_in) { state_in->step = step_A; state_in->result = 0; - state_in->stepcount = 0; } char base64_encode_value(char value_in) @@ -76,12 +74,6 @@ int base64_encode_block(const char *plaintext_in, int length_in, char *code_out, *codechar++ = base64_encode_value(result); result = (fragment & 0x03f) >> 0; *codechar++ = base64_encode_value(result); - - ++(state_in->stepcount); - if (state_in->stepcount == CHARS_PER_LINE/4) { - *codechar++ = '\n'; - state_in->stepcount = 0; - } } } /* control should not reach here */ @@ -105,7 +97,6 @@ int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in) case step_A: break; } - *codechar++ = '\n'; return codechar - code_out; } diff --git a/lib/base64.h b/lib/base64.h index 839f92aa7c..9bf4ace82f 100644 --- a/lib/base64.h +++ b/lib/base64.h @@ -14,7 +14,6 @@ enum base64_encodestep { struct base64_encodestate { enum base64_encodestep step; char result; - int stepcount; }; void base64_init_encodestate(struct base64_encodestate *state_in); diff --git a/lib/filter.c b/lib/filter.c index a0adff0e35..5a0790f8bf 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -410,7 +410,10 @@ void access_list_filter_add(struct access_list *access, filter->prev = access->tail; access->tail = filter; } +} +void access_list_filter_update(struct access_list *access) +{ /* Run hook function. */ if (access->master->add_hook) (*access->master->add_hook)(access); diff --git a/lib/filter.h b/lib/filter.h index bd9e22d384..4fa482ba4e 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -128,6 +128,7 @@ struct filter *filter_new(void); void access_list_filter_add(struct access_list *access, struct filter *filter); void access_list_filter_delete(struct access_list *access, struct filter *filter); +void access_list_filter_update(struct access_list *access); int64_t filter_new_seq_get(struct access_list *access); extern const struct frr_yang_module_info frr_filter_info; diff --git a/lib/filter_nb.c b/lib/filter_nb.c index eba4e421c0..39042d39ab 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -17,23 +17,6 @@ #include "lib/plist_int.h" #include "lib/routemap.h" -/* Helper function. */ -static void acl_notify_route_map(struct access_list *acl, int route_map_event) -{ - switch (route_map_event) { - case RMAP_EVENT_FILTER_ADDED: - if (acl->master->add_hook) - (*acl->master->add_hook)(acl); - break; - case RMAP_EVENT_FILTER_DELETED: - if (acl->master->delete_hook) - (*acl->master->delete_hook)(acl); - break; - } - - route_map_notify_dependencies(acl->name, route_map_event); -} - static enum nb_error prefix_list_length_validate(struct nb_cb_modify_args *args) { int type = yang_dnode_get_enum(args->dnode, "../../type"); @@ -153,9 +136,6 @@ static int lib_prefix_list_entry_prefix_length_greater_or_equal_modify( ple->ge = yang_dnode_get_uint8(args->dnode, NULL); - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -174,9 +154,6 @@ static int lib_prefix_list_entry_prefix_length_lesser_or_equal_modify( ple->le = yang_dnode_get_uint8(args->dnode, NULL); - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -195,9 +172,6 @@ static int lib_prefix_list_entry_prefix_length_greater_or_equal_destroy( ple->ge = 0; - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -216,9 +190,6 @@ static int lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy( ple->le = 0; - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -575,6 +546,15 @@ static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +static void +lib_access_list_entry_apply_finish(struct nb_cb_apply_finish_args *args) +{ + struct filter *f; + + f = nb_running_get_entry(args->dnode, NULL, true); + access_list_filter_update(f->acl); +} + /* * XPath: /frr-filter:lib/access-list/entry/action */ @@ -594,8 +574,6 @@ lib_access_list_entry_action_modify(struct nb_cb_modify_args *args) else f->type = FILTER_DENY; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -629,8 +607,6 @@ lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args) fz = &f->u.zfilter; yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -647,8 +623,6 @@ lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args) fz = &f->u.zfilter; memset(&fz->prefix, 0, sizeof(fz->prefix)); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); - return NB_OK; } @@ -681,8 +655,6 @@ lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args) fz = &f->u.zfilter; fz->exact = yang_dnode_get_bool(args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -699,8 +671,6 @@ lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args) fz = &f->u.zfilter; fz->exact = 0; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); - return NB_OK; } @@ -733,8 +703,6 @@ lib_access_list_entry_host_modify(struct nb_cb_modify_args *args) yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL); fc->addr_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -751,7 +719,29 @@ lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args) fc = &f->u.cfilter; cisco_unset_addr_mask(&fc->addr, &fc->addr_mask); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); + return NB_OK; +} + +/* + * XPath: /frr-filter:lib/access-list/entry/network + */ +static int lib_access_list_entry_network_create(struct nb_cb_create_args *args) +{ + /* Nothing to do here, everything is done in children callbacks */ + return NB_OK; +} + +static int lib_access_list_entry_network_destroy(struct nb_cb_destroy_args *args) +{ + struct filter_cisco *fc; + struct filter *f; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + f = nb_running_get_entry(args->dnode, NULL, true); + fc = &f->u.cfilter; + cisco_unset_addr_mask(&fc->addr, &fc->addr_mask); return NB_OK; } @@ -784,8 +774,6 @@ lib_access_list_entry_network_address_modify(struct nb_cb_modify_args *args) fc = &f->u.cfilter; yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -817,8 +805,6 @@ lib_access_list_entry_network_mask_modify(struct nb_cb_modify_args *args) fc = &f->u.cfilter; yang_dnode_get_ipv4(&fc->addr_mask, args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -851,8 +837,6 @@ lib_access_list_entry_source_any_create(struct nb_cb_create_args *args) fc->addr.s_addr = INADDR_ANY; fc->addr_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -869,8 +853,6 @@ lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args *args) fc = &f->u.cfilter; cisco_unset_addr_mask(&fc->addr, &fc->addr_mask); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); - return NB_OK; } @@ -903,8 +885,6 @@ static int lib_access_list_entry_destination_host_modify( yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL); fc->mask_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -922,7 +902,32 @@ static int lib_access_list_entry_destination_host_destroy( fc->extended = 0; cisco_unset_addr_mask(&fc->mask, &fc->mask_mask); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); + return NB_OK; +} + +/* + * XPath: /frr-filter:lib/access-list/entry/destination-network + */ +static int +lib_access_list_entry_destination_network_create(struct nb_cb_create_args *args) +{ + /* Nothing to do here, everything is done in children callbacks */ + return NB_OK; +} + +static int lib_access_list_entry_destination_network_destroy( + struct nb_cb_destroy_args *args) +{ + struct filter_cisco *fc; + struct filter *f; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + f = nb_running_get_entry(args->dnode, NULL, true); + fc = &f->u.cfilter; + fc->extended = 0; + cisco_unset_addr_mask(&fc->mask, &fc->mask_mask); return NB_OK; } @@ -955,8 +960,6 @@ static int lib_access_list_entry_destination_network_address_modify( fc->extended = 1; yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -988,8 +991,6 @@ static int lib_access_list_entry_destination_network_mask_modify( fc->extended = 1; yang_dnode_get_ipv4(&fc->mask_mask, args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -1022,8 +1023,6 @@ static int lib_access_list_entry_destination_any_create( fc->mask.s_addr = INADDR_ANY; fc->mask_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -1041,8 +1040,6 @@ static int lib_access_list_entry_destination_any_destroy( fc->extended = 0; cisco_unset_addr_mask(&fc->mask, &fc->mask_mask); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); - return NB_OK; } @@ -1089,8 +1086,6 @@ static int lib_access_list_entry_any_create(struct nb_cb_create_args *args) break; } - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -1106,8 +1101,6 @@ static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args) fz = &f->u.zfilter; fz->prefix.family = AF_UNSPEC; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); - return NB_OK; } @@ -1224,6 +1217,22 @@ static int lib_prefix_list_entry_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +static void +lib_prefix_list_entry_apply_finish(struct nb_cb_apply_finish_args *args) +{ + struct prefix_list_entry *ple; + + ple = nb_running_get_entry(args->dnode, NULL, true); + + /* + * Finish prefix entry update procedure. The procedure is started in + * children callbacks. `prefix_list_entry_update_start` can be called + * multiple times if multiple children are modified, but it is actually + * executed only once because of the protection by `ple->installed`. + */ + prefix_list_entry_update_finish(ple); +} + /* * XPath: /frr-filter:lib/prefix-list/entry/action */ @@ -1246,9 +1255,6 @@ static int lib_prefix_list_entry_action_modify(struct nb_cb_modify_args *args) else ple->type = PREFIX_DENY; - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -1276,10 +1282,6 @@ static int lib_prefix_list_entry_prefix_modify(struct nb_cb_modify_args *args) prefix_copy(&ple->prefix, &p); } - - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -1297,9 +1299,6 @@ static int lib_prefix_list_entry_prefix_destroy(struct nb_cb_destroy_args *args) memset(&ple->prefix, 0, sizeof(ple->prefix)); - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -1547,9 +1546,6 @@ static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args) break; } - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -1567,9 +1563,6 @@ static int lib_prefix_list_entry_any_destroy(struct nb_cb_destroy_args *args) ple->any = false; - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -1597,6 +1590,7 @@ const struct frr_yang_module_info frr_filter_info = { .cbs = { .create = lib_access_list_entry_create, .destroy = lib_access_list_entry_destroy, + .apply_finish = lib_access_list_entry_apply_finish, .cli_cmp = access_list_cmp, .cli_show = access_list_show, } @@ -1629,6 +1623,13 @@ const struct frr_yang_module_info frr_filter_info = { } }, { + .xpath = "/frr-filter:lib/access-list/entry/network", + .cbs = { + .create = lib_access_list_entry_network_create, + .destroy = lib_access_list_entry_network_destroy, + } + }, + { .xpath = "/frr-filter:lib/access-list/entry/network/address", .cbs = { .modify = lib_access_list_entry_network_address_modify, @@ -1655,6 +1656,13 @@ const struct frr_yang_module_info frr_filter_info = { } }, { + .xpath = "/frr-filter:lib/access-list/entry/destination-network", + .cbs = { + .create = lib_access_list_entry_destination_network_create, + .destroy = lib_access_list_entry_destination_network_destroy, + } + }, + { .xpath = "/frr-filter:lib/access-list/entry/destination-network/address", .cbs = { .modify = lib_access_list_entry_destination_network_address_modify, @@ -1721,6 +1729,7 @@ const struct frr_yang_module_info frr_filter_info = { .cbs = { .create = lib_prefix_list_entry_create, .destroy = lib_prefix_list_entry_destroy, + .apply_finish = lib_prefix_list_entry_apply_finish, .cli_cmp = prefix_list_cmp, .cli_show = prefix_list_show, } diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c index bfdecedc4e..a107582bea 100644 --- a/lib/mgmt_fe_client.c +++ b/lib/mgmt_fe_client.c @@ -510,14 +510,11 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client, debug_fe_client("Got native message for session-id %" PRIu64, msg->refer_id); - if (msg->code != MGMT_MSG_CODE_NOTIFY) { - session = mgmt_fe_find_session_by_session_id(client, - msg->refer_id); - if (!session || !session->client) { - log_err_fe_client("No session for received native msg session-id %" PRIu64, - msg->refer_id); - return; - } + session = mgmt_fe_find_session_by_session_id(client, msg->refer_id); + if (!session || !session->client) { + log_err_fe_client("No session for received native msg session-id %" PRIu64, + msg->refer_id); + return; } switch (msg->code) { @@ -558,6 +555,9 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client, tree_msg->partial_error); break; case MGMT_MSG_CODE_NOTIFY: + if (!session->client->cbs.async_notification) + return; + notify_msg = (typeof(notify_msg))msg; if (msg_len < sizeof(*notify_msg)) { log_err_fe_client("Corrupt notify-data msg recv"); @@ -579,15 +579,13 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client, notify_msg->result_type); return; } - FOREACH_SESSION_IN_LIST (client, session) { - if (!session->client->cbs.async_notification) - continue; - session->client->cbs - .async_notification(client, client->user_data, - session->client_id, - session->user_ctx, data); - } + session->client->cbs.async_notification(client, + client->user_data, + session->client_id, + msg->refer_id, + session->user_ctx, data); + if (notify_msg->result_type != LYD_JSON) darr_free(data); break; diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h index 7af1270071..eee4594e17 100644 --- a/lib/mgmt_fe_client.h +++ b/lib/mgmt_fe_client.h @@ -117,7 +117,8 @@ struct mgmt_fe_client_cbs { /* Called with asynchronous notifications from backends */ int (*async_notification)(struct mgmt_fe_client *client, uintptr_t user_data, uint64_t client_id, - uintptr_t session_ctx, const char *result); + uint64_t session_id, uintptr_t session_ctx, + const char *result); /* Called when new native error is returned */ int (*error_notify)(struct mgmt_fe_client *client, uintptr_t user_data, diff --git a/lib/northbound.c b/lib/northbound.c index a3d91e56af..25ea658bc4 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -157,7 +157,7 @@ void nb_nodes_delete(void) struct nb_node *nb_node_find(const char *path) { const struct lysc_node *snode; - uint32_t llopts; + uint32_t llopts = 0; /* * Use libyang to find the schema node associated to the path and get @@ -165,8 +165,6 @@ struct nb_node *nb_node_find(const char *path) * disable logging temporarily to avoid libyang from logging an error * message when the node is not found. */ - llopts = ly_log_options(LY_LOSTORE); - llopts &= ~LY_LOLOG; ly_temp_log_options(&llopts); snode = yang_find_snode(ly_native_ctx, path, 0); @@ -391,13 +389,29 @@ void nb_config_replace(struct nb_config *config_dst, static inline int nb_config_cb_compare(const struct nb_config_cb *a, const struct nb_config_cb *b) { - /* Sort by priority first. */ - if (a->nb_node->priority < b->nb_node->priority) + bool a_destroy = a->operation == NB_CB_DESTROY; + bool b_destroy = b->operation == NB_CB_DESTROY; + + /* + * Sort by operation first. All "destroys" must come first, to correctly + * process the change of a "case" inside a "choice". The old "case" must + * be deleted before the new "case" is created. + */ + if (a_destroy && !b_destroy) return -1; - if (a->nb_node->priority > b->nb_node->priority) + if (!a_destroy && b_destroy) return 1; /* + * Then sort by priority. If the operation is "destroy", reverse the + * order, so that the dependants are deleted before the dependencies. + */ + if (a->nb_node->priority < b->nb_node->priority) + return !a_destroy ? -1 : 1; + if (a->nb_node->priority > b->nb_node->priority) + return !a_destroy ? 1 : -1; + + /* * Preserve the order of the configuration changes as told by libyang. */ if (a->seq < b->seq) @@ -1811,6 +1825,7 @@ nb_apply_finish_cb_new(struct nb_config_cbs *cbs, const struct nb_node *nb_node, struct nb_config_cb *cb; cb = XCALLOC(MTYPE_TMP, sizeof(*cb)); + cb->operation = NB_CB_APPLY_FINISH; cb->nb_node = nb_node; cb->dnode = dnode; RB_INSERT(nb_config_cbs, cbs, cb); @@ -1825,6 +1840,7 @@ nb_apply_finish_cb_find(struct nb_config_cbs *cbs, { struct nb_config_cb s; + s.operation = NB_CB_APPLY_FINISH; s.seq = 0; s.nb_node = nb_node; s.dnode = dnode; @@ -1922,6 +1938,8 @@ bool nb_cb_operation_is_valid(enum nb_cb_operation operation, return false; break; case LYS_CONTAINER: + if (snode->parent && snode->parent->nodetype == LYS_CASE) + return true; scontainer = (struct lysc_node_container *)snode; if (!CHECK_FLAG(scontainer->flags, LYS_PRESENCE)) return false; @@ -1976,6 +1994,8 @@ bool nb_cb_operation_is_valid(enum nb_cb_operation operation, return false; break; case LYS_CONTAINER: + if (snode->parent && snode->parent->nodetype == LYS_CASE) + return true; scontainer = (struct lysc_node_container *)snode; if (!CHECK_FLAG(scontainer->flags, LYS_PRESENCE)) return false; diff --git a/lib/routemap.c b/lib/routemap.c index 6b3f81b4d4..ea917ebd8c 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -2548,7 +2548,6 @@ route_map_result_t route_map_apply_ext(struct route_map *map, struct route_map_index *index = NULL; struct route_map_rule *set = NULL; bool skip_match_clause = false; - struct prefix conv; if (recursion > RMAP_RECURSION_LIMIT) { if (map) @@ -2571,31 +2570,14 @@ route_map_result_t route_map_apply_ext(struct route_map *map, map->applied++; - /* - * Handling for matching evpn_routes in the prefix table. - * - * We convert type2/5 prefix to ipv4/6 prefix to do longest - * prefix matching on. - */ if (prefix->family == AF_EVPN) { - if (evpn_prefix2prefix(prefix, &conv) != 0) { - if (unlikely(CHECK_FLAG(rmap_debug, - DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "Unable to convert EVPN prefix %pFX into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup", - prefix); - } else { - if (unlikely(CHECK_FLAG(rmap_debug, - DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "Converted EVPN prefix %pFX into %pFX for optimized route-map lookup", - prefix, &conv); - - prefix = &conv; - } + index = map->head; + } else { + skip_match_clause = true; + index = route_map_get_index(map, prefix, match_object, + &match_ret); } - index = route_map_get_index(map, prefix, match_object, &match_ret); if (index) { index->applied++; if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))) @@ -2619,7 +2601,6 @@ route_map_result_t route_map_apply_ext(struct route_map *map, ret = RMAP_DENYMATCH; goto route_map_apply_end; } - skip_match_clause = true; for (; index; index = index->next) { if (!skip_match_clause) { diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c index 4aab880d22..d1ef85c9a6 100644 --- a/ospfd/ospf_ldp_sync.c +++ b/ospfd/ospf_ldp_sync.c @@ -774,7 +774,7 @@ DEFPY (no_ospf_mpls_ldp_sync, "Disable MPLS LDP-IGP Sync\n") { VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - ospf_ldp_sync_gbl_exit(ospf, false); + ospf_ldp_sync_gbl_exit(ospf, true); return CMD_SUCCESS; } diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 99326b41b3..dbe44f7be4 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -1784,11 +1784,10 @@ static void ospf_router_info_schedule(enum lsa_opcode opcode) DEFUN (router_info, router_info_area_cmd, - "router-info <as|area [A.B.C.D]>", + "router-info <as|area>", OSPF_RI_STR "Enable the Router Information functionality with AS flooding scope\n" - "Enable the Router Information functionality with Area flooding scope\n" - "OSPF area ID in IP format (deprecated)\n") + "Enable the Router Information functionality with Area flooding scope\n") { int idx_mode = 1; uint8_t scope; @@ -1844,6 +1843,15 @@ DEFUN (router_info, return CMD_SUCCESS; } +#if CONFDATE > 20240809 +CPP_NOTICE("Drop deprecated router_info_area_id_cmd") +#endif +ALIAS_HIDDEN (router_info, + router_info_area_id_cmd, + "router-info area A.B.C.D", + OSPF_RI_STR + "Enable the Router Information functionality with Area flooding scope\n" + "OSPF area ID in IP format (deprecated)\n") DEFUN (no_router_info, no_router_info_cmd, @@ -2239,6 +2247,7 @@ static void ospf_router_info_register_vty(void) install_element(VIEW_NODE, &show_ip_ospf_router_info_pce_cmd); install_element(OSPF_NODE, &router_info_area_cmd); + install_element(OSPF_NODE, &router_info_area_id_cmd); install_element(OSPF_NODE, &no_router_info_cmd); install_element(OSPF_NODE, &pce_address_cmd); install_element(OSPF_NODE, &no_pce_address_cmd); diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index a55a37a907..359dc1f5d4 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -2246,6 +2246,10 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) } /* Get corresponding Edge from Link State Data Base */ + if (IPV4_NET0(attr.standard.local.s_addr) && !attr.standard.local_id) { + ote_debug(" |- Found no TE Link local address/ID. Abort!"); + return -1; + } edge = get_edge(ted, attr.adv, attr.standard.local); old = edge->attributes; diff --git a/tests/topotests/bgp_addpath_paths_limit/__init__.py b/tests/topotests/bgp_addpath_paths_limit/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/__init__.py diff --git a/tests/topotests/bgp_addpath_paths_limit/r1/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r1/frr.conf new file mode 100644 index 0000000000..65beb7f286 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r1/frr.conf @@ -0,0 +1,13 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers connect 5 + address-family ipv4 unicast + neighbor 192.168.1.2 addpath-rx-paths-limit 2 + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r2/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r2/frr.conf new file mode 100644 index 0000000000..796b4d0ba7 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r2/frr.conf @@ -0,0 +1,37 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +int r2-eth1 + ip address 192.168.2.2/24 +! +int r2-eth2 + ip address 192.168.7.2/24 +! +router bgp 65002 + timers bgp 3 10 + no bgp ebgp-requires-policy + 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 + neighbor 192.168.2.3 timers connect 5 + neighbor 192.168.2.3 weight 3 + neighbor 192.168.2.4 remote-as external + neighbor 192.168.2.4 timers connect 5 + neighbor 192.168.2.4 weight 4 + neighbor 192.168.2.5 remote-as external + neighbor 192.168.2.5 timers connect 5 + neighbor 192.168.2.5 weight 5 + neighbor 192.168.2.6 remote-as external + neighbor 192.168.2.6 timers connect 5 + neighbor 192.168.2.6 weight 6 + address-family ipv4 unicast + neighbor 192.168.1.1 addpath-tx-all-paths + neighbor 192.168.1.1 prefix-list announce out + neighbor 192.168.7.7 addpath-tx-all-paths + neighbor 192.168.7.7 prefix-list announce out + exit-address-family +! +ip prefix-list announce seq 5 permit 172.16.16.254/32 +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r3/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r3/frr.conf new file mode 100644 index 0000000000..4d834d3113 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r3/frr.conf @@ -0,0 +1,16 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r3-eth0 + ip address 192.168.2.3/24 +! +router bgp 65003 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as external + neighbor 192.168.2.2 timers connect 5 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r4/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r4/frr.conf new file mode 100644 index 0000000000..01e0aa99d3 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r4/frr.conf @@ -0,0 +1,16 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r4-eth0 + ip address 192.168.2.4/24 +! +router bgp 65004 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as external + neighbor 192.168.2.2 timers connect 5 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r5/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r5/frr.conf new file mode 100644 index 0000000000..02bb847987 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r5/frr.conf @@ -0,0 +1,16 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r5-eth0 + ip address 192.168.2.5/24 +! +router bgp 65005 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as external + neighbor 192.168.2.2 timers connect 5 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r6/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r6/frr.conf new file mode 100644 index 0000000000..39fdbcce32 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r6/frr.conf @@ -0,0 +1,16 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r6-eth0 + ip address 192.168.2.6/24 +! +router bgp 65006 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as external + neighbor 192.168.2.2 timers connect 5 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r7/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r7/frr.conf new file mode 100644 index 0000000000..8c44566b2f --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r7/frr.conf @@ -0,0 +1,13 @@ +! +int r7-eth0 + ip address 192.168.7.7/24 +! +router bgp 65007 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.7.2 remote-as external + neighbor 192.168.7.2 timers connect 5 + address-family ipv4 unicast + neighbor 192.168.7.2 addpath-rx-paths-limit 3 + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py new file mode 100644 index 0000000000..b7a1cfbb27 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +""" +Test if Paths-Limit capability works as expected. +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 8): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r7"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_addpath_paths_limit(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + r7 = tgen.gears["r7"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.7.7": { + "neighborCapabilities": { + "pathsLimit": { + "ipv4Unicast": { + "advertisedAndReceived": True, + "advertisedPathsLimit": 0, + "receivedPathsLimit": 3, + } + } + } + }, + "192.168.1.1": { + "neighborCapabilities": { + "pathsLimit": { + "ipv4Unicast": { + "advertisedAndReceived": True, + "advertisedPathsLimit": 0, + "receivedPathsLimit": 2, + } + } + } + }, + } + 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 _bgp_check_received_routes(router, expected): + output = json.loads( + router.vtysh_cmd("show bgp ipv4 unicast 172.16.16.254/32 json") + ) + + if "paths" not in output: + return "No paths received" + + return topotest.json_cmp(len(output["paths"]), expected) + + test_func = functools.partial(_bgp_check_received_routes, r1, 2) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Received routes count is not as expected" + + test_func = functools.partial(_bgp_check_received_routes, r7, 3) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Received routes count is not as expected" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py index 945c0383e7..7d8ddac4c8 100644 --- a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py +++ b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py @@ -389,13 +389,6 @@ def setup_module(module): tors.append("torm22") config_tors(tgen, tors) - hosts = [] - hosts.append("hostd11") - hosts.append("hostd12") - hosts.append("hostd21") - hosts.append("hostd22") - config_hosts(tgen, hosts) - # tgen.mininet_cli() # This is a sample of configuration loading. router_list = tgen.routers() @@ -410,6 +403,13 @@ def setup_module(module): TopoRouter.RD_BGP, os.path.join(CWD, "{}/evpn.conf".format(rname)) ) tgen.start_router() + + hosts = [] + hosts.append("hostd11") + hosts.append("hostd12") + hosts.append("hostd21") + hosts.append("hostd22") + config_hosts(tgen, hosts) # tgen.mininet_cli() @@ -634,6 +634,7 @@ def check_mac(dut, vni, mac, m_type, esi, intf, ping_gw=False, tgen=None): out = dut.vtysh_cmd("show evpn mac vni %d mac %s json" % (vni, mac)) + tmp_esi = None mac_js = json.loads(out) for mac, info in mac_js.items(): tmp_esi = info.get("esi", "") @@ -642,7 +643,15 @@ def check_mac(dut, vni, mac, m_type, esi, intf, ping_gw=False, tgen=None): if tmp_esi == esi and tmp_m_type == m_type and intf == intf: return None - return "invalid vni %d mac %s out %s" % (vni, mac, mac_js) + return "invalid vni %d mac %s expected esi %s, %s m_type %s and intf %s out %s" % ( + vni, + mac, + tmp_esi, + esi, + m_type, + intf, + mac_js, + ) def test_evpn_mac(): diff --git a/tests/topotests/bgp_evpn_route_map_match/r1/frr.conf b/tests/topotests/bgp_evpn_route_map_match/r1/frr.conf index 33353a61f1..4347052c5e 100644 --- a/tests/topotests/bgp_evpn_route_map_match/r1/frr.conf +++ b/tests/topotests/bgp_evpn_route_map_match/r1/frr.conf @@ -1,5 +1,8 @@ ! !debug bgp neighbor +!debug route-map detail +! +vni 10 ! int lo ip address 10.10.10.1/32 @@ -9,22 +12,33 @@ int r1-eth1 ! router bgp 65001 no bgp ebgp-requires-policy + no bgp network import-check neighbor 192.168.1.2 remote-as external neighbor 192.168.1.2 timers 1 3 neighbor 192.168.1.2 timers connect 1 ! address-family ipv4 unicast redistribute connected + network 10.10.10.10/32 exit-address-family ! address-family l2vpn evpn neighbor 192.168.1.2 activate neighbor 192.168.1.2 route-map r2 out advertise-all-vni + advertise ipv4 unicast exit-address-family ! route-map r2 deny 10 match evpn route-type macip ! -route-map r2 permit 20 +route-map r2 deny 20 + match ip address prefix-list pl + match evpn route-type prefix +! +route-map r2 permit 30 +! +ip prefix-list pl seq 5 permit 192.168.1.0/24 +ip prefix-list pl seq 10 permit 10.10.10.1/32 +ip prefix-list pl seq 15 permit 10.10.10.2/32 ! diff --git a/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py index 18e25d5674..5781684a88 100644 --- a/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py +++ b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py @@ -83,8 +83,8 @@ def test_bgp_evpn_route_map_match_route_type(): ) expected = { "advertisedRoutes": { - "10.10.10.1:2": { - "[3]:[0]:[32]:[10.10.10.1]": { + "10.10.10.1:1": { + "[5]:[0]:[32]:[10.10.10.10]": { "valid": True, } }, @@ -102,7 +102,7 @@ def test_bgp_evpn_route_map_match_route_type(): _bgp_converge, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) - assert result is None, "MAC-IP EVPN routes should not be advertised" + assert result is None, "Filtered EVPN routes should not be advertised" if __name__ == "__main__": diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json index 98ae92ce55..45d00c6fa6 100644 --- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json @@ -1,7 +1,7 @@ { "vni":101, "type":"L2", - "vrf":"default", + "tenantVrf":"default", "vxlanInterface":"vxlan0", "vtepIp":"10.10.10.10", "mcastGroup":"0.0.0.0", diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json index 5c059786b2..f480b567ae 100644 --- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json @@ -1,7 +1,7 @@ { "vni":101, "type":"L2", - "vrf":"default", + "tenantVrf":"default", "vxlanInterface":"vxlan0", "vtepIp":"10.30.30.30", "mcastGroup":"0.0.0.0", diff --git a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py index a0cd89f064..d373a749fe 100644 --- a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py +++ b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py @@ -62,23 +62,48 @@ def teardown_module(mod): tgen.stop_topology() +expected_1 = { + "routes": { + "172.16.255.31/32": [{"path": "65002"}], + "172.16.255.32/32": [{"path": ""}], + } +} + +expected_2 = { + "routes": { + "172.16.255.31/32": [{"path": ""}], + "172.16.255.32/32": [{"path": ""}], + } +} + +expected_3 = { + "routes": { + "172.16.255.31/32": [{"path": "65003"}], + "172.16.255.32/32": [{"path": "65003"}], + } +} + +expected_4 = { + "routes": { + "172.16.255.31/32": [{"path": "65002 65003"}], + "172.16.255.32/32": [{"path": "65002 65003"}], + } +} + + +def bgp_converge(router, expected): + output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json")) + + return topotest.json_cmp(output, expected) + + def test_bgp_set_aspath_exclude(): tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) - def _bgp_converge(router): - output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json")) - expected = { - "routes": { - "172.16.255.31/32": [{"path": "65002"}], - "172.16.255.32/32": [{"path": ""}], - } - } - return topotest.json_cmp(output, expected) - - test_func = functools.partial(_bgp_converge, tgen.gears["r1"]) + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_1) _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed overriding incoming AS-PATH with route-map" @@ -102,19 +127,7 @@ conf """ ) - expected = { - "routes": { - "172.16.255.31/32": [{"path": ""}], - "172.16.255.32/32": [{"path": ""}], - } - } - - 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"]) + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_2) _, 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" @@ -127,19 +140,46 @@ conf """ ) - expected = { - "routes": { - "172.16.255.31/32": [{"path": "65003"}], - "172.16.255.32/32": [{"path": "65003"}], - } - } - - test_func = functools.partial(_bgp_regexp_1, tgen.gears["r1"]) + # tgen.mininet_cli() + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3) _, 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" +def test_no_bgp_set_aspath_exclude_access_list(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + rname = "r1" + r1 = tgen.gears[rname] + + r1.vtysh_cmd( + """ +conf + no bgp as-path access-list SECOND permit 2 + """ + ) + + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, "Failed removing bgp as-path access-list" + + r1.vtysh_cmd( + """ +clear bgp * + """ + ) + + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_4) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, "Failed to renegotiate with peers" + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_srv6_sid_reachability/c11/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c11/bgpd.conf new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c11/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c11/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c11/staticd.conf new file mode 100644 index 0000000000..bcf5a0499f --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c11/staticd.conf @@ -0,0 +1,4 @@ +! +ip route 0.0.0.0/0 192.168.1.254 +ipv6 route ::/0 2001:1::ffff +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c11/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c11/zebra.conf new file mode 100644 index 0000000000..0615cf9a95 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c11/zebra.conf @@ -0,0 +1,6 @@ +hostname c11 +! +interface eth0 + ip address 192.168.1.1/24 + ipv6 address 2001:1::1/64 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c12/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c12/bgpd.conf new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c12/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c12/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c12/staticd.conf new file mode 100644 index 0000000000..bcf5a0499f --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c12/staticd.conf @@ -0,0 +1,4 @@ +! +ip route 0.0.0.0/0 192.168.1.254 +ipv6 route ::/0 2001:1::ffff +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c12/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c12/zebra.conf new file mode 100644 index 0000000000..18985aa383 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c12/zebra.conf @@ -0,0 +1,6 @@ +hostname c12 +! +interface eth0 + ip address 192.168.1.1/24 + ipv6 address 2001:1::1/64 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c21/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c21/bgpd.conf new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c21/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c21/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c21/staticd.conf new file mode 100644 index 0000000000..608e60060e --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c21/staticd.conf @@ -0,0 +1,4 @@ +! +ip route 0.0.0.0/0 192.168.2.254 +ipv6 route ::/0 2001:2::ffff +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c21/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c21/zebra.conf new file mode 100644 index 0000000000..b8b70ac965 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c21/zebra.conf @@ -0,0 +1,6 @@ +hostname c21 +! +interface eth0 + ip address 192.168.2.1/24 + ipv6 address 2001:2::1/64 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c22/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c22/bgpd.conf new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c22/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c22/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c22/staticd.conf new file mode 100644 index 0000000000..277aae998c --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c22/staticd.conf @@ -0,0 +1,5 @@ + +! +ip route 0.0.0.0/0 192.168.2.254 +ipv6 route ::/0 2001:2::ffff +!
\ No newline at end of file diff --git a/tests/topotests/bgp_srv6_sid_reachability/c22/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c22/zebra.conf new file mode 100644 index 0000000000..cc764cc35c --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c22/zebra.conf @@ -0,0 +1,9 @@ +hostname c22 +! +interface eth0 + ip address 192.168.2.1/24 + ipv6 address 2001:2::1/64 +! +ip route 0.0.0.0/0 192.168.2.254 +ipv6 route ::/0 2001:2::ffff +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c31/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c31/bgpd.conf new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c31/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c31/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c31/staticd.conf new file mode 100644 index 0000000000..0c88575abd --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c31/staticd.conf @@ -0,0 +1,4 @@ +! +ip route 0.0.0.0/0 192.168.3.254 +ipv6 route ::/0 2001:3::ffff +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c31/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c31/zebra.conf new file mode 100644 index 0000000000..3f75641ea7 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c31/zebra.conf @@ -0,0 +1,6 @@ +hostname c31 +! +interface eth0 + ip address 192.168.3.1/24 + ipv6 address 2001:3::1/64 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c32/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c32/bgpd.conf new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c32/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c32/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c32/staticd.conf new file mode 100644 index 0000000000..0c88575abd --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c32/staticd.conf @@ -0,0 +1,4 @@ +! +ip route 0.0.0.0/0 192.168.3.254 +ipv6 route ::/0 2001:3::ffff +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c32/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c32/zebra.conf new file mode 100644 index 0000000000..c06a7d19f5 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c32/zebra.conf @@ -0,0 +1,6 @@ +hostname c32 +! +interface eth0 + ip address 192.168.3.1/24 + ipv6 address 2001:3::1/64 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r1/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/r1/bgpd.conf new file mode 100644 index 0000000000..573dbe0951 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r1/bgpd.conf @@ -0,0 +1,61 @@ +frr defaults traditional +! +hostname r1 +password zebra +! +log commands +! +router bgp 65001 + bgp router-id 192.0.2.1 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 2001:db8:12::2 remote-as 65002 + neighbor 2001:db8:12::2 timers 3 10 + neighbor 2001:db8:12::2 timers connect 1 + neighbor 2001:db8:12::2 capability extended-nexthop + neighbor 2001:db8:13::3 remote-as 65001 + neighbor 2001:db8:13::3 timers 3 10 + neighbor 2001:db8:13::3 timers connect 1 + neighbor 2001:db8:13::3 capability extended-nexthop + ! + segment-routing srv6 + locator default + ! + address-family ipv4 vpn + neighbor 2001:db8:12::2 activate + neighbor 2001:db8:13::3 activate + exit-address-family + ! +! +router bgp 65001 vrf vrf10 + bgp router-id 192.0.2.1 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 1 + rd vpn export 65001:10 + rt vpn both 0:10 + import vpn + export vpn + exit-address-family + ! +! +router bgp 65001 vrf vrf20 + bgp router-id 192.0.2.1 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 2 + rd vpn export 65001:20 + rt vpn both 0:20 + import vpn + export vpn + exit-address-family + ! +! +interface eth0 + mpls bgp forwarding +! +interface eth1 + mpls bgp forwarding +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r1/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/r1/staticd.conf new file mode 100644 index 0000000000..49b64fd7af --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r1/staticd.conf @@ -0,0 +1,4 @@ +! +ipv6 route 2001:db8:2:2::/64 2001:db8:12::2 +ipv6 route 2001:db8:3:3::/64 2001:db8:13::3 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r1/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/r1/zebra.conf new file mode 100644 index 0000000000..79dbf95593 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r1/zebra.conf @@ -0,0 +1,32 @@ +log file zebra.log +! +hostname r1 +! +interface lo + ipv6 address 2001:db8:1:1::1/128 +! +interface eth0 + ipv6 address 2001:db8:12::1/64 +! +interface eth1 + ipv6 address 2001:db8:13::1/64 +! +interface eth2 vrf vrf10 + ip address 192.168.1.254/24 +! +interface eth3 vrf vrf20 + ip address 192.168.1.254/24 +! +segment-routing + srv6 + locators + locator default + prefix 2001:db8:1:1::/64 + ! + ! +! +ip forwarding +ipv6 forwarding +! +line vty +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r2/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/r2/bgpd.conf new file mode 100644 index 0000000000..723d6fca2f --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r2/bgpd.conf @@ -0,0 +1,50 @@ +frr defaults traditional +! +hostname r2 +password zebra +! +log commands +! +router bgp 65002 + bgp router-id 192.0.2.2 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 2001:db8:12::1 remote-as 65001 + neighbor 2001:db8:12::1 timers 3 10 + neighbor 2001:db8:12::1 timers connect 1 + neighbor 2001:db8:12::1 capability extended-nexthop + ! + segment-routing srv6 + locator default + ! + address-family ipv4 vpn + neighbor 2001:db8:12::1 activate + exit-address-family + ! +! +router bgp 65002 vrf vrf10 + bgp router-id 192.0.2.2 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 1 + rd vpn export 65002:10 + rt vpn both 0:10 + import vpn + export vpn + exit-address-family + ! +! +router bgp 65002 vrf vrf20 + bgp router-id 192.0.2.2 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 2 + rd vpn export 65002:20 + rt vpn both 0:20 + import vpn + export vpn + exit-address-family + ! +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r2/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/r2/staticd.conf new file mode 100644 index 0000000000..8d80c1ead2 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r2/staticd.conf @@ -0,0 +1,4 @@ +! +ipv6 route 2001:db8:1:1::/64 2001:db8:12::1 +ipv6 route 2001:db8:3:3::/64 2001:db8:12::1 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r2/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/r2/zebra.conf new file mode 100644 index 0000000000..09a65b989c --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r2/zebra.conf @@ -0,0 +1,29 @@ +log file zebra.log +! +hostname r2 +! +interface lo + ipv6 address 2001:db8:2:2::1/128 +! +interface eth0 + ipv6 address 2001:db8:12::2/64 +! +interface eth1 vrf vrf10 + ip address 192.168.2.254/24 +! +interface eth2 vrf vrf20 + ip address 192.168.2.254/24 +! +segment-routing + srv6 + locators + locator default + prefix 2001:db8:2:2::/64 + ! + ! +! +ip forwarding +ipv6 forwarding +! +line vty +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r3/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/r3/bgpd.conf new file mode 100644 index 0000000000..c412cb6d29 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r3/bgpd.conf @@ -0,0 +1,50 @@ +frr defaults traditional +! +hostname r2 +password zebra +! +log commands +! +router bgp 65001 + bgp router-id 192.0.2.3 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 2001:db8:13::1 remote-as 65001 + neighbor 2001:db8:13::1 timers 3 10 + neighbor 2001:db8:13::1 timers connect 1 + neighbor 2001:db8:13::1 capability extended-nexthop + ! + segment-routing srv6 + locator default + ! + address-family ipv4 vpn + neighbor 2001:db8:13::1 activate + exit-address-family + ! +! +router bgp 65001 vrf vrf10 + bgp router-id 192.0.2.3 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 1 + rd vpn export 65001:10 + rt vpn both 0:10 + import vpn + export vpn + exit-address-family + ! +! +router bgp 65001 vrf vrf20 + bgp router-id 192.0.2.2 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 2 + rd vpn export 65001:20 + rt vpn both 0:20 + import vpn + export vpn + exit-address-family + ! +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r3/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/r3/staticd.conf new file mode 100644 index 0000000000..9d672d51ba --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r3/staticd.conf @@ -0,0 +1,6 @@ +! +ipv6 route 2001:db8:12::/64 2001:db8:13::1 +! +ipv6 route 2001:db8:1:1::/64 2001:db8:13::1 +ipv6 route 2001:db8:2:2::/64 2001:db8:13::1 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r3/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/r3/zebra.conf new file mode 100644 index 0000000000..a20cb76a74 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r3/zebra.conf @@ -0,0 +1,29 @@ +log file zebra.log +! +hostname r2 +! +interface lo + ipv6 address 2001:db8:3:3::1/128 +! +interface eth0 + ipv6 address 2001:db8:13::3/64 +! +interface eth1 vrf vrf10 + ip address 192.168.3.254/24 +! +interface eth2 vrf vrf20 + ip address 192.168.3.254/24 +! +segment-routing + srv6 + locators + locator default + prefix 2001:db8:3:3::/64 + ! + ! +! +ip forwarding +ipv6 forwarding +! +line vty +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py new file mode 100755 index 0000000000..92315bce04 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2023 by 6WIND +# + +import os +import re +import sys +import json +import functools +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +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, pytest.mark.staticd] + + +def build_topo(tgen): + tgen.add_router("r1") + tgen.add_router("r2") + tgen.add_router("r3") + + tgen.add_router("c11") + tgen.add_router("c12") + tgen.add_router("c21") + tgen.add_router("c22") + tgen.add_router("c31") + tgen.add_router("c32") + + tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "eth0", "eth0") + tgen.add_link(tgen.gears["r1"], tgen.gears["r3"], "eth1", "eth0") + tgen.add_link(tgen.gears["r1"], tgen.gears["c11"], "eth2", "eth0") + tgen.add_link(tgen.gears["r1"], tgen.gears["c12"], "eth3", "eth0") + tgen.add_link(tgen.gears["r2"], tgen.gears["c21"], "eth1", "eth0") + tgen.add_link(tgen.gears["r2"], tgen.gears["c22"], "eth2", "eth0") + tgen.add_link(tgen.gears["r3"], tgen.gears["c31"], "eth1", "eth0") + tgen.add_link(tgen.gears["r3"], tgen.gears["c32"], "eth2", "eth0") + + +def setup_module(mod): + result = required_linux_kernel_version("5.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + for rname, router in tgen.routers().items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.gears["r1"].run("sysctl net.vrf.strict_mode=1") + tgen.gears["r1"].run("ip link add vrf10 type vrf table 10") + tgen.gears["r1"].run("ip link set vrf10 up") + tgen.gears["r1"].run("ip link add vrf20 type vrf table 20") + tgen.gears["r1"].run("ip link set vrf20 up") + tgen.gears["r1"].run("ip link set eth2 master vrf10") + tgen.gears["r1"].run("ip link set eth3 master vrf20") + + tgen.gears["r2"].run("sysctl net.vrf.strict_mode=1") + tgen.gears["r2"].run("ip link add vrf10 type vrf table 10") + tgen.gears["r2"].run("ip link set vrf10 up") + tgen.gears["r2"].run("ip link add vrf20 type vrf table 20") + tgen.gears["r2"].run("ip link set vrf20 up") + tgen.gears["r2"].run("ip link set eth1 master vrf10") + tgen.gears["r2"].run("ip link set eth2 master vrf20") + + tgen.gears["r3"].run("sysctl net.vrf.strict_mode=1") + tgen.gears["r3"].run("ip link add vrf10 type vrf table 10") + tgen.gears["r3"].run("ip link set vrf10 up") + tgen.gears["r3"].run("ip link add vrf20 type vrf table 20") + tgen.gears["r3"].run("ip link set vrf20 up") + tgen.gears["r3"].run("ip link set eth1 master vrf10") + tgen.gears["r3"].run("ip link set eth2 master vrf20") + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_ping(): + tgen = get_topogen() + + 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) + + +def test_sid_unreachable_nht(): + get_topogen().gears["r1"].vtysh_cmd( + """ + configure terminal + no ipv6 route 2001:db8:2:2::/64 2001:db8:12::2 + """ + ) + check_ping("c11", "192.168.2.1", False, 10, 1) + + +def test_sid_reachable_again_nht(): + get_topogen().gears["r1"].vtysh_cmd( + """ + configure terminal + ipv6 route 2001:db8:2:2::/64 2001:db8:12::2 + """ + ) + check_ping("c11", "192.168.2.1", True, 10, 1) + + +def test_sid_unreachable_bgp_update(): + get_topogen().gears["r2"].vtysh_cmd( + """ + configure terminal + router bgp 65002 + no segment-routing srv6 + exit + router bgp 65002 vrf vrf10 + address-family ipv4 unicast + no sid vpn export 1 + """ + ) + check_ping("c11", "192.168.2.1", False, 10, 1) + + +def test_sid_reachable_again_bgp_update(): + get_topogen().gears["r2"].vtysh_cmd( + """ + configure terminal + router bgp 65002 + segment-routing srv6 + locator default + exit + exit + router bgp 65002 vrf vrf10 + address-family ipv4 unicast + sid vpn export 1 + """ + ) + check_ping("c11", "192.168.2.1", True, 10, 1) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf index f52f56b0e0..397f7938d2 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf +++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf @@ -12,7 +12,7 @@ router bgp 99 vrf DONNA address-family ipv4 unicast redistribute connected import vrf EVA - import vrf NOTEXISTING + import vrf ZITA import vrf default ! ! @@ -21,10 +21,10 @@ router bgp 99 vrf EVA address-family ipv4 unicast redistribute connected import vrf DONNA - import vrf NOTEXISTING + import vrf ZITA ! ! -router bgp 99 vrf NOTEXISTING +router bgp 99 vrf ZITA no bgp ebgp-requires-policy no bgp network import-check address-family ipv4 unicast diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py index ef813e9541..013ddfece9 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py +++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py @@ -24,7 +24,7 @@ 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 pytestmark = [pytest.mark.bgpd] @@ -126,11 +126,13 @@ def test_vrf_route_leak_donna(): "172.16.101.0/24": [ { "protocol": "bgp", + "selected": None, "nexthops": [ { - "interfaceIndex": 0, + "fib": None, "interfaceName": "unknown", "vrf": "Unknown", + "active": None, }, ], }, @@ -196,11 +198,13 @@ def test_vrf_route_leak_eva(): "172.16.101.0/24": [ { "protocol": "bgp", + "selected": None, "nexthops": [ { - "interfaceIndex": 0, + "fib": None, "interfaceName": "unknown", "vrf": "Unknown", + "active": None, }, ], }, @@ -214,7 +218,7 @@ def test_vrf_route_leak_eva(): assert result, "BGP VRF EVA check failed:\n{}".format(diff) -def test_vrf_route_leak_donna(): +def test_vrf_route_leak_default(): logger.info("Ensure that routes are leaked back and forth") tgen = get_topogen() # Don't run this test if we have any failure. @@ -223,37 +227,31 @@ def test_vrf_route_leak_donna(): r1 = tgen.gears["r1"] - # Test DONNA VRF. + # Test default VRF. expect = { "10.0.0.0/24": [ { - "protocol": "connected", - } - ], - "10.0.1.0/24": [ - { "protocol": "bgp", "selected": True, "nexthops": [ { "fib": True, - "interfaceName": "EVA", - "vrf": "EVA", + "interfaceName": "DONNA", + "vrf": "DONNA", "active": True, }, ], }, ], - "10.0.2.0/24": [{"protocol": "connected"}], - "10.0.3.0/24": [ + "10.0.2.0/24": [ { "protocol": "bgp", "selected": True, "nexthops": [ { "fib": True, - "interfaceName": "EVA", - "vrf": "EVA", + "interfaceName": "DONNA", + "vrf": "DONNA", "active": True, }, ], @@ -261,26 +259,73 @@ def test_vrf_route_leak_donna(): ], "10.0.4.0/24": [ { + "protocol": "connected", + } + ], + } + + test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF default check failed:\n{}".format(diff) + + +def test_ping(): + "Simple ping tests" + + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + logger.info("Ping from default to DONNA") + check_ping("r1", "10.0.0.1", True, 10, 0.5, source_addr="10.0.4.1") + + +def test_vrf_route_leak_donna_after_eva_down(): + logger.info("Ensure that route states change after EVA interface goes down") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +interface EVA + shutdown +""" + ) + + # Test DONNA VRF. + expect = { + "10.0.1.0/24": [ + { "protocol": "bgp", - "selected": True, + "selected": None, "nexthops": [ { - "fib": True, - "interfaceName": "lo", - "vrf": "default", - "active": True, + "fib": None, + "interfaceName": "EVA", + "vrf": "EVA", + "active": None, }, ], }, ], - "172.16.101.0/24": [ + "10.0.3.0/24": [ { "protocol": "bgp", + "selected": None, "nexthops": [ { - "interfaceIndex": 0, - "interfaceName": "unknown", - "vrf": "Unknown", + "fib": None, + "interfaceName": "EVA", + "vrf": "EVA", + "active": None, }, ], }, @@ -294,135 +339,157 @@ def test_vrf_route_leak_donna(): assert result, "BGP VRF DONNA check failed:\n{}".format(diff) -def test_vrf_route_leak_eva(): - logger.info("Ensure that routes are leaked back and forth") +def test_vrf_route_leak_donna_after_eva_up(): + logger.info("Ensure that route states change after EVA interface goes up") tgen = get_topogen() # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +interface EVA + no shutdown +""" + ) - # Test EVA VRF. + # Test DONNA VRF. expect = { - "10.0.0.0/24": [ + "10.0.1.0/24": [ { "protocol": "bgp", "selected": True, "nexthops": [ { "fib": True, - "interfaceName": "DONNA", - "vrf": "DONNA", + "interfaceName": "EVA", + "vrf": "EVA", "active": True, }, ], }, ], - "10.0.1.0/24": [ - { - "protocol": "connected", - } - ], - "10.0.2.0/24": [ + "10.0.3.0/24": [ { "protocol": "bgp", "selected": True, "nexthops": [ { "fib": True, - "interfaceName": "DONNA", - "vrf": "DONNA", + "interfaceName": "EVA", + "vrf": "EVA", "active": True, }, ], }, ], - "10.0.3.0/24": [ - { - "protocol": "connected", - } - ], + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + +def test_vrf_route_leak_donna_add_vrf_zita(): + logger.info("Add VRF ZITA and ensure that the route from VRF ZITA is updated") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.cmd("ip link add ZITA type vrf table 1003") + + # Test DONNA VRF. + expect = { "172.16.101.0/24": [ { "protocol": "bgp", + "selected": None, "nexthops": [ { - "interfaceIndex": 0, - "interfaceName": "unknown", - "vrf": "Unknown", + "fib": None, + "interfaceName": "ZITA", + "vrf": "ZITA", + "active": None, }, ], }, ], } + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + -def test_vrf_route_leak_default(): - logger.info("Ensure that routes are leaked back and forth") +def test_vrf_route_leak_donna_set_zita_up(): + logger.info("Set VRF ZITA up and ensure that the route from VRF ZITA is updated") tgen = get_topogen() # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +interface ZITA + no shutdown +""" + ) - # Test default VRF. + # Test DONNA VRF. expect = { - "10.0.0.0/24": [ - { - "protocol": "bgp", - "selected": True, - "nexthops": [ - { - "fib": True, - "interfaceName": "DONNA", - "vrf": "DONNA", - "active": True, - }, - ], - }, - ], - "10.0.2.0/24": [ + "172.16.101.0/24": [ { "protocol": "bgp", "selected": True, "nexthops": [ { "fib": True, - "interfaceName": "DONNA", - "vrf": "DONNA", + "interfaceName": "ZITA", + "vrf": "ZITA", "active": True, }, ], }, ], - "10.0.4.0/24": [ - { - "protocol": "connected", - } - ], } - test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) - assert result, "BGP VRF default check failed:\n{}".format(diff) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) -def test_ping(): - "Simple ping tests" - +def test_vrf_route_leak_donna_delete_vrf_zita(): + logger.info("Delete VRF ZITA and ensure that the route from VRF ZITA is deleted") tgen = get_topogen() - # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) r1 = tgen.gears["r1"] + r1.cmd("ip link delete ZITA") - logger.info("Ping from default to DONNA") - output = r1.run("ping -c 4 -w 4 -I 10.0.4.1 10.0.0.1") - assert " 0% packet loss" in output, "Ping default->DONNA FAILED" + # Test DONNA VRF. + expect = { + "172.16.101.0/24": None, + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) def test_memory_leak(): diff --git a/tests/topotests/lib/checkping.py b/tests/topotests/lib/checkping.py index aaa6164dd4..5500807fab 100644 --- a/tests/topotests/lib/checkping.py +++ b/tests/topotests/lib/checkping.py @@ -8,7 +8,7 @@ from lib.topolog import logger from lib import topotest -def check_ping(name, dest_addr, expect_connected, count, wait): +def check_ping(name, dest_addr, expect_connected, count, wait, source_addr=None): """ Assert that ping to dest_addr is expected * 'name': the router to set the ping from @@ -18,9 +18,13 @@ def check_ping(name, dest_addr, expect_connected, count, wait): * 'wait': how long ping should wait to receive all replies """ - def _check(name, dest_addr, match): + def _check(name, dest_addr, source_addr, match): tgen = get_topogen() - output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr)) + cmd = "ping {}".format(dest_addr) + if source_addr: + cmd += " -I {}".format(source_addr) + cmd += " -c 1 -w 1" + output = tgen.gears[name].run(cmd) logger.info(output) if match not in output: return "ping fail" @@ -28,6 +32,6 @@ def check_ping(name, dest_addr, expect_connected, count, wait): 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) + func = functools.partial(_check, name, dest_addr, source_addr, match) success, result = topotest.run_and_expect(func, None, count=count, wait=wait) assert result is None, "Failed" diff --git a/tests/topotests/lib/fe_client.py b/tests/topotests/lib/fe_client.py index 07059ccf3a..a47544633b 100755 --- a/tests/topotests/lib/fe_client.py +++ b/tests/topotests/lib/fe_client.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 eval: (blacken-mode 1) -*- # SPDX-License-Identifier: GPL-2.0-or-later # diff --git a/tests/topotests/mgmt_config/test_regression.py b/tests/topotests/mgmt_config/test_regression.py index 70f38d2ec7..928151a23a 100644 --- a/tests/topotests/mgmt_config/test_regression.py +++ b/tests/topotests/mgmt_config/test_regression.py @@ -51,3 +51,23 @@ def test_regression_issue_13920(tgen): ) output = r1.net.checkRouterCores() assert not output.strip() + + +def test_regression_pullreq_15423(tgen): + r1 = tgen.gears["r1"] + r1.vtysh_multicmd( + """ + conf t + access-list test seq 1 permit ip any 10.10.10.0 0.0.0.255 + """ + ) + + output = r1.vtysh_multicmd( + """ + conf terminal file-lock + mgmt delete-config /frr-filter:lib/access-list[name='test'][type='ipv4']/entry[sequence='1']/destination-network + mgmt commit apply + end + """ + ) + assert "No changes found" not in output diff --git a/tests/topotests/nb_config/r1/frr.conf b/tests/topotests/nb_config/r1/frr.conf new file mode 100644 index 0000000000..677ec0b86d --- /dev/null +++ b/tests/topotests/nb_config/r1/frr.conf @@ -0,0 +1,6 @@ +log timestamp precision 6 +log file frr.log + +interface r1-eth0 + ip address 1.1.1.1/24 +exit diff --git a/tests/topotests/nb_config/test_nb_config.py b/tests/topotests/nb_config/test_nb_config.py new file mode 100644 index 0000000000..f699a4e20e --- /dev/null +++ b/tests/topotests/nb_config/test_nb_config.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# February 24 2024, Christian Hopps <chopps@labn.net> +# +# Copyright (c) 2024, LabN Consulting, L.L.C. +# +""" +Test Northbound Config Operations +""" +import json +import os + +import pytest +from lib.topogen import Topogen +from lib.topotest import json_cmp + +pytestmark = [pytest.mark.mgmtd] + +CWD = os.path.dirname(os.path.realpath(__file__)) + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = { + "s1": ("r1",) + } + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + router.load_frr_config("frr.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def test_access_list_config_ordering(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + output = r1.vtysh_multicmd([ + "conf t", + "access-list test seq 1 permit host 10.0.0.1"]) + output = r1.vtysh_cmd("show ip access-list test json") + got = json.loads(output) + expected = json.loads('{"ZEBRA":{"test":{"type":"Standard", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "address":"10.0.0.1", "mask":"0.0.0.0"}]}}}') + result = json_cmp(got, expected) + assert result is None + + # + # If the northbound mis-orders the create/delete then this test fails. + # https://github.com/FRRouting/frr/pull/15423/commits/38b85e0c2bc555b8827dbd2cb6515b6febf548b4 + # + output = r1.vtysh_multicmd([ + "conf t", + "access-list test seq 1 permit 10.0.0.0/8"]) + output = r1.vtysh_cmd("show ip access-list test json") + got = json.loads(output) + expected = json.loads('{"ZEBRA":{"test":{"type":"Zebra", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "prefix":"10.0.0.0/8", "exact-match":false}]}}}') + result = json_cmp(got, expected) + assert result is None diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang index c50c51389e..c679f3b911 100644 --- a/yang/frr-bgp-route-map.yang +++ b/yang/frr-bgp-route-map.yang @@ -379,6 +379,7 @@ identity set-extcommunity-color { grouping extcommunity-non-transitive-types { leaf two-octet-as-specific { type boolean; + default false; description "Non-Transitive Two-Octet AS-Specific Extended Community"; } @@ -769,6 +770,7 @@ identity set-extcommunity-color { + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-extcommunity')"; container comm-list { leaf comm-list-name { + mandatory true; type bgp-filter:bgp-list-name; } @@ -872,11 +874,13 @@ identity set-extcommunity-color { description "Value of the ext-community."; leaf lb-type { + mandatory true; type frr-bgp-route-map:extcommunity-lb-type; } leaf bandwidth { when "../lb-type = 'explicit-bandwidth'"; + mandatory true; type uint16 { range "1..25600"; } @@ -1108,12 +1112,14 @@ identity set-extcommunity-color { container aggregator { leaf aggregator-asn { type asn-type; + mandatory true; description "ASN of the aggregator"; } leaf aggregator-address { type inet:ipv4-address; + mandatory true; description "IPv4 address of the aggregator"; } diff --git a/zebra/dpdk/zebra_dplane_dpdk.c b/zebra/dpdk/zebra_dplane_dpdk.c index 4c32044251..7a5388c57b 100644 --- a/zebra/dpdk/zebra_dplane_dpdk.c +++ b/zebra/dpdk/zebra_dplane_dpdk.c @@ -105,8 +105,7 @@ static int zd_dpdk_pbr_show_rules_walkcb(struct hash_bucket *bucket, void *arg) ifp = if_lookup_by_name_vrf(rule->ifname, vrf); if (ifp) - zd_dpdk_flow_stat_show(vty, ifp->ifindex, - zaction->dp_flow_ptr); + zd_dpdk_flow_stat_show(vty, ifp->ifindex, zaction->dp_flow_ptr); } return HASHWALK_CONTINUE; } @@ -153,8 +152,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL) zlog_debug( "PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; in_port %d missing\n", - dplane_ctx_rule_get_ifname(ctx), seq, pri, - unique, in_ifindex); + dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, in_ifindex); return; } @@ -163,8 +161,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL) zlog_debug( "PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; out_port %d missing\n", - dplane_ctx_rule_get_ifname(ctx), seq, pri, - unique, out_ifindex); + dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, out_ifindex); return; } @@ -180,7 +177,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) memset(&ip, 0, sizeof(ip)); memset(&ip_mask, 0, sizeof(ip_mask)); - if (filter_bm & PBR_FILTER_SRC_IP) { + if (CHECK_FLAG(filter_bm, PBR_FILTER_SRC_IP)) { const struct prefix *src_ip; src_ip = dplane_ctx_rule_get_src_ip(ctx); @@ -188,7 +185,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) masklen2ip(src_ip->prefixlen, &tmp_mask); ip_mask.hdr.src_addr = tmp_mask.s_addr; } - if (filter_bm & PBR_FILTER_DST_IP) { + if (CHECK_FLAG(filter_bm, PBR_FILTER_DST_IP)) { const struct prefix *dst_ip; dst_ip = dplane_ctx_rule_get_dst_ip(ctx); @@ -196,7 +193,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) masklen2ip(dst_ip->prefixlen, &tmp_mask); ip_mask.hdr.dst_addr = tmp_mask.s_addr; } - if (filter_bm & PBR_FILTER_IP_PROTOCOL) { + if (CHECK_FLAG(filter_bm, PBR_FILTER_IP_PROTOCOL)) { ip.hdr.next_proto_id = dplane_ctx_rule_get_ipproto(ctx); ip_mask.hdr.next_proto_id = UINT8_MAX; } @@ -206,17 +203,15 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) items[item_cnt].last = NULL; ++item_cnt; - if ((filter_bm & (PBR_FILTER_SRC_PORT | PBR_FILTER_DST_PORT))) { + if (CHECK_FLAG(filter_bm, (PBR_FILTER_SRC_PORT | PBR_FILTER_DST_PORT))) { memset(&udp, 0, sizeof(udp)); memset(&udp_mask, 0, sizeof(udp_mask)); - if (filter_bm & PBR_FILTER_SRC_PORT) { - udp.hdr.src_port = - RTE_BE16(dplane_ctx_rule_get_src_port(ctx)); + if (CHECK_FLAG(filter_bm, PBR_FILTER_SRC_PORT)) { + udp.hdr.src_port = RTE_BE16(dplane_ctx_rule_get_src_port(ctx)); udp_mask.hdr.src_port = UINT16_MAX; } - if (filter_bm & PBR_FILTER_DST_PORT) { - udp.hdr.dst_port = - RTE_BE16(dplane_ctx_rule_get_dst_port(ctx)); + if (CHECK_FLAG(filter_bm, PBR_FILTER_DST_PORT)) { + udp.hdr.dst_port = RTE_BE16(dplane_ctx_rule_get_dst_port(ctx)); udp_mask.hdr.dst_port = UINT16_MAX; } items[item_cnt].type = RTE_FLOW_ITEM_TYPE_UDP; @@ -273,8 +268,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) } else { zlog_warn( "PBR dpdk flow create failed ifname %s seq %d pri %u unique %d; rc %d\n", - dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, - error.type); + dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, error.type); } } @@ -562,7 +556,7 @@ void zd_dpdk_port_show(struct vty *vty, uint16_t port_id, bool uj, int detail) for (count = 0; count < RTE_MAX_ETHPORTS; ++count) { dport = &dpdk_ctx->dpdk_ports[count]; - if (dport->flags & ZD_DPDK_PORT_FLAG_INITED) + if (CHECK_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_INITED)) zd_dpdk_port_show_entry(dport, vty, detail); } } @@ -592,14 +586,14 @@ static void zd_dpdk_port_init(void) dport = &dpdk_ctx->dpdk_ports[count]; count++; dport->port_id = port_id; - dport->flags |= ZD_DPDK_PORT_FLAG_PROBED; + SET_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_PROBED); dev_info = &dport->dev_info; if (rte_eth_dev_info_get(port_id, dev_info) < 0) { zlog_warn("failed to get dev info for %u, %s", port_id, rte_strerror(rte_errno)); continue; } - dport->flags |= ZD_DPDK_PORT_FLAG_INITED; + SET_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_INITED); if (IS_ZEBRA_DEBUG_DPLANE_DPDK) zlog_debug( "port %u, dev %s, ifI %d, sw_name %s, sw_domain %u, sw_port %u", @@ -611,12 +605,10 @@ static void zd_dpdk_port_init(void) if (rte_flow_isolate(port_id, 1, &error)) { if (IS_ZEBRA_DEBUG_DPLANE_DPDK) zlog_debug( - "Flow isolate on port %u failed %d", - port_id, error.type); + "Flow isolate on port %u failed %d", port_id, error.type); } else { if (IS_ZEBRA_DEBUG_DPLANE_DPDK) - zlog_debug("Flow isolate on port %u", - port_id); + zlog_debug("Flow isolate on port %u", port_id); } rc = rte_eth_dev_start(port_id); if (rc) { @@ -625,8 +617,7 @@ static void zd_dpdk_port_init(void) continue; } if (IS_ZEBRA_DEBUG_DPLANE_DPDK) - zlog_debug("DPDK port %d started in promiscuous mode ", - port_id); + zlog_debug("DPDK port %d started in promiscuous mode ", port_id); } if (!count) { @@ -639,8 +630,7 @@ static void zd_dpdk_port_init(void) static int zd_dpdk_init(void) { int rc; - static const char *argv[] = {(char *)"/usr/lib/frr/zebra", - (char *)"--"}; + static const char *argv[] = {(char *)"/usr/lib/frr/zebra", (char *)"--"}; zd_dpdk_vty_init(); @@ -674,8 +664,7 @@ static int zd_dpdk_finish(struct zebra_dplane_provider *prov, bool early) if (early) { if (IS_ZEBRA_DEBUG_DPLANE_DPDK) - zlog_debug("%s early finish", - dplane_provider_get_name(prov)); + zlog_debug("%s early finish", dplane_provider_get_name(prov)); return 0; } diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index 147f5b93fa..ae9b3c49eb 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -109,21 +109,14 @@ void zebra_evpn_print(struct zebra_evpn *zevpn, void **ctxt) } else { json_object_int_add(json, "vni", zevpn->vni); json_object_string_add(json, "type", "L2"); -#if CONFDATE > 20240210 -CPP_NOTICE("Drop `vrf` from JSON output") -#endif - json_object_string_add(json, "vrf", - vrf_id_to_name(zevpn->vrf_id)); - json_object_string_add(json, "tenantVrf", - vrf_id_to_name(zevpn->vrf_id)); + json_object_string_add(json, "tenantVrf", vrf_id_to_name(zevpn->vrf_id)); } if (!zevpn->vxlan_if) { // unexpected if (json == NULL) vty_out(vty, " VxLAN interface: unknown\n"); else - json_object_string_add(json, "vxlanInterface", - "unknown"); + json_object_string_add(json, "vxlanInterface", "unknown"); return; } num_macs = num_valid_macs(zevpn); @@ -135,35 +128,21 @@ CPP_NOTICE("Drop `vrf` from JSON output") (zevpn->svi_if ? zevpn->svi_if->name : "")); vty_out(vty, " SVI ifIndex: %u\n", (zevpn->svi_if ? zevpn->svi_if->ifindex : 0)); - vty_out(vty, " Local VTEP IP: %pI4\n", - &zevpn->local_vtep_ip); - vty_out(vty, " Mcast group: %pI4\n", - &zevpn->mcast_grp); + vty_out(vty, " Local VTEP IP: %pI4\n", &zevpn->local_vtep_ip); + vty_out(vty, " Mcast group: %pI4\n", &zevpn->mcast_grp); } else { - json_object_string_add(json, "vxlanInterface", - zevpn->vxlan_if->name); -#if CONFDATE > 20240210 -CPP_NOTICE("Drop `ifindex` from JSON output") -#endif - json_object_int_add(json, "ifindex", zevpn->vxlan_if->ifindex); - json_object_int_add(json, "vxlanIfindex", - zevpn->vxlan_if->ifindex); + json_object_string_add(json, "vxlanInterface", zevpn->vxlan_if->name); + json_object_int_add(json, "vxlanIfindex", zevpn->vxlan_if->ifindex); if (zevpn->svi_if) { - json_object_string_add(json, "sviInterface", - zevpn->svi_if->name); - json_object_int_add(json, "sviIfindex", - zevpn->svi_if->ifindex); + json_object_string_add(json, "sviInterface", zevpn->svi_if->name); + json_object_int_add(json, "sviIfindex", zevpn->svi_if->ifindex); } - json_object_string_addf(json, "vtepIp", "%pI4", - &zevpn->local_vtep_ip); - json_object_string_addf(json, "mcastGroup", "%pI4", - &zevpn->mcast_grp); + json_object_string_addf(json, "vtepIp", "%pI4", &zevpn->local_vtep_ip); + json_object_string_addf(json, "mcastGroup", "%pI4", &zevpn->mcast_grp); json_object_string_add(json, "advertiseGatewayMacip", - zevpn->advertise_gw_macip ? "Yes" - : "No"); + zevpn->advertise_gw_macip ? "Yes" : "No"); json_object_string_add(json, "advertiseSviMacip", - zevpn->advertise_svi_macip ? "Yes" - : "No"); + zevpn->advertise_svi_macip ? "Yes" : "No"); json_object_int_add(json, "numMacs", num_macs); json_object_int_add(json, "numArpNd", num_neigh); } @@ -179,28 +158,21 @@ CPP_NOTICE("Drop `ifindex` from JSON output") json_vtep_list = json_object_new_array(); for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) { const char *flood_str = lookup_msg( - zvtep_flood_str, zvtep->flood_control, - VXLAN_FLOOD_STR_DEFAULT); + zvtep_flood_str, zvtep->flood_control, VXLAN_FLOOD_STR_DEFAULT); if (json == NULL) { - vty_out(vty, " %pI4 flood: %s\n", - &zvtep->vtep_ip, - flood_str); + vty_out(vty, " %pI4 flood: %s\n", &zvtep->vtep_ip, flood_str); } else { json_vtep = json_object_new_object(); - json_object_string_addf(json_vtep, "ip", "%pI4", - &zvtep->vtep_ip); - json_object_string_add(json_vtep, "flood", - flood_str); - json_object_array_add(json_vtep_list, - json_vtep); + json_object_string_addf(json_vtep, "ip", "%pI4", &zvtep->vtep_ip); + json_object_string_add(json_vtep, "flood", flood_str); + json_object_array_add(json_vtep_list, json_vtep); } num_vteps++; } if (json) { json_object_int_add(json, "numRemoteVteps", num_vteps); - json_object_object_add(json, "remoteVteps", - json_vtep_list); + json_object_object_add(json, "remoteVteps", json_vtep_list); } } if (json == NULL) { @@ -261,8 +233,7 @@ void zebra_evpn_print_hash(struct hash_bucket *bucket, void *ctxt[]) json_object_int_add(json_evpn, "vni", zevpn->vni); json_object_string_add(json_evpn, "type", "L2"); json_object_string_add(json_evpn, "vxlanIf", - zevpn->vxlan_if ? zevpn->vxlan_if->name - : "unknown"); + zevpn->vxlan_if ? zevpn->vxlan_if->name : "unknown"); json_object_int_add(json_evpn, "numMacs", num_macs); json_object_int_add(json_evpn, "numArpNd", num_neigh); json_object_int_add(json_evpn, "numRemoteVteps", num_vteps); @@ -272,13 +243,10 @@ void zebra_evpn_print_hash(struct hash_bucket *bucket, void *ctxt[]) json_vtep_list = json_object_new_array(); for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) { json_ip_str = json_object_new_string( - inet_ntop(AF_INET, &zvtep->vtep_ip, buf, - sizeof(buf))); - json_object_array_add(json_vtep_list, - json_ip_str); + inet_ntop(AF_INET, &zvtep->vtep_ip, buf, sizeof(buf))); + json_object_array_add(json_vtep_list, json_ip_str); } - json_object_object_add(json_evpn, "remoteVteps", - json_vtep_list); + json_object_object_add(json_evpn, "remoteVteps", json_vtep_list); } json_object_object_add(json, vni_str, json_evpn); } @@ -490,8 +458,7 @@ int zebra_evpn_gw_macip_del(struct interface *ifp, struct zebra_evpn *zevpn, /* Remove neighbor from BGP. */ zebra_evpn_neigh_send_del_to_client(zevpn->vni, &n->ip, &n->emac, - n->flags, ZEBRA_NEIGH_ACTIVE, - false /*force*/); + n->flags, ZEBRA_NEIGH_ACTIVE, false /*force*/); /* Delete this neighbor entry. */ zebra_evpn_neigh_del(zevpn, n); @@ -521,8 +488,7 @@ void zebra_evpn_gw_macip_del_for_evpn_hash(struct hash_bucket *bucket, */ if (zevpn->advertise_gw_macip) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip", - zevpn->vni); + zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip", zevpn->vni); return; } @@ -694,8 +660,7 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns, if (zif->brslave_info.br_if != br_if) continue; - vni_id = - zebra_vxlan_if_access_vlan_vni_find(zif, br_if); + vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if); if (vni_id) { found = 1; break; @@ -732,9 +697,7 @@ struct zebra_evpn *zebra_evpn_map_vlan(struct interface *ifp, in_param.zif = zif; p_zevpn = &zevpn; - ns_walk_func(zebra_evpn_map_vlan_ns, - (void *)&in_param, - (void **)p_zevpn); + ns_walk_func(zebra_evpn_map_vlan_ns, (void *)&in_param, (void **)p_zevpn); return zevpn; } @@ -854,9 +817,7 @@ struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp, return zevpn; } -static int zvni_map_to_macvlan_ns(struct ns *ns, - void *_in_param, - void **_p_ifp) +static int zvni_map_to_macvlan_ns(struct ns *ns, void *_in_param, void **_p_ifp) { struct zebra_ns *zns = ns->info; struct zebra_from_svi_param *in_param = @@ -918,9 +879,7 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if, p_ifp = &tmp_if; /* Identify corresponding VLAN interface. */ - ns_walk_func(zvni_map_to_macvlan_ns, - (void *)&in_param, - (void **)p_ifp); + ns_walk_func(zvni_map_to_macvlan_ns, (void *)&in_param, (void **)p_ifp); return tmp_if; } @@ -1125,8 +1084,7 @@ struct zebra_evpn *zebra_evpn_add(vni_t vni) /* Create hash table for MAC */ zevpn->mac_table = zebra_mac_db_create(buffer); - snprintf(buffer, sizeof(buffer), "Zebra EVPN Neighbor Table vni: %u", - vni); + snprintf(buffer, sizeof(buffer), "Zebra EVPN Neighbor Table vni: %u", vni); /* Create hash table for neighbors */ zevpn->neigh_table = zebra_neigh_db_create(buffer); @@ -1205,8 +1163,8 @@ int zebra_evpn_send_add_to_client(struct zebra_evpn *zevpn) client->vniadd_cnt++; rc = zserv_send_message(client, s); - if (!(zevpn->flags & ZEVPN_READY_FOR_BGP)) { - zevpn->flags |= ZEVPN_READY_FOR_BGP; + if (!CHECK_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP)) { + SET_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP); /* once the EVPN is sent the ES-EVIs can also be replayed * to BGP */ @@ -1228,8 +1186,8 @@ int zebra_evpn_send_del_to_client(struct zebra_evpn *zevpn) if (!client) return 0; - if (zevpn->flags & ZEVPN_READY_FOR_BGP) { - zevpn->flags &= ~ZEVPN_READY_FOR_BGP; + if (CHECK_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP)) { + UNSET_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP); /* the ES-EVIs must be removed from BGP before the EVPN is */ zebra_evpn_update_all_es(zevpn); } @@ -1350,8 +1308,7 @@ int zebra_evpn_vtep_install(struct zebra_evpn *zevpn, struct zebra_vtep *zvtep) if (is_vxlan_flooding_head_end() && (zvtep->flood_control == VXLAN_FLOOD_HEAD_END_REPL)) { if (ZEBRA_DPLANE_REQUEST_FAILURE == - dplane_vtep_add(zevpn->vxlan_if, - &zvtep->vtep_ip, zevpn->vni)) + dplane_vtep_add(zevpn->vxlan_if, &zvtep->vtep_ip, zevpn->vni)) return -1; } @@ -1442,9 +1399,7 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn, zevpn->vni, macaddr, ipa_len ? " IP " : "", - ipa_len ? ipaddr2str(ipaddr, ipbuf, - sizeof(ipbuf)) - : "", + ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "", sticky ? " sticky" : "", remote_gw ? " remote_gw" : ""); return; @@ -1459,16 +1414,13 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn, mac = zebra_evpn_mac_lookup(zevpn, macaddr); if (!mac) { mac = zebra_evpn_proc_sync_mac_update(zevpn, macaddr, - ipa_len, ipaddr, - flags, seq, esi); + ipa_len, ipaddr, flags, seq, esi); } if (!mac) return; n = zebra_evpn_neigh_lookup(zevpn, ipaddr); - if (n - && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq, - true)) + if (n && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq, true)) return; zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr, @@ -1514,22 +1466,19 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, * SYNC - if ES is local * REMOTE - if ES is not local */ - if (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) { + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SYNC_PATH)) { struct zebra_evpn_es *es; es = zebra_evpn_es_find(esi); - if (es && (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)) { + if (es && CHECK_FLAG(es->flags, ZEBRA_EVPNES_READY_FOR_BGP)) { zebra_evpn_process_sync_macip_add(zevpn, macaddr, - ipa_len, ipaddr, - flags, seq, esi); + ipa_len, ipaddr, flags, seq, esi); } else { if (IS_ZEBRA_DEBUG_EVPN_MH_ES) { char esi_str[ESI_STR_LEN]; esi_to_str(esi, esi_str, sizeof(esi_str)); - zlog_debug( - "Ignore sync-macip add; ES %s is not ready", - esi_str); + zlog_debug("Ignore sync-macip add; ES %s is not ready", esi_str); } } @@ -1543,8 +1492,7 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, if (vtep_ip.s_addr) { zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip); if (!zvtep) { - zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, - VXLAN_FLOOD_DISABLED); + zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, VXLAN_FLOOD_DISABLED); if (!zvtep) { flog_err( EC_ZEBRA_VTEP_ADD_FAILED, @@ -1621,9 +1569,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr, vnip = zebra_vxlan_if_vni_find(zif, vni); if (!vnip) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "VNI %u not in interface upon remote MACIP DEL", - vni); + zlog_debug("VNI %u not in interface upon remote MACIP DEL", vni); return; } diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c index 7e1c43c204..e1ca5ec19b 100644 --- a/zebra/zebra_nb.c +++ b/zebra/zebra_nb.c @@ -456,6 +456,8 @@ const struct frr_yang_module_info frr_zebra_info = { { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities", .cbs = { + .create = lib_interface_zebra_affinities_create, + .destroy = lib_interface_zebra_affinities_destroy, }, }, { @@ -531,6 +533,13 @@ const struct frr_yang_module_info frr_zebra_info = { } }, { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0", + .cbs = { + .create = lib_interface_zebra_evpn_mh_type_0_create, + .destroy = lib_interface_zebra_evpn_mh_type_0_destroy, + } + }, + { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi", .cbs = { .modify = lib_interface_zebra_evpn_mh_type_0_esi_modify, @@ -538,6 +547,13 @@ const struct frr_yang_module_info frr_zebra_info = { } }, { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3", + .cbs = { + .create = lib_interface_zebra_evpn_mh_type_3_create, + .destroy = lib_interface_zebra_evpn_mh_type_3_destroy, + } + }, + { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac", .cbs = { .modify = lib_interface_zebra_evpn_mh_type_3_system_mac_modify, diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index 97979ef962..d7cf5f4040 100644 --- a/zebra/zebra_nb.h +++ b/zebra/zebra_nb.h @@ -145,6 +145,8 @@ int lib_interface_zebra_link_params_utilized_bandwidth_destroy( int lib_interface_zebra_legacy_admin_group_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_legacy_admin_group_destroy( struct nb_cb_destroy_args *args); +int lib_interface_zebra_affinities_create(struct nb_cb_create_args *args); +int lib_interface_zebra_affinities_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args); int lib_interface_zebra_affinity_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_affinity_mode_modify(struct nb_cb_modify_args *args); @@ -175,9 +177,13 @@ int lib_interface_zebra_link_params_packet_loss_modify( struct nb_cb_modify_args *args); int lib_interface_zebra_link_params_packet_loss_destroy( struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_0_create(struct nb_cb_create_args *args); +int lib_interface_zebra_evpn_mh_type_0_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_evpn_mh_type_0_esi_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_evpn_mh_type_0_esi_destroy( struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_3_create(struct nb_cb_create_args *args); +int lib_interface_zebra_evpn_mh_type_3_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_evpn_mh_type_3_system_mac_modify( struct nb_cb_modify_args *args); int lib_interface_zebra_evpn_mh_type_3_system_mac_destroy( diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c index 46c95e6c0f..5cb9985ee4 100644 --- a/zebra/zebra_nb_config.c +++ b/zebra/zebra_nb_config.c @@ -1746,9 +1746,6 @@ int lib_interface_zebra_legacy_admin_group_modify( iflp->admin_grp = admin_group_value; SET_PARAM(iflp, LP_ADM_GRP); - - admin_group_clear(&iflp->ext_admin_grp); - UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); break; } return NB_OK; @@ -1778,6 +1775,35 @@ int lib_interface_zebra_legacy_admin_group_destroy( /* * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities + */ +int lib_interface_zebra_affinities_create(struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_interface_zebra_affinities_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->admin_grp = 0; + UNSET_PARAM(iflp, LP_ADM_GRP); + + admin_group_clear(&iflp->ext_admin_grp); + UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); + + return NB_OK; +} + +/* + * XPath: * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity */ int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args) @@ -2282,6 +2308,27 @@ static bool esi_unique(struct lyd_node *dnode) } /* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0 + */ +int lib_interface_zebra_evpn_mh_type_0_create(struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_0_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_type0_esi_update(ifp->info, NULL); + + return NB_OK; +} + +/* * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi */ int lib_interface_zebra_evpn_mh_type_0_esi_modify(struct nb_cb_modify_args *args) @@ -2325,6 +2372,28 @@ int lib_interface_zebra_evpn_mh_type_0_esi_destroy(struct nb_cb_destroy_args *ar } /* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3 + */ +int lib_interface_zebra_evpn_mh_type_3_create(struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_3_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_sys_mac_update(ifp->info, NULL); + zebra_evpn_es_lid_update(ifp->info, 0); + + return NB_OK; +} + +/* * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac */ int lib_interface_zebra_evpn_mh_type_3_system_mac_modify( diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 64eae38fc9..cc12cb4221 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -769,10 +769,6 @@ static void zl3vni_print(struct zebra_l3vni *zl3vni, void **ctx) json_evpn_list = json_object_new_array(); json_object_int_add(json, "vni", zl3vni->vni); json_object_string_add(json, "type", "L3"); -#if CONFDATE > 20240210 -CPP_NOTICE("Drop `vrf` from JSON outputs") -#endif - json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni)); json_object_string_add(json, "tenantVrf", zl3vni_vrf_name(zl3vni)); json_object_string_addf(json, "localVtepIp", "%pI4", |
