From 852d9f97570045dc4186940d424c856995999fbb Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 26 Oct 2021 17:55:54 -0400 Subject: [PATCH] bgpd,zebra,lib: bgp evpn vni macip into two tables Re-work the bgp vni table to use separately keyed tables for type2 routes. So, with type2 routes, we have the main table keyed off of the IP and a new MAC table keyed off of MACs. By separating out the two, we are able to run path selection separately for the neigh and mac. Keeping the two separate is also more in-line with what happens in zebra (they are managed comptletely seperate). With this change type2 routes go into each table like so: ``` Remote MAC-IP -> IP Table & MAC Table Remote MAC -> MAC Table Local MAC-IP -> IP Table Local MAC -> MAC Table ``` The difference for local is necessary because we should not ever allow multiple paths for a local MAC. Also cleaned up the commands for querying the vni tables: ``` show bgp vni all type ... show bgp vni VNI type ... ``` Old commands will be deprecated in a separate commit. Signed-off-by: Stephen Worley --- bgpd/bgp_evpn.c | 858 +++++++++++++++++++++++++++------------ bgpd/bgp_evpn_mh.c | 4 +- bgpd/bgp_evpn_private.h | 92 ++++- bgpd/bgp_evpn_vty.c | 729 +++++++++++++++++++++++++++++---- bgpd/bgp_evpn_vty.h | 6 + bgpd/bgp_route.h | 5 +- lib/command.h | 2 + zebra/zebra_evpn.c | 58 ++- zebra/zebra_evpn_mac.c | 131 +++--- zebra/zebra_evpn_mac.h | 33 +- zebra/zebra_evpn_neigh.c | 17 +- zebra/zebra_evpn_neigh.h | 2 +- 12 files changed, 1473 insertions(+), 464 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index f50a45e940..6d402a4fef 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -66,7 +66,6 @@ DEFINE_QOBJ_TYPE(bgp_evpn_es); /* * Static function declarations */ -static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn); static void bgp_evpn_remote_ip_hash_init(struct bgpevpn *evpn); static void bgp_evpn_remote_ip_hash_destroy(struct bgpevpn *evpn); static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn, @@ -572,12 +571,22 @@ struct bgp_dest *bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi, } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && local_pi) { /* - * prefix in the global table needs MAC, ensure it's present, - * using one from local table's path_info. + * prefix in the global table needs MAC/IP, ensure they are + * present, using one's from local table's path_info. */ - evpn_type2_prefix_global_copy( - &global_p, evp, - *evpn_type2_path_info_get_mac(local_pi)); + if (is_evpn_prefix_ipaddr_none(evp)) { + /* VNI MAC -> Global */ + evpn_type2_prefix_global_copy( + &global_p, evp, NULL /* mac */, + evpn_type2_path_info_get_ip(local_pi)); + } else { + /* VNI IP -> Global */ + evpn_type2_prefix_global_copy( + &global_p, evp, + evpn_type2_path_info_get_mac(local_pi), + NULL /* ip */); + } + evp = &global_p; } return bgp_afi_node_get(table, afi, safi, (struct prefix *)evp, prd); @@ -603,23 +612,33 @@ bgp_evpn_global_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi, } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && local_pi) { /* - * prefix in the global table needs MAC, ensure it's present, - * using one from local table's path_info. + * prefix in the global table needs MAC/IP, ensure they are + * present, using one's from local table's path_info. */ - evpn_type2_prefix_global_copy( - &global_p, evp, - *evpn_type2_path_info_get_mac(local_pi)); + if (is_evpn_prefix_ipaddr_none(evp)) { + /* VNI MAC -> Global */ + evpn_type2_prefix_global_copy( + &global_p, evp, NULL /* mac */, + evpn_type2_path_info_get_ip(local_pi)); + } else { + /* VNI IP -> Global */ + evpn_type2_prefix_global_copy( + &global_p, evp, + evpn_type2_path_info_get_mac(local_pi), + NULL /* ip */); + } + evp = &global_p; } return bgp_afi_node_lookup(table, afi, safi, (struct prefix *)evp, prd); } /* - * Wrapper for node get in VNI table. + * Wrapper for node get in VNI IP table. */ -struct bgp_dest *bgp_evpn_vni_node_get(struct bgp_table *const table, - const struct prefix_evpn *evp, - const struct bgp_path_info *parent_pi) +struct bgp_dest *bgp_evpn_vni_ip_node_get(struct bgp_table *const table, + const struct prefix_evpn *evp, + const struct bgp_path_info *parent_pi) { struct prefix_evpn vni_p; @@ -627,29 +646,30 @@ struct bgp_dest *bgp_evpn_vni_node_get(struct bgp_table *const table, /* prefix in the global table doesn't include the VTEP-IP so * we need to create a different copy for the VNI */ - evpn_type1_prefix_vni_copy(&vni_p, evp, - parent_pi->attr->nexthop); + evpn_type1_prefix_vni_ip_copy(&vni_p, evp, + parent_pi->attr->nexthop); evp = &vni_p; - } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && - !is_evpn_prefix_ipaddr_none(evp)) { + } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + /* Only MAC-IP should go into this table, not mac-only */ + assert(is_evpn_prefix_ipaddr_none(evp) == false); + /* - * IP prefix in the vni table doesn't include MAC so + * prefix in the vni IP table doesn't include MAC so * we need to create a different copy of the prefix. - * - * However, if it's MAC-only, keep it. */ - evpn_type2_prefix_vni_copy(&vni_p, evp); + evpn_type2_prefix_vni_ip_copy(&vni_p, evp); evp = &vni_p; } return bgp_node_get(table, (struct prefix *)evp); } /* - * Wrapper for node lookup in VNI table. + * Wrapper for node lookup in VNI IP table. */ -struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgp_table *const table, - const struct prefix_evpn *evp, - const struct bgp_path_info *parent_pi) +struct bgp_dest * +bgp_evpn_vni_ip_node_lookup(const struct bgp_table *const table, + const struct prefix_evpn *evp, + const struct bgp_path_info *parent_pi) { struct prefix_evpn vni_p; @@ -657,23 +677,96 @@ struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgp_table *const table, /* prefix in the global table doesn't include the VTEP-IP so * we need to create a different copy for the VNI */ - evpn_type1_prefix_vni_copy(&vni_p, evp, - parent_pi->attr->nexthop); + evpn_type1_prefix_vni_ip_copy(&vni_p, evp, + parent_pi->attr->nexthop); evp = &vni_p; - } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && - !is_evpn_prefix_ipaddr_none(evp)) { + } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + /* Only MAC-IP should go into this table, not mac-only */ + assert(is_evpn_prefix_ipaddr_none(evp) == false); + /* - * IP prefix in the vni table doesn't include MAC so + * prefix in the vni IP table doesn't include MAC so * we need to create a different copy of the prefix. - * - * However, if it's MAC-only, keep it. */ - evpn_type2_prefix_vni_copy(&vni_p, evp); + evpn_type2_prefix_vni_ip_copy(&vni_p, evp); evp = &vni_p; } return bgp_node_lookup(table, (struct prefix *)evp); } +/* + * Wrapper for node get in VNI MAC table. + */ +struct bgp_dest * +bgp_evpn_vni_mac_node_get(struct bgp_table *const table, + const struct prefix_evpn *evp, + const struct bgp_path_info *parent_pi) +{ + struct prefix_evpn vni_p; + + /* Only type-2 should ever go into this table */ + assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE); + + /* + * prefix in the vni MAC table doesn't include IP so + * we need to create a different copy of the prefix. + */ + evpn_type2_prefix_vni_mac_copy(&vni_p, evp); + evp = &vni_p; + return bgp_node_get(table, (struct prefix *)evp); +} + +/* + * Wrapper for node lookup in VNI MAC table. + */ +struct bgp_dest * +bgp_evpn_vni_mac_node_lookup(const struct bgp_table *const table, + const struct prefix_evpn *evp, + const struct bgp_path_info *parent_pi) +{ + struct prefix_evpn vni_p; + + /* Only type-2 should ever go into this table */ + assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE); + + /* + * prefix in the vni MAC table doesn't include IP so + * we need to create a different copy of the prefix. + */ + evpn_type2_prefix_vni_mac_copy(&vni_p, evp); + evp = &vni_p; + return bgp_node_lookup(table, (struct prefix *)evp); +} + +/* + * Wrapper for node get in both VNI tables. + */ +struct bgp_dest *bgp_evpn_vni_node_get(struct bgpevpn *vpn, + const struct prefix_evpn *p, + const struct bgp_path_info *parent_pi) +{ + if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) && + (is_evpn_prefix_ipaddr_none(p) == true)) + return bgp_evpn_vni_mac_node_get(vpn->mac_table, p, parent_pi); + + return bgp_evpn_vni_ip_node_get(vpn->ip_table, p, parent_pi); +} + +/* + * Wrapper for node lookup in both VNI tables. + */ +struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn, + const struct prefix_evpn *p, + const struct bgp_path_info *parent_pi) +{ + if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) && + (is_evpn_prefix_ipaddr_none(p) == true)) + return bgp_evpn_vni_mac_node_lookup(vpn->mac_table, p, + parent_pi); + + return bgp_evpn_vni_ip_node_lookup(vpn->ip_table, p, parent_pi); +} + /* * Add (update) or delete MACIP from zebra. */ @@ -756,8 +849,9 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, zlog_debug( "Tx %s MACIP, VNI %u MAC %pEA IP %pIA flags 0x%x seq %u remote VTEP %pI4 esi %s", add ? "ADD" : "DEL", vpn->vni, - &p->prefix.macip_addr.mac, &p->prefix.macip_addr.ip, - flags, seq, &remote_vtep_ip, esi_buf); + (mac ? mac : &p->prefix.macip_addr.mac), + &p->prefix.macip_addr.ip, flags, seq, &remote_vtep_ip, + esi_buf); } frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip, @@ -1090,7 +1184,11 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, } ret = bgp_zebra_send_remote_macip( - bgp, vpn, p, evpn_type2_path_info_get_mac(pi), + bgp, vpn, p, + (is_evpn_prefix_ipaddr_none(p) + ? NULL /* MAC update */ + : evpn_type2_path_info_get_mac( + pi) /* MAC-IP update */), pi->attr->nexthop, 1, flags, seq, bgp_evpn_attr_get_esi(pi->attr)); } else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE) { @@ -1124,7 +1222,11 @@ static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) ret = bgp_zebra_send_remote_macip( - bgp, vpn, p, evpn_type2_path_info_get_mac(pi), + bgp, vpn, p, + (is_evpn_prefix_ipaddr_none(p) + ? NULL /* MAC update */ + : evpn_type2_path_info_get_mac( + pi) /* MAC-IP update */), (is_sync ? zero_vtep_ip : pi->attr->nexthop), 0, 0, 0, NULL); else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE) @@ -1635,13 +1737,14 @@ static void update_evpn_route_entry_sync_info(struct bgp *bgp, } /* - * Create or update EVPN route entry. This could be in the VNI route table + * Create or update EVPN route entry. This could be in the VNI route tables * or the global route table. */ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, afi_t afi, safi_t safi, struct bgp_dest *dest, struct attr *attr, - const struct ethaddr *mac, int add, + const struct ethaddr *mac, + const struct ipaddr *ip, int add, struct bgp_path_info **pi, uint8_t flags, uint32_t seq, bool vpn_rt, bool *old_is_sync) { @@ -1716,9 +1819,12 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, memcpy(&tmp_pi->extra->label, label, sizeof(label)); tmp_pi->extra->num_labels = num_labels; - if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && mac) - evpn_type2_path_info_set_mac(tmp_pi, *mac); - + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + if (mac) + evpn_type2_path_info_set_mac(tmp_pi, *mac); + else if (ip) + evpn_type2_path_info_set_ip(tmp_pi, *ip); + } /* Mark route as self type-2 route */ if (flags && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP)) @@ -1749,9 +1855,14 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, memcpy(&tmp_pi->extra->label, label, sizeof(label)); tmp_pi->extra->num_labels = num_labels; - if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && - mac) - evpn_type2_path_info_set_mac(tmp_pi, *mac); + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + if (mac) + evpn_type2_path_info_set_mac(tmp_pi, + *mac); + else if (ip) + evpn_type2_path_info_set_ip(tmp_pi, + *ip); + } /* The attribute has changed. */ /* Add (or update) attribute to hash. */ @@ -1872,6 +1983,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, safi_t safi = SAFI_EVPN; int route_change; bool old_is_sync = false; + bool mac_only = false; memset(&attr, 0, sizeof(attr)); @@ -1931,13 +2043,19 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, /* Set up extended community. */ build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm); - /* First, create (or fetch) route node within the VNI. */ - /* NOTE: There is no RD here. */ - dest = bgp_evpn_vni_node_get(vpn->route_table, p, NULL); + /* First, create (or fetch) route node within the VNI. + * NOTE: There is no RD here. + */ + dest = bgp_evpn_vni_node_get(vpn, p, NULL); + + if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) && + (is_evpn_prefix_ipaddr_none(p) == true)) + mac_only = true; /* Create or update route entry. */ route_change = update_evpn_route_entry( - bgp, vpn, afi, safi, dest, &attr, &p->prefix.macip_addr.mac, 1, + bgp, vpn, afi, safi, dest, &attr, + (mac_only ? NULL : &p->prefix.macip_addr.mac), NULL /* ip */, 1, &pi, flags, seq, true /* setup_sync */, &old_is_sync); assert(pi); attr_new = pi->attr; @@ -1993,10 +2111,10 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi, p, &vpn->prd, NULL); - update_evpn_route_entry(bgp, vpn, afi, safi, dest, attr_new, - NULL /* mac */, 1, &global_pi, flags, - seq, false /* setup_sync */, - NULL /* old_is_sync */); + update_evpn_route_entry( + bgp, vpn, afi, safi, dest, attr_new, NULL /* mac */, + NULL /* ip */, 1, &global_pi, flags, seq, + false /* setup_sync */, NULL /* old_is_sync */); /* Schedule for processing and unlock node. */ bgp_process(bgp, dest, afi, safi); @@ -2077,9 +2195,9 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, /* First, locate the route node within the VNI. If it doesn't exist, * there * is nothing further to do. + * NOTE: There is no RD here. */ - /* NOTE: There is no RD here. */ - dest = bgp_evpn_vni_node_lookup(vpn->route_table, p, NULL); + dest = bgp_evpn_vni_node_lookup(vpn, p, NULL); if (!dest) return 0; @@ -2138,8 +2256,17 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * VNI table MAC-IP prefixes don't have MAC so make sure it's set from * path info here. */ - evpn_type2_prefix_global_copy(&evp, (struct prefix_evpn *)&dest->p, - *evpn_type2_path_info_get_mac(local_pi)); + if (is_evpn_prefix_ipaddr_none((struct prefix_evpn *)&dest->p)) { + /* VNI MAC -> Global */ + evpn_type2_prefix_global_copy( + &evp, (struct prefix_evpn *)&dest->p, NULL /* mac */, + evpn_type2_path_info_get_ip(local_pi)); + } else { + /* VNI IP -> Global */ + evpn_type2_prefix_global_copy( + &evp, (struct prefix_evpn *)&dest->p, + evpn_type2_path_info_get_mac(local_pi), NULL /* ip */); + } /* * Build attribute per local route as the MAC mobility and @@ -2186,8 +2313,8 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, /* Update the route entry. */ route_change = update_evpn_route_entry( - bgp, vpn, afi, safi, dest, &attr, NULL /* mac */, 0, &pi, 0, - seq, true /* setup_sync */, &old_is_sync); + bgp, vpn, afi, safi, dest, &attr, NULL /* mac */, NULL /* ip */, + 0, &pi, 0, seq, true /* setup_sync */, &old_is_sync); assert(pi); attr_new = pi->attr; @@ -2235,11 +2362,11 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, global_dest = bgp_evpn_global_node_get( bgp->rib[afi][safi], afi, safi, &evp, &vpn->prd, NULL); assert(global_dest); - update_evpn_route_entry(bgp, vpn, afi, safi, global_dest, - attr_new, NULL /* mac */, 0, &global_pi, - 0, mac_mobility_seqnum(attr_new), - false /* setup_sync */, - NULL /* old_is_sync */); + update_evpn_route_entry( + bgp, vpn, afi, safi, global_dest, attr_new, + NULL /* mac */, NULL /* ip */, 0, &global_pi, 0, + mac_mobility_seqnum(attr_new), false /* setup_sync */, + NULL /* old_is_sync */); /* Schedule for processing and unlock node. */ bgp_process(bgp, global_dest, afi, safi); @@ -2250,43 +2377,51 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, aspath_unintern(&attr.aspath); } +static void update_type2_route(struct bgp *bgp, struct bgpevpn *vpn, + struct bgp_dest *dest) +{ + struct bgp_path_info *tmp_pi; + + const struct prefix_evpn *evp = + (const struct prefix_evpn *)bgp_dest_get_prefix(dest); + + if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + return; + + /* Identify local route. */ + for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi; + tmp_pi = tmp_pi->next) { + if (tmp_pi->peer == bgp->peer_self && + tmp_pi->type == ZEBRA_ROUTE_BGP && + tmp_pi->sub_type == BGP_ROUTE_STATIC) + break; + } + + if (!tmp_pi) + return; + + bgp_evpn_update_type2_route_entry(bgp, vpn, dest, tmp_pi, __func__); +} + /* * Update all type-2 (MACIP) local routes for this VNI - these should also * be scheduled for advertise to peers. */ -static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) +static void update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) { struct bgp_dest *dest; - struct bgp_path_info *tmp_pi; - /* Walk this VNI's route table and update local type-2 routes. For any - * routes updated, update corresponding entry in the global table too. + /* Walk this VNI's route MAC & IP table and update local type-2 + * routes. For any routes updated, update corresponding entry in the + * global table too. */ - for (dest = bgp_table_top(vpn->route_table); dest; - dest = bgp_route_next(dest)) { - const struct prefix_evpn *evp = - (const struct prefix_evpn *)bgp_dest_get_prefix(dest); - - if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) - continue; - - /* Identify local route. */ - for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi; - tmp_pi = tmp_pi->next) { - if (tmp_pi->peer == bgp->peer_self - && tmp_pi->type == ZEBRA_ROUTE_BGP - && tmp_pi->sub_type == BGP_ROUTE_STATIC) - break; - } - - if (!tmp_pi) - continue; - - bgp_evpn_update_type2_route_entry(bgp, vpn, dest, tmp_pi, - __func__); - } + for (dest = bgp_table_top(vpn->mac_table); dest; + dest = bgp_route_next(dest)) + update_type2_route(bgp, vpn, dest); - return 0; + for (dest = bgp_table_top(vpn->ip_table); dest; + dest = bgp_route_next(dest)) + update_type2_route(bgp, vpn, dest); } /* @@ -2327,55 +2462,65 @@ static void delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) } } +static void delete_vni_type2_route(struct bgp *bgp, struct bgp_dest *dest) +{ + struct bgp_path_info *pi; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + + const struct prefix_evpn *evp = + (const struct prefix_evpn *)bgp_dest_get_prefix(dest); + + if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + return; + + delete_evpn_route_entry(bgp, afi, safi, dest, &pi); + + /* Route entry in local table gets deleted immediately. */ + if (pi) + bgp_path_info_reap(dest, pi); +} + +static void delete_vni_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) +{ + struct bgp_dest *dest; + + /* Next, walk this VNI's MAC & IP route table and delete local type-2 + * routes. + */ + for (dest = bgp_table_top(vpn->mac_table); dest; + dest = bgp_route_next(dest)) + delete_vni_type2_route(bgp, dest); + + for (dest = bgp_table_top(vpn->ip_table); dest; + dest = bgp_route_next(dest)) + delete_vni_type2_route(bgp, dest); +} + /* * Delete all type-2 (MACIP) local routes for this VNI - from the global * table as well as the per-VNI route table. */ -static int delete_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) +static void delete_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) { - afi_t afi; - safi_t safi; - struct bgp_dest *dest; - struct bgp_path_info *pi; - - afi = AFI_L2VPN; - safi = SAFI_EVPN; - /* First, walk the global route table for this VNI's type-2 local * routes. * EVPN routes are a 2-level table, first get the RD table. */ delete_global_type2_routes(bgp, vpn); - - /* Next, walk this VNI's route table and delete local type-2 routes. */ - for (dest = bgp_table_top(vpn->route_table); dest; - dest = bgp_route_next(dest)) { - const struct prefix_evpn *evp = - (const struct prefix_evpn *)bgp_dest_get_prefix(dest); - - if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) - continue; - - delete_evpn_route_entry(bgp, afi, safi, dest, &pi); - - /* Route entry in local table gets deleted immediately. */ - if (pi) - bgp_path_info_reap(dest, pi); - } - - return 0; + delete_vni_type2_routes(bgp, vpn); } /* * Delete all routes in the per-VNI route table. */ -static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) +static void delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) { struct bgp_dest *dest; struct bgp_path_info *pi, *nextpi; - /* Walk this VNI's route table and delete all routes. */ - for (dest = bgp_table_top(vpn->route_table); dest; + /* Walk this VNI's MAC & IP route table and delete all routes. */ + for (dest = bgp_table_top(vpn->mac_table); dest; dest = bgp_route_next(dest)) { for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) { @@ -2385,7 +2530,14 @@ static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) } } - return 0; + for (dest = bgp_table_top(vpn->ip_table); dest; + dest = bgp_route_next(dest)) { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) { + bgp_path_info_delete(dest, pi); + bgp_path_info_reap(dest, pi); + } + } } /* BUM traffic flood mode per-l2-vni */ @@ -2432,7 +2584,8 @@ int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) return ret; } - return update_all_type2_routes(bgp, vpn); + update_all_type2_routes(bgp, vpn); + return 0; } /* @@ -2449,9 +2602,7 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) /* Delete and withdraw locally learnt type-2 routes (MACIP) * followed by type-3 routes (only one) - for this VNI. */ - ret = delete_all_type2_routes(bgp, vpn); - if (ret) - return ret; + delete_all_type2_routes(bgp, vpn); build_evpn_type3_prefix(&p, vpn->originator_ip); ret = delete_evpn_route(bgp, vpn, &p); @@ -2459,7 +2610,8 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) return ret; /* Delete all routes from the per-VNI table. */ - return delete_all_vni_routes(bgp, vpn); + delete_all_vni_routes(bgp, vpn); + return 0; } /* @@ -2719,13 +2871,12 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, } /* - * Install route entry into the VNI routing table and invoke route selection. + * Common handling for vni route tables install/selection. */ -static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - struct bgp_path_info *parent_pi) +static int install_evpn_route_entry_in_vni_common( + struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p, + struct bgp_dest *dest, struct bgp_path_info *parent_pi) { - struct bgp_dest *dest; struct bgp_path_info *pi; struct bgp_path_info *local_pi; struct attr *attr_new; @@ -2733,10 +2884,6 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, bool old_local_es = false; bool new_local_es; - /* Create (or fetch) route within the VNI. */ - /* NOTE: There is no RD here. */ - dest = bgp_evpn_vni_node_get(vpn->route_table, p, parent_pi); - /* Check if route entry is already present. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (pi->extra @@ -2748,9 +2895,14 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, pi = bgp_create_evpn_bgp_path_info(parent_pi, dest, parent_pi->attr); - if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - evpn_type2_path_info_set_mac(pi, - p->prefix.macip_addr.mac); + if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + if (is_evpn_type2_dest_ipaddr_none(dest)) + evpn_type2_path_info_set_ip( + pi, p->prefix.macip_addr.ip); + else + evpn_type2_path_info_set_mac( + pi, p->prefix.macip_addr.mac); + } new_local_es = bgp_evpn_attr_is_local_es(pi->attr); } else { @@ -2809,11 +2961,159 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, if (local_pi && (old_local_es || new_local_es)) bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi, __func__); + + return ret; +} + +/* + * Common handling for vni route tables uninstall/selection. + */ +static int uninstall_evpn_route_entry_in_vni_common( + struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p, + struct bgp_dest *dest, struct bgp_path_info *parent_pi) +{ + struct bgp_path_info *pi; + struct bgp_path_info *local_pi; + int ret; + + /* Find matching route entry. */ + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) + if (pi->extra && + (struct bgp_path_info *)pi->extra->parent == parent_pi) + break; + + if (!pi) + return 0; + + bgp_evpn_remote_ip_hash_del(vpn, pi); + + /* Mark entry for deletion */ + bgp_path_info_delete(dest, pi); + + /* Perform route selection and update zebra, if required. */ + ret = evpn_route_select_install(bgp, vpn, dest); + + /* if the best path is a local path with a non-zero ES + * sync info against the local path may need to be updated + * when a remote path is deleted + */ + local_pi = bgp_evpn_route_get_local_path(bgp, dest); + if (local_pi && bgp_evpn_attr_is_local_es(local_pi->attr)) + bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi, + __func__); + + return ret; +} + +/* + * Install route entry into VNI IP table and invoke route selection. + */ +static int install_evpn_route_entry_in_vni_ip(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *parent_pi) +{ + int ret; + struct bgp_dest *dest; + + /* Ignore MAC Only Type-2 */ + if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) && + (is_evpn_prefix_ipaddr_none(p) == true)) + return 0; + + /* Create (or fetch) route within the VNI IP table. */ + dest = bgp_evpn_vni_ip_node_get(vpn->ip_table, p, parent_pi); + + ret = install_evpn_route_entry_in_vni_common(bgp, vpn, p, dest, + parent_pi); + + bgp_dest_unlock_node(dest); + + return ret; +} + +/* + * Install route entry into VNI MAC table and invoke route selection. + */ +static int install_evpn_route_entry_in_vni_mac(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *parent_pi) +{ + int ret; + struct bgp_dest *dest; + + /* Only type-2 routes go into this table */ + if (p->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + return 0; + + /* Create (or fetch) route within the VNI MAC table. */ + dest = bgp_evpn_vni_mac_node_get(vpn->mac_table, p, parent_pi); + + ret = install_evpn_route_entry_in_vni_common(bgp, vpn, p, dest, + parent_pi); + + bgp_dest_unlock_node(dest); + + return ret; +} + +/* + * Uninstall route entry from VNI IP table and invoke route selection. + */ +static int uninstall_evpn_route_entry_in_vni_ip(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *parent_pi) +{ + int ret; + struct bgp_dest *dest; + + /* Ignore MAC Only Type-2 */ + if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) && + (is_evpn_prefix_ipaddr_none(p) == true)) + return 0; + + /* Locate route within the VNI IP table. */ + dest = bgp_evpn_vni_ip_node_lookup(vpn->ip_table, p, parent_pi); + if (!dest) + return 0; + + ret = uninstall_evpn_route_entry_in_vni_common(bgp, vpn, p, dest, + parent_pi); + bgp_dest_unlock_node(dest); return ret; } +/* + * Uninstall route entry from VNI IP table and invoke route selection. + */ +static int +uninstall_evpn_route_entry_in_vni_mac(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *parent_pi) +{ + int ret; + struct bgp_dest *dest; + + /* Only type-2 routes go into this table */ + if (p->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + return 0; + + /* Locate route within the VNI MAC table. */ + dest = bgp_evpn_vni_mac_node_lookup(vpn->mac_table, p, parent_pi); + if (!dest) + return 0; + + ret = uninstall_evpn_route_entry_in_vni_common(bgp, vpn, p, dest, + parent_pi); + + bgp_dest_unlock_node(dest); + + return ret; +} /* * Uninstall route entry from the VRF routing table and send message * to zebra, if appropriate. @@ -2892,54 +3192,79 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, } /* - * Uninstall route entry from the VNI routing table and send message - * to zebra, if appropriate. + * Install route entry into the VNI routing tables. + */ +static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *parent_pi) +{ + int ret = 0; + + if (bgp_debug_update(parent_pi->peer, NULL, NULL, 1)) + zlog_debug( + "%s (%u): Installing EVPN %pFX route in VNI %u IP/MAC table", + vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni); + + ret = install_evpn_route_entry_in_vni_mac(bgp, vpn, p, parent_pi); + + if (ret) { + flog_err( + EC_BGP_EVPN_FAIL, + "%s (%u): Failed to install EVPN %pFX route in VNI %u MAC table", + vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni); + + return ret; + } + + ret = install_evpn_route_entry_in_vni_ip(bgp, vpn, p, parent_pi); + + if (ret) { + flog_err( + EC_BGP_EVPN_FAIL, + "%s (%u): Failed to install EVPN %pFX route in VNI %u IP table", + vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni); + + return ret; + } + + return ret; +} + +/* + * Uninstall route entry from the VNI routing tables. */ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p, struct bgp_path_info *parent_pi) { - struct bgp_dest *dest; - struct bgp_path_info *pi; - struct bgp_path_info *local_pi; - int ret; - - /* Locate route within the VNI. */ - /* NOTE: There is no RD here. */ - dest = bgp_evpn_vni_node_lookup(vpn->route_table, p, parent_pi); - if (!dest) - return 0; + int ret = 0; - /* Find matching route entry. */ - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) - if (pi->extra - && (struct bgp_path_info *)pi->extra->parent == parent_pi) - break; + if (bgp_debug_update(parent_pi->peer, NULL, NULL, 1)) + zlog_debug( + "%s (%u): Uninstalling EVPN %pFX route from VNI %u IP/MAC table", + vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni); - if (!pi) { - bgp_dest_unlock_node(dest); - return 0; - } + ret = uninstall_evpn_route_entry_in_vni_ip(bgp, vpn, p, parent_pi); - bgp_evpn_remote_ip_hash_del(vpn, pi); + if (ret) { + flog_err( + EC_BGP_EVPN_FAIL, + "%s (%u): Failed to uninstall EVPN %pFX route from VNI %u IP table", + vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni); - /* Mark entry for deletion */ - bgp_path_info_delete(dest, pi); + return ret; + } - /* Perform route selection and update zebra, if required. */ - ret = evpn_route_select_install(bgp, vpn, dest); + ret = uninstall_evpn_route_entry_in_vni_mac(bgp, vpn, p, parent_pi); - /* if the best path is a local path with a non-zero ES - * sync info against the local path may need to be updated - * when a remote path is deleted - */ - local_pi = bgp_evpn_route_get_local_path(bgp, dest); - if (local_pi && bgp_evpn_attr_is_local_es(local_pi->attr)) - bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi, - __func__); + if (ret) { + flog_err( + EC_BGP_EVPN_FAIL, + "%s (%u): Failed to uninstall EVPN %pFX route from VNI %u MAC table", + vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni); - /* Unlock route node. */ - bgp_dest_unlock_node(dest); + return ret; + } return ret; } @@ -3515,7 +3840,8 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi, * we need to create a different copy for the VNI */ if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) - evp = evpn_type1_prefix_vni_copy(&ad_evp, evp, attr->nexthop); + evp = evpn_type1_prefix_vni_ip_copy(&ad_evp, evp, + attr->nexthop); ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) @@ -3730,16 +4056,94 @@ static void withdraw_router_id_vrf(struct bgp *bgp_vrf) delete_withdraw_vrf_routes(bgp_vrf); } +static void update_advertise_vni_route(struct bgp *bgp, struct bgpevpn *vpn, + struct bgp_dest *dest) +{ + struct bgp_dest *global_dest; + struct bgp_path_info *pi, *global_pi; + struct attr *attr; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + + struct prefix_evpn tmp_evp; + const struct prefix_evpn *evp = + (const struct prefix_evpn *)bgp_dest_get_prefix(dest); + + /* + * We have already processed type-3 routes. + * Process only type-1 and type-2 routes here. + */ + if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE && + evp->prefix.route_type != BGP_EVPN_AD_ROUTE) + return; + + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) + if (pi->peer == bgp->peer_self && pi->type == ZEBRA_ROUTE_BGP && + pi->sub_type == BGP_ROUTE_STATIC) + break; + if (!pi) + return; + + /* + * VNI table MAC-IP prefixes don't have MAC so make sure it's + * set from path info here. + */ + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + if (is_evpn_prefix_ipaddr_none(evp)) { + /* VNI MAC -> Global */ + evpn_type2_prefix_global_copy( + &tmp_evp, evp, NULL /* mac */, + evpn_type2_path_info_get_ip(pi)); + } else { + /* VNI IP -> Global */ + evpn_type2_prefix_global_copy( + &tmp_evp, evp, evpn_type2_path_info_get_mac(pi), + NULL /* ip */); + } + } else { + memcpy(&tmp_evp, evp, sizeof(tmp_evp)); + } + + /* Create route in global routing table using this route entry's + * attribute. + */ + attr = pi->attr; + global_dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi, + &tmp_evp, &vpn->prd, NULL); + assert(global_dest); + + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + /* Type-2 route */ + update_evpn_route_entry( + bgp, vpn, afi, safi, global_dest, attr, NULL /* mac */, + NULL /* ip */, 1, &global_pi, 0, + mac_mobility_seqnum(attr), false /* setup_sync */, + NULL /* old_is_sync */); + } else { + /* Type-1 route */ + struct bgp_evpn_es *es; + int route_changed = 0; + + es = bgp_evpn_es_find(&evp->prefix.ead_addr.esi); + bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, global_dest, + attr, &global_pi, &route_changed); + } + + /* Schedule for processing and unlock node. */ + bgp_process(bgp, global_dest, afi, safi); + bgp_dest_unlock_node(global_dest); +} + /* * Update and advertise local routes for a VNI. Invoked upon router-id * change. Note that the processing is done only on the global route table * using routes that already exist in the per-VNI table. */ -static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) +static void update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) { struct prefix_evpn p; struct bgp_dest *dest, *global_dest; - struct bgp_path_info *pi, *global_pi; + struct bgp_path_info *pi; struct attr *attr; afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; @@ -3753,9 +4157,9 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) if (bgp_evpn_vni_flood_mode_get(bgp, vpn) == VXLAN_FLOOD_HEAD_END_REPL) { build_evpn_type3_prefix(&p, vpn->originator_ip); - dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL); + dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL); if (!dest) /* unexpected */ - return 0; + return; for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (pi->peer == bgp->peer_self && pi->type == ZEBRA_ROUTE_BGP @@ -3763,15 +4167,16 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) break; if (!pi) { bgp_dest_unlock_node(dest); - return 0; + return; } + attr = pi->attr; global_dest = bgp_evpn_global_node_get( bgp->rib[afi][safi], afi, safi, &p, &vpn->prd, NULL); update_evpn_route_entry( bgp, vpn, afi, safi, global_dest, attr, NULL /* mac */, - 1, &pi, 0, mac_mobility_seqnum(attr), + NULL /* ip */, 1, &pi, 0, mac_mobility_seqnum(attr), false /* setup_sync */, NULL /* old_is_sync */); /* Schedule for processing and unlock node. */ @@ -3779,71 +4184,16 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) bgp_dest_unlock_node(global_dest); } - /* Now, walk this VNI's route table and use the route and its attribute - * to create and schedule route in global table. + /* Now, walk this VNI's MAC & IP route table and use the route and its + * attribute to create and schedule route in global table. */ - for (dest = bgp_table_top(vpn->route_table); dest; - dest = bgp_route_next(dest)) { - struct prefix_evpn tmp_evp; - const struct prefix_evpn *evp = - (const struct prefix_evpn *)bgp_dest_get_prefix(dest); - - /* - * We have already processed type-3 routes. - * Process only type-1 and type-2 routes here. - */ - if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE - && evp->prefix.route_type != BGP_EVPN_AD_ROUTE) - continue; - - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) - if (pi->peer == bgp->peer_self - && pi->type == ZEBRA_ROUTE_BGP - && pi->sub_type == BGP_ROUTE_STATIC) - break; - if (!pi) - continue; - - /* - * VNI table MAC-IP prefixes don't have MAC so make sure it's - * set from path info here. - */ - evpn_type2_prefix_global_copy( - &tmp_evp, evp, *evpn_type2_path_info_get_mac(pi)); - - /* Create route in global routing table using this route entry's - * attribute. - */ - attr = pi->attr; - global_dest = - bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi, - &tmp_evp, &vpn->prd, NULL); - assert(global_dest); - - if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { - /* Type-2 route */ - update_evpn_route_entry( - bgp, vpn, afi, safi, global_dest, attr, - NULL /* mac */, 1, &global_pi, 0, - mac_mobility_seqnum(attr), - false /* setup_sync */, NULL /* old_is_sync */); - } else { - /* Type-1 route */ - struct bgp_evpn_es *es; - int route_changed = 0; - - es = bgp_evpn_es_find(&evp->prefix.ead_addr.esi); - bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, - global_dest, attr, &global_pi, - &route_changed); - } - - /* Schedule for processing and unlock node. */ - bgp_process(bgp, global_dest, afi, safi); - bgp_dest_unlock_node(global_dest); - } + for (dest = bgp_table_top(vpn->mac_table); dest; + dest = bgp_route_next(dest)) + update_advertise_vni_route(bgp, vpn, dest); - return 0; + for (dest = bgp_table_top(vpn->ip_table); dest; + dest = bgp_route_next(dest)) + update_advertise_vni_route(bgp, vpn, dest); } /* @@ -5468,8 +5818,9 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni, bf_assign_index(bm->rd_idspace, vpn->rd_id); derive_rd_rt_for_vni(bgp, vpn); - /* Initialize EVPN route table. */ - vpn->route_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN); + /* Initialize EVPN route tables. */ + vpn->ip_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN); + vpn->mac_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN); /* Add to hash */ (void)hash_get(bgp->vnihash, vpn, hash_alloc_intern); @@ -5497,7 +5848,8 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn) bgp_evpn_remote_ip_hash_destroy(vpn); bgp_evpn_vni_es_cleanup(vpn); bgpevpn_unlink_from_l3vni(vpn); - bgp_table_unlock(vpn->route_table); + bgp_table_unlock(vpn->ip_table); + bgp_table_unlock(vpn->mac_table); bgp_evpn_unmap_vni_from_its_rts(bgp, vpn); list_delete(&vpn->import_rtl); list_delete(&vpn->export_rtl); @@ -5623,7 +5975,7 @@ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac, delete_evpn_route(bgp, vpn, &p); } else { /* Re-instate the current remote best path if any */ - dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL); + dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL); if (dest) { evpn_zebra_reinstall_best_route(bgp, vpn, dest); bgp_dest_unlock_node(dest); @@ -6629,7 +6981,7 @@ void bgp_evpn_handle_resolve_overlay_index_set(struct hash_bucket *bucket, bgp_evpn_remote_ip_hash_init(vpn); - for (dest = bgp_table_top(vpn->route_table); dest; + for (dest = bgp_table_top(vpn->ip_table); dest; dest = bgp_route_next(dest)) for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) bgp_evpn_remote_ip_hash_add(vpn, pi); diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index a0ab0881e7..2a5c5d7ec4 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -471,7 +471,7 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es, struct prefix_rd *prd; if (vpn) { - rt_table = vpn->route_table; + rt_table = vpn->ip_table; prd = &vpn->prd; } else { rt_table = es->route_table; @@ -960,7 +960,7 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es, bgp_evpn_type1_evi_route_extcomm_build(es, vpn, &attr); /* First, create (or fetch) route node within the VNI. */ - dest = bgp_node_get(vpn->route_table, (struct prefix *)p); + dest = bgp_node_get(vpn->ip_table, (struct prefix *)p); /* Create or update route entry. */ ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest, diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 9b4405afe7..eb78a755db 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -112,9 +112,10 @@ struct bgpevpn { */ struct hash *remote_ip_hash; - /* Route table for EVPN routes for + /* Route tables for EVPN routes for * this VNI. */ - struct bgp_table *route_table; + struct bgp_table *ip_table; + struct bgp_table *mac_table; /* RB tree of ES-EVIs */ struct bgp_es_evi_rb_head es_evi_rb_tree; @@ -531,10 +532,10 @@ static inline void evpn_type1_prefix_global_copy(struct prefix_evpn *global_p, /* EAD prefix in the global table doesn't include the VTEP-IP so * we need to create a different copy for the VNI */ -static inline struct prefix_evpn *evpn_type1_prefix_vni_copy( - struct prefix_evpn *vni_p, - const struct prefix_evpn *global_p, - struct in_addr originator_ip) +static inline struct prefix_evpn * +evpn_type1_prefix_vni_ip_copy(struct prefix_evpn *vni_p, + const struct prefix_evpn *global_p, + struct in_addr originator_ip) { memcpy(vni_p, global_p, sizeof(*vni_p)); vni_p->prefix.ead_addr.ip.ipa_type = IPADDR_V4; @@ -543,29 +544,49 @@ static inline struct prefix_evpn *evpn_type1_prefix_vni_copy( return vni_p; } -static inline void -evpn_type2_prefix_global_copy(struct prefix_evpn *global_p, - const struct prefix_evpn *vni_p, - const struct ethaddr mac) +static inline void evpn_type2_prefix_global_copy( + struct prefix_evpn *global_p, const struct prefix_evpn *vni_p, + const struct ethaddr *mac, const struct ipaddr *ip) { memcpy(global_p, vni_p, sizeof(*global_p)); - global_p->prefix.macip_addr.mac = mac; + + if (mac) + global_p->prefix.macip_addr.mac = *mac; + + if (ip) + global_p->prefix.macip_addr.ip = *ip; } static inline void -evpn_type2_prefix_vni_copy(struct prefix_evpn *vni_p, - const struct prefix_evpn *global_p) +evpn_type2_prefix_vni_ip_copy(struct prefix_evpn *vni_p, + const struct prefix_evpn *global_p) { memcpy(vni_p, global_p, sizeof(*vni_p)); memset(&vni_p->prefix.macip_addr.mac, 0, sizeof(struct ethaddr)); } +static inline void +evpn_type2_prefix_vni_mac_copy(struct prefix_evpn *vni_p, + const struct prefix_evpn *global_p) +{ + memcpy(vni_p, global_p, sizeof(*vni_p)); + memset(&vni_p->prefix.macip_addr.ip, 0, sizeof(struct ipaddr)); +} + /* Get MAC of path_info prefix */ static inline struct ethaddr * evpn_type2_path_info_get_mac(const struct bgp_path_info *local_pi) { assert(local_pi->extra); - return &local_pi->extra->mac; + return &local_pi->extra->vni_info.mac; +} + +/* Get IP of path_info prefix */ +static inline struct ipaddr * +evpn_type2_path_info_get_ip(const struct bgp_path_info *local_pi) +{ + assert(local_pi->extra); + return &local_pi->extra->vni_info.ip; } /* Set MAC of path_info prefix */ @@ -573,7 +594,25 @@ static inline void evpn_type2_path_info_set_mac(struct bgp_path_info *local_pi, const struct ethaddr mac) { assert(local_pi->extra); - local_pi->extra->mac = mac; + local_pi->extra->vni_info.mac = mac; +} + +/* Set IP of path_info prefix */ +static inline void evpn_type2_path_info_set_ip(struct bgp_path_info *local_pi, + const struct ipaddr ip) +{ + assert(local_pi->extra); + local_pi->extra->vni_info.ip = ip; +} + +/* Is the IP empty for the RT's dest? */ +static inline bool is_evpn_type2_dest_ipaddr_none(const struct bgp_dest *dest) +{ + const struct prefix_evpn *evp = + (const struct prefix_evpn *)bgp_dest_get_prefix(dest); + + assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE); + return is_evpn_prefix_ipaddr_none(evp); } static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi, @@ -676,13 +715,28 @@ bgp_evpn_global_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi, struct prefix_rd *prd, const struct bgp_path_info *local_pi); extern struct bgp_dest * -bgp_evpn_vni_node_get(struct bgp_table *const table, - const struct prefix_evpn *evp, +bgp_evpn_vni_ip_node_get(struct bgp_table *const table, + const struct prefix_evpn *evp, + const struct bgp_path_info *parent_pi); +extern struct bgp_dest * +bgp_evpn_vni_ip_node_lookup(const struct bgp_table *const table, + const struct prefix_evpn *evp, + const struct bgp_path_info *parent_pi); +extern struct bgp_dest * +bgp_evpn_vni_mac_node_get(struct bgp_table *const table, + const struct prefix_evpn *evp, + const struct bgp_path_info *parent_pi); +extern struct bgp_dest * +bgp_evpn_vni_mac_node_lookup(const struct bgp_table *const table, + const struct prefix_evpn *evp, + const struct bgp_path_info *parent_pi); +extern struct bgp_dest * +bgp_evpn_vni_node_get(struct bgpevpn *vpn, const struct prefix_evpn *p, const struct bgp_path_info *parent_pi); extern struct bgp_dest * -bgp_evpn_vni_node_lookup(const struct bgp_table *const table, - const struct prefix_evpn *evp, +bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn, const struct prefix_evpn *p, const struct bgp_path_info *parent_pi); + extern void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import); extern void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index fc2271ed72..f8110117ec 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -57,6 +57,8 @@ struct vni_walk_ctx { struct in_addr vtep_ip; json_object *json; int detail; + int type; + bool mac_table; }; int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc, int *oly_idx, @@ -771,9 +773,10 @@ static void bgp_evpn_show_routes_mac_ip_global_es(struct vty *vty, esi_t *esi, bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, true); } -static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, - struct vty *vty, struct in_addr vtep_ip, - json_object *json, int detail) +static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, + struct vty *vty, int type, bool mac_table, + struct in_addr vtep_ip, json_object *json, + int detail) { struct bgp_dest *dest; struct bgp_path_info *pi; @@ -784,7 +787,11 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, prefix_cnt = path_cnt = 0; - table = vpn->route_table; + if (mac_table) + table = vpn->mac_table; + else + table = vpn->ip_table; + tbl_ver = table->version; for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { const struct prefix_evpn *evp = @@ -829,14 +836,26 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { /* - * VNI table MAC-IP prefixes don't have MAC so - * make sure it's set from path info - * here. + * VNI IP/MAC table prefixes don't have MAC/IP + * respectively so make sure it's set from path + * info here. */ - evpn_type2_prefix_global_copy( - (struct prefix_evpn *)&tmp_p, - (struct prefix_evpn *)p, - *evpn_type2_path_info_get_mac(pi)); + if (is_evpn_prefix_ipaddr_none(evp)) { + /* VNI MAC -> Global */ + evpn_type2_prefix_global_copy( + (struct prefix_evpn *)&tmp_p, + evp, NULL /* mac */, + evpn_type2_path_info_get_ip( + pi)); + } else { + /* VNI IP -> Global */ + evpn_type2_prefix_global_copy( + (struct prefix_evpn *)&tmp_p, + evp, + evpn_type2_path_info_get_mac( + pi), + NULL /* ip */); + } } else memcpy(&tmp_p, p, sizeof(tmp_p)); @@ -849,6 +868,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, AFI_L2VPN, SAFI_EVPN, RPKI_NOT_BEING_USED, json_path); + else route_vty_out(vty, &tmp_p, pi, 0, SAFI_EVPN, json_path, false); @@ -862,19 +882,6 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, if (json) { if (add_prefix_to_json) { - struct prefix tmp_p; - - if (evp->prefix.route_type == - BGP_EVPN_MAC_IP_ROUTE) { - pi = bgp_dest_get_bgp_path_info(dest); - evpn_type2_prefix_global_copy( - (struct prefix_evpn *)&tmp_p, - (struct prefix_evpn *)p, - *evpn_type2_path_info_get_mac( - pi)); - } else - memcpy(&tmp_p, p, sizeof(tmp_p)); - json_object_string_addf(json_prefix, "prefix", "%pFX", p); json_object_int_add(json_prefix, "prefixLen", @@ -924,11 +931,47 @@ static void show_vni_routes_hash(struct hash_bucket *bucket, void *arg) vty_out(vty, "\nVNI: %d\n\n", vpn->vni); } - show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip, json_vni, - wctx->detail); + show_vni_routes(wctx->bgp, vpn, wctx->vty, wctx->type, wctx->mac_table, + wctx->vtep_ip, json_vni, wctx->detail); + + if (json) + json_object_object_add(json, vni_str, json_vni); +} + +static void show_vni_routes_all_hash(struct hash_bucket *bucket, void *arg) +{ + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; + struct vni_walk_ctx *wctx = arg; + struct vty *vty = wctx->vty; + json_object *json = wctx->json; + json_object *json_vni = NULL; + json_object *json_vni_mac = NULL; + char vni_str[VNI_STR_LEN]; + + snprintf(vni_str, sizeof(vni_str), "%d", vpn->vni); + if (json) { + json_vni = json_object_new_object(); + json_object_int_add(json_vni, "vni", vpn->vni); + } else { + vty_out(vty, "\nVNI: %d\n\n", vpn->vni); + } + + show_vni_routes(wctx->bgp, vpn, wctx->vty, 0, false, wctx->vtep_ip, + json_vni, wctx->detail); if (json) json_object_object_add(json, vni_str, json_vni); + + if (json) + json_vni_mac = json_object_new_object(); + else + vty_out(vty, "\nVNI: %d MAC Table\n\n", vpn->vni); + + show_vni_routes(wctx->bgp, vpn, wctx->vty, 0, true, wctx->vtep_ip, + json_vni_mac, wctx->detail); + + if (json) + json_object_object_add(json_vni, "macTable", json_vni_mac); } static void show_l3vni_entry(struct vty *vty, struct bgp *bgp, @@ -2351,9 +2394,9 @@ static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp, /* * Display EVPN routes for all VNIs - vty handler. */ -static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, - struct in_addr vtep_ip, json_object *json, - int detail) +static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, int type, + bool mac_table, struct in_addr vtep_ip, + json_object *json, int detail) { uint32_t num_vnis; struct vni_walk_ctx wctx; @@ -2364,6 +2407,8 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, memset(&wctx, 0, sizeof(wctx)); wctx.bgp = bgp; wctx.vty = vty; + wctx.type = type; + wctx.mac_table = mac_table; wctx.vtep_ip = vtep_ip; wctx.json = json; wctx.detail = detail; @@ -2372,6 +2417,32 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, &wctx); } +/* + * Display EVPN routes for all VNIs & all types - vty handler. + */ +static void evpn_show_routes_vni_all_type_all(struct vty *vty, struct bgp *bgp, + struct in_addr vtep_ip, + json_object *json, int detail) +{ + uint32_t num_vnis; + struct vni_walk_ctx wctx; + + num_vnis = hashcount(bgp->vnihash); + if (!num_vnis) + return; + + memset(&wctx, 0, sizeof(struct vni_walk_ctx)); + wctx.bgp = bgp; + wctx.vty = vty; + wctx.vtep_ip = vtep_ip; + wctx.json = json; + wctx.detail = detail; + hash_iterate(bgp->vnihash, + (void (*)(struct hash_bucket *, + void *))show_vni_routes_all_hash, + &wctx); +} + /* * Display EVPN routes for a VNI -- for specific type-3 route (vty handler). */ @@ -2400,7 +2471,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, /* See if route exists. */ build_evpn_type3_prefix(&p, orig_ip); - dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL); + dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL); if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) { if (!json) vty_out(vty, "%% Network not in table\n"); @@ -2465,6 +2536,8 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, afi_t afi; safi_t safi; json_object *json_paths = NULL; + struct ethaddr empty_mac = {}; + const struct prefix_evpn *evp; afi = AFI_L2VPN; safi = SAFI_EVPN; @@ -2477,9 +2550,10 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, return; } + build_evpn_type2_prefix(&p, mac ? mac : &empty_mac, ip); + /* See if route exists. Look for both non-sticky and sticky. */ - build_evpn_type2_prefix(&p, mac, ip); - dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL); + dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL); if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) { if (!json) vty_out(vty, "%% Network not in table\n"); @@ -2494,16 +2568,18 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, * MAC is per-path, we have to walk the path_info's and look for it * first here. */ - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { - if (memcmp(mac, evpn_type2_path_info_get_mac(pi), - sizeof(*mac)) == 0) - break; - } + if (ip && mac) { + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + if (memcmp(mac, evpn_type2_path_info_get_mac(pi), + sizeof(*mac)) == 0) + break; + } - if (!pi) { - if (!json) - vty_out(vty, "%% Network not in table\n"); - return; + if (!pi) { + if (!json) + vty_out(vty, "%% Network not in table\n"); + return; + } } if (json) @@ -2513,12 +2589,15 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, route_vty_out_detail_header(vty, bgp, dest, (struct prefix *)&p, NULL, afi, safi, json); + evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest); + /* Display each path for this prefix. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { json_object *json_path = NULL; /* skip non-matching MACs */ - if (memcmp(mac, evpn_type2_path_info_get_mac(pi), + if (ip && mac && + memcmp(mac, evpn_type2_path_info_get_mac(pi), sizeof(*mac)) != 0) continue; @@ -2530,10 +2609,19 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, * make sure it's set from path info * here. */ - evpn_type2_prefix_global_copy( - (struct prefix_evpn *)&tmp_p, - (struct prefix_evpn *)bgp_dest_get_prefix(dest), - *evpn_type2_path_info_get_mac(pi)); + if (is_evpn_prefix_ipaddr_none(evp)) { + /* VNI MAC -> Global */ + evpn_type2_prefix_global_copy( + (struct prefix_evpn *)&tmp_p, evp, + NULL /* mac */, + evpn_type2_path_info_get_ip(pi)); + } else { + /* VNI IP -> Global */ + evpn_type2_prefix_global_copy( + (struct prefix_evpn *)&tmp_p, evp, + evpn_type2_path_info_get_mac(pi), + NULL /* ip */); + } route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p, pi, afi, safi, RPKI_NOT_BEING_USED, @@ -2581,8 +2669,8 @@ static void evpn_show_routes_esi(struct vty *vty, struct bgp *bgp, * If the vtep_ip is non zero, only routes behind that vtep are shown */ static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni, - int type, struct in_addr vtep_ip, - json_object *json) + int type, bool mac_table, + struct in_addr vtep_ip, json_object *json) { struct bgpevpn *vpn; @@ -2595,7 +2683,7 @@ static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni, } /* Walk this VNI's route table and display appropriate routes. */ - show_vni_routes(bgp, vpn, type, vty, vtep_ip, json, 0); + show_vni_routes(bgp, vpn, vty, type, mac_table, vtep_ip, json, 0); } /* @@ -4633,28 +4721,32 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd, as_type, as, show_flags); } +static int bgp_evpn_cli_parse_type_cmp(int *type, const char *type_str) +{ + if ((strncmp(type_str, "ma", 2) == 0) || (strmatch(type_str, "2"))) + *type = BGP_EVPN_MAC_IP_ROUTE; + else if ((strncmp(type_str, "mu", 2) == 0) || (strmatch(type_str, "3"))) + *type = BGP_EVPN_IMET_ROUTE; + else if ((strncmp(type_str, "es", 2) == 0) || (strmatch(type_str, "4"))) + *type = BGP_EVPN_ES_ROUTE; + else if ((strncmp(type_str, "ea", 2) == 0) || (strmatch(type_str, "1"))) + *type = BGP_EVPN_AD_ROUTE; + else if ((strncmp(type_str, "p", 1) == 0) || (strmatch(type_str, "5"))) + *type = BGP_EVPN_IP_PREFIX_ROUTE; + else + return -1; + + return 0; +} + int bgp_evpn_cli_parse_type(int *type, struct cmd_token **argv, int argc) { int type_idx = 0; if (argv_find(argv, argc, "type", &type_idx)) { /* Specific type is requested */ - if ((strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0) - || (strmatch(argv[type_idx + 1]->arg, "2"))) - *type = BGP_EVPN_MAC_IP_ROUTE; - else if ((strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0) - || (strmatch(argv[type_idx + 1]->arg, "3"))) - *type = BGP_EVPN_IMET_ROUTE; - else if ((strncmp(argv[type_idx + 1]->arg, "es", 2) == 0) - || (strmatch(argv[type_idx + 1]->arg, "4"))) - *type = BGP_EVPN_ES_ROUTE; - else if ((strncmp(argv[type_idx + 1]->arg, "ea", 2) == 0) - || (strmatch(argv[type_idx + 1]->arg, "1"))) - *type = BGP_EVPN_AD_ROUTE; - else if ((strncmp(argv[type_idx + 1]->arg, "p", 1) == 0) - || (strmatch(argv[type_idx + 1]->arg, "5"))) - *type = BGP_EVPN_IP_PREFIX_ROUTE; - else + if (bgp_evpn_cli_parse_type_cmp(type, + argv[type_idx + 1]->arg) != 0) return -1; } @@ -4952,7 +5044,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd, } } - evpn_show_routes_vni(vty, bgp, vni, type, vtep_ip, json); + evpn_show_routes_vni(vty, bgp, vni, type, false, vtep_ip, json); if (uj) vty_json(vty, json); @@ -5134,10 +5226,497 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all, } } - evpn_show_routes_vni_all(vty, bgp, vtep_ip, json, da); + evpn_show_routes_vni_all(vty, bgp, 0, false, vtep_ip, json, da); - if (uj) + if (uj) { vty_json(vty, json); + json_object_free(json); + } + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN ALL routing tables - for all VNIs. + */ +DEFPY(show_bgp_vni_all, + show_bgp_vni_all_cmd, + "show bgp vni all [vtep A.B.C.D$addr] [detail$detail]", + SHOW_STR + BGP_STR + VNI_HELP_STR + VNI_ALL_HELP_STR + VTEP_HELP_STR + VTEP_IP_HELP_STR + DETAIL_HELP_STR) +{ + struct bgp *bgp; + json_object *json = NULL; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + /* check if we need json output */ + /* + if (uj) + json = json_object_new_object(); + */ + + evpn_show_routes_vni_all_type_all(vty, bgp, addr, json, !!detail); + + /* + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + */ + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN EAD routing table - for all VNIs. + */ +DEFPY(show_bgp_vni_all_ead, + show_bgp_vni_all_ead_cmd, + "show bgp vni all type <1|ead> [vtep A.B.C.D$addr] []", + SHOW_STR + BGP_STR + VNI_HELP_STR + VNI_ALL_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_1_HELP_STR + EVPN_TYPE_1_HELP_STR + VTEP_HELP_STR + VTEP_IP_HELP_STR + DETAIL_HELP_STR + JSON_STR) +{ + struct bgp *bgp; + json_object *json = NULL; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + /* check if we need json output */ + if (uj) + json = json_object_new_object(); + + evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_AD_ROUTE, false, addr, json, + !!detail); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN MAC routing table - for all VNIs. + */ +DEFPY(show_bgp_vni_all_macip_mac, + show_bgp_vni_all_macip_mac_cmd, + "show bgp vni all type <2|macip> mac [vtep A.B.C.D$addr] []", + SHOW_STR + BGP_STR + VNI_HELP_STR + VNI_ALL_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_2_HELP_STR + "MAC Table\n" + VTEP_HELP_STR + VTEP_IP_HELP_STR + DETAIL_HELP_STR + JSON_STR) +{ + struct bgp *bgp; + json_object *json = NULL; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + /* check if we need json output */ + if (uj) + json = json_object_new_object(); + + evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_MAC_IP_ROUTE, true, addr, + json, !!detail); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN IP routing table - for all VNIs. + */ +DEFPY(show_bgp_vni_all_macip_ip, + show_bgp_vni_all_macip_ip_cmd, + "show bgp vni all type <2|macip> ip [vtep A.B.C.D$addr] []", + SHOW_STR + BGP_STR + VNI_HELP_STR + VNI_ALL_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_2_HELP_STR + "IP Table\n" + VTEP_HELP_STR + VTEP_IP_HELP_STR + DETAIL_HELP_STR + JSON_STR) +{ + struct bgp *bgp; + json_object *json = NULL; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + /* check if we need json output */ + if (uj) + json = json_object_new_object(); + + evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_MAC_IP_ROUTE, false, addr, + json, !!detail); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN Multicast routing table - for all VNIs. + */ +DEFPY(show_bgp_vni_all_imet, + show_bgp_vni_all_imet_cmd, + "show bgp vni all type <3|multicast> [vtep A.B.C.D$addr] []", + SHOW_STR + BGP_STR + VNI_HELP_STR + VNI_ALL_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_3_HELP_STR + EVPN_TYPE_3_HELP_STR + VTEP_HELP_STR + VTEP_IP_HELP_STR + DETAIL_HELP_STR + JSON_STR) +{ + struct bgp *bgp; + json_object *json = NULL; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + /* check if we need json output */ + if (uj) + json = json_object_new_object(); + + evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_IMET_ROUTE, false, addr, + json, !!detail); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN ALL routing tables - for select VNI + */ +DEFPY(show_bgp_vni, + show_bgp_vni_cmd, + "show bgp vni "CMD_VNI_RANGE"$vni [vtep A.B.C.D$addr]", + SHOW_STR + BGP_STR + VNI_HELP_STR + VNI_NUM_HELP_STR + VTEP_HELP_STR + VTEP_IP_HELP_STR) +{ + struct bgp *bgp; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + evpn_show_routes_vni(vty, bgp, vni, 0, false, addr, NULL); + vty_out(vty, "\n\nMAC Table:\n\n"); + evpn_show_routes_vni(vty, bgp, vni, 0, true, addr, NULL); + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN EAD routing table - for select VNI + */ +DEFPY(show_bgp_vni_ead, + show_bgp_vni_ead_cmd, + "show bgp vni "CMD_VNI_RANGE"$vni type <1|ead> [vtep A.B.C.D$addr] [json$uj]", + SHOW_STR + BGP_STR + VNI_HELP_STR + VNI_NUM_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_1_HELP_STR + EVPN_TYPE_1_HELP_STR + VTEP_HELP_STR + VTEP_IP_HELP_STR + JSON_STR) +{ + struct bgp *bgp; + json_object *json = NULL; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + /* check if we need json output */ + if (uj) + json = json_object_new_object(); + + evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_AD_ROUTE, false, addr, + json); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN MAC-IP MAC routing table - for select VNI + */ +DEFPY(show_bgp_vni_macip_mac, + show_bgp_vni_macip_mac_cmd, + "show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> mac [vtep A.B.C.D$addr] [json$uj]", + SHOW_STR + BGP_STR + VNI_HELP_STR + VNI_NUM_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_2_HELP_STR + "MAC Table\n" + VTEP_HELP_STR + VTEP_IP_HELP_STR + JSON_STR) +{ + struct bgp *bgp; + json_object *json = NULL; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + /* check if we need json output */ + if (uj) + json = json_object_new_object(); + + evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_MAC_IP_ROUTE, true, addr, + json); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN MAC-IP IP routing table - for select VNI + */ +DEFPY(show_bgp_vni_macip_ip, + show_bgp_vni_macip_ip_cmd, + "show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> ip [vtep A.B.C.D$addr] [json$uj]", + SHOW_STR + BGP_STR + VNI_HELP_STR + VNI_NUM_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_2_HELP_STR + "IP Table\n" + VTEP_HELP_STR + VTEP_IP_HELP_STR + JSON_STR) +{ + struct bgp *bgp; + json_object *json = NULL; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + /* check if we need json output */ + if (uj) + json = json_object_new_object(); + + evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_MAC_IP_ROUTE, false, addr, + json); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN Multicast routing table - for select VNI + */ +DEFPY(show_bgp_vni_imet, + show_bgp_vni_imet_cmd, + "show bgp vni "CMD_VNI_RANGE"$vni type <3|multicast> [vtep A.B.C.D$addr] [json$uj]", + SHOW_STR + BGP_STR + VNI_HELP_STR + VNI_NUM_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_3_HELP_STR + EVPN_TYPE_3_HELP_STR + VTEP_HELP_STR + VTEP_IP_HELP_STR + JSON_STR) +{ + struct bgp *bgp; + json_object *json = NULL; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + /* check if we need json output */ + if (uj) + json = json_object_new_object(); + + evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_IMET_ROUTE, false, addr, + json); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN MACIP MAC routing table - for select VNI & MAC + */ +DEFPY(show_bgp_vni_macip_mac_addr, + show_bgp_vni_macip_mac_addr_cmd, + "show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> mac X:X:X:X:X:X [json$uj]", + SHOW_STR + BGP_STR + VNI_HELP_STR + VNI_NUM_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_2_HELP_STR + "MAC Table\n" + MAC_STR + JSON_STR) +{ + struct bgp *bgp; + json_object *json = NULL; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + /* check if we need json output */ + if (uj) + json = json_object_new_object(); + + evpn_show_route_vni_macip(vty, bgp, vni, &mac->eth_addr, NULL, json); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + +/* + * Display per-VNI EVPN MACIP IP routing table - for select VNI & IP + */ +DEFPY(show_bgp_vni_macip_ip_addr, show_bgp_vni_macip_ip_addr_cmd, + "show bgp vni " CMD_VNI_RANGE + "$vni type <2|macip> ip [json$uj]", + SHOW_STR BGP_STR VNI_HELP_STR VNI_NUM_HELP_STR EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR EVPN_TYPE_2_HELP_STR + "IP Table\n" IP_ADDR_STR IP6_ADDR_STR JSON_STR) +{ + struct bgp *bgp; + json_object *json = NULL; + struct ipaddr ip_addr = {.ipa_type = IPADDR_NONE}; + + bgp = bgp_get_evpn(); + if (!bgp) + return CMD_WARNING; + + /* check if we need json output */ + if (uj) + json = json_object_new_object(); + + if (sockunion_family(ip) == AF_INET) { + ip_addr.ipa_type = IPADDR_V4; + ip_addr.ipaddr_v4.s_addr = sockunion2ip(ip); + } else { + ip_addr.ipa_type = IPADDR_V6; + memcpy(&ip_addr.ipaddr_v6, &ip->sin6.sin6_addr, + sizeof(struct in6_addr)); + } + evpn_show_route_vni_macip(vty, bgp, vni, NULL, &ip_addr, json); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } @@ -6590,6 +7169,20 @@ void bgp_ethernetvpn_init(void) install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd); + /* "show bgp vni" commands. */ + install_element(VIEW_NODE, &show_bgp_vni_all_cmd); + install_element(VIEW_NODE, &show_bgp_vni_all_ead_cmd); + install_element(VIEW_NODE, &show_bgp_vni_all_macip_mac_cmd); + install_element(VIEW_NODE, &show_bgp_vni_all_macip_ip_cmd); + install_element(VIEW_NODE, &show_bgp_vni_all_imet_cmd); + install_element(VIEW_NODE, &show_bgp_vni_cmd); + install_element(VIEW_NODE, &show_bgp_vni_ead_cmd); + install_element(VIEW_NODE, &show_bgp_vni_macip_mac_cmd); + install_element(VIEW_NODE, &show_bgp_vni_macip_ip_cmd); + install_element(VIEW_NODE, &show_bgp_vni_imet_cmd); + install_element(VIEW_NODE, &show_bgp_vni_macip_mac_addr_cmd); + install_element(VIEW_NODE, &show_bgp_vni_macip_ip_addr_cmd); + /* "show bgp evpn" commands. */ install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd); install_element(VIEW_NODE, &show_bgp_evpn_summary_cmd); diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h index 137365ddbf..6b17a83b74 100644 --- a/bgpd/bgp_evpn_vty.h +++ b/bgpd/bgp_evpn_vty.h @@ -27,6 +27,12 @@ extern void bgp_ethernetvpn_init(void); #define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n" #define EVPN_HELP_STR "Ethernet Virtual Private Network\n" +#define VNI_HELP_STR "VXLAN Network Identifier\n" +#define VNI_NUM_HELP_STR "VNI number\n" +#define VNI_ALL_HELP_STR "All VNIs\n" +#define DETAIL_HELP_STR "Print Detailed Output\n" +#define VTEP_HELP_STR "Remote VTEP\n" +#define VTEP_IP_HELP_STR "Remote VTEP IP address\n" extern int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc, int *oly_idx, diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 48e1547166..1b04bfc713 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -218,7 +218,10 @@ struct bgp_path_info_extra { * For imported routes into a VNI (or VRF) */ void *parent; /* parent from global table */ - struct ethaddr mac; /* MAC set here for VNI table */ + union { + struct ethaddr mac; /* MAC set here for VNI IP table */ + struct ipaddr ip; /* IP set here for VNI MAC table */ + } vni_info; /* * Some tunnelish parameters follow. Maybe consolidate into an diff --git a/lib/command.h b/lib/command.h index 70e52708a7..b701d4d0e9 100644 --- a/lib/command.h +++ b/lib/command.h @@ -404,6 +404,8 @@ struct cmd_node { #define SHOW_STR "Show running system information\n" #define IP_STR "IP information\n" #define IPV6_STR "IPv6 information\n" +#define IP_ADDR_STR "IPv4 Address\n" +#define IP6_ADDR_STR "IPv6 Address\n" #define SRTE_STR "SR-TE information\n" #define SRTE_COLOR_STR "SR-TE Color information\n" #define NO_STR "Negate a command or set its defaults\n" diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index 168f0b2ce6..e37f56f0eb 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -1327,11 +1327,11 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn, uint8_t flags, uint32_t seq, const esi_t *esi) { - struct sync_mac_ip_ctx ctx; char ipbuf[INET6_ADDRSTRLEN]; bool sticky; bool remote_gw; struct zebra_neigh *n = NULL; + struct zebra_mac *mac = NULL; sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW); @@ -1352,22 +1352,30 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn, return; } - if (ipa_len) { + if (!ipa_len) { + /* MAC update */ + (void)zebra_evpn_proc_sync_mac_update(zevpn, macaddr, ipa_len, + ipaddr, flags, seq, esi); + } else { + /* MAC-IP update */ + mac = zebra_evpn_mac_lookup(zevpn, macaddr); + if (!mac) { + mac = zebra_evpn_proc_sync_mac_update(zevpn, macaddr, + 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)) return; - } - - memset(&ctx, 0, sizeof(ctx)); - ctx.mac = zebra_evpn_proc_sync_mac_update( - zevpn, macaddr, ipa_len, ipaddr, flags, seq, esi, &ctx); - if (ctx.ignore_macip || !ctx.mac || !ipa_len) - return; - zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr, flags, seq, - esi, &ctx); + zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr, + flags, seq, esi, mac); + } } /************************** remote mac-ip handling **************************/ @@ -1452,14 +1460,30 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, } zvrf = zebra_vrf_get_evpn(); - if (zebra_evpn_mac_remote_macip_add(zevpn, zvrf, macaddr, ipa_len, - ipaddr, &mac, vtep_ip, flags, seq, - esi) - != 0) + if (!zvrf) return; - zebra_evpn_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac, vtep_ip, - flags, seq); + if (!ipa_len) { + /* MAC update */ + zebra_evpn_mac_remote_macip_add(zevpn, zvrf, macaddr, vtep_ip, + flags, seq, esi); + } else { + /* MAC-IP update + * Add auto MAC if it doesn't exist. + */ + mac = zebra_evpn_mac_lookup(zevpn, macaddr); + if (!mac) { + mac = zebra_evpn_mac_add_auto(zevpn, macaddr); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Neigh %pIA: MAC %pEA not found, Auto MAC created", + ipaddr, macaddr); + } + + zebra_evpn_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac, + vtep_ip, flags, seq); + } } /* Process a remote MACIP delete from BGP. */ diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index 4300b55c3b..f0d256e28a 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -1179,6 +1179,25 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) return 0; } +/* + * Add Auto MAC entry. + */ +struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevpn, + const struct ethaddr *macaddr) +{ + struct zebra_mac *mac; + + mac = zebra_evpn_mac_add(zevpn, macaddr); + if (!mac) + return NULL; + + zebra_evpn_mac_clear_fwd_info(mac); + memset(&mac->flags, 0, sizeof(uint32_t)); + SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + + return mac; +} + static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx, struct zebra_mac *mac) { @@ -1592,11 +1611,8 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac) static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, struct zebra_mac *mac, - uint32_t seq, uint16_t ipa_len, - const struct ipaddr *ipaddr, - bool sync) + uint32_t seq, bool sync) { - char ipbuf[INET6_ADDRSTRLEN]; char mac_buf[MAC_BUF_SIZE]; uint32_t tmp_seq; const char *n_type; @@ -1630,14 +1646,9 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) { zlog_debug( - "%s-macip accept vni %u %s-mac %pEA%s%s lower seq %u f %s", + "%s-macip accept vni %u %s-mac %pEA lower seq %u f %s", sync ? "sync" : "rem", zevpn->vni, - n_type, &mac->macaddr, - ipa_len ? " IP " : "", - ipa_len ? ipaddr2str(ipaddr, ipbuf, - sizeof(ipbuf)) - : "", - tmp_seq, + n_type, &mac->macaddr, tmp_seq, zebra_evpn_zebra_mac_flag_dump( mac, mac_buf, sizeof(mac_buf))); } @@ -1647,14 +1658,9 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) { zlog_debug( - "%s-macip ignore vni %u %s-mac %pEA%s%s as existing has higher seq %u f %s", + "%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s", sync ? "sync" : "rem", zevpn->vni, n_type, - &mac->macaddr, - ipa_len ? " IP " : "", - ipa_len ? ipaddr2str(ipaddr, ipbuf, - sizeof(ipbuf)) - : "", - tmp_seq, + &mac->macaddr, tmp_seq, zebra_evpn_zebra_mac_flag_dump( mac, mac_buf, sizeof(mac_buf))); } @@ -1665,10 +1671,12 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, return true; } -struct zebra_mac *zebra_evpn_proc_sync_mac_update( - struct zebra_evpn *zevpn, const struct ethaddr *macaddr, - uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags, - uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx) +struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, + const struct ethaddr *macaddr, + uint16_t ipa_len, + const struct ipaddr *ipaddr, + uint8_t flags, uint32_t seq, + const esi_t *esi) { struct zebra_mac *mac; bool inform_bgp = false; @@ -1680,6 +1688,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update( bool old_local = false; bool old_bgp_ready; bool new_bgp_ready; + bool created = false; mac = zebra_evpn_mac_lookup(zevpn, macaddr); if (!mac) { @@ -1688,8 +1697,6 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update( */ inform_bgp = true; inform_dataplane = true; - ctx->mac_created = true; - ctx->mac_inactive = true; /* create the MAC and associate it with the dest ES */ mac = zebra_evpn_mac_add(zevpn, macaddr); @@ -1707,6 +1714,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update( SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE); old_bgp_ready = false; new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); + created = true; } else { uint32_t old_flags; uint32_t new_flags; @@ -1731,14 +1739,10 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update( : "", sticky ? " sticky" : "", remote_gw ? " remote_gw" : ""); - ctx->ignore_macip = true; return NULL; } - if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, ipa_len, - ipaddr, true)) { - ctx->ignore_macip = true; + if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, true)) return NULL; - } old_local = !!CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL); old_static = zebra_evpn_mac_is_static(mac); @@ -1747,12 +1751,11 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update( new_flags = 0; SET_FLAG(new_flags, ZEBRA_MAC_LOCAL); /* retain old local activity flag */ - if (old_flags & ZEBRA_MAC_LOCAL) { + if (old_flags & ZEBRA_MAC_LOCAL) new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE); - } else { + else new_flags |= ZEBRA_MAC_LOCAL_INACTIVE; - ctx->mac_inactive = true; - } + if (ipa_len) { /* if mac-ip route do NOT update the peer flags * i.e. retain only flags as is @@ -1805,7 +1808,6 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update( if (es_change) { inform_bgp = true; inform_dataplane = true; - ctx->mac_inactive = true; } /* if peer-flag is being set notify dataplane that the @@ -1836,8 +1838,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update( char mac_buf[MAC_BUF_SIZE]; zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s", - ctx->mac_created ? "created" : "updated", - zevpn->vni, macaddr, + created ? "created" : "updated", zevpn->vni, macaddr, mac->es ? mac->es->esi_str : "-", mac->loc_seq, zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), @@ -1856,22 +1857,15 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update( zebra_evpn_process_neigh_on_local_mac_change( zevpn, mac, seq_change, es_change); - if (inform_dataplane) { - if (ipa_len) - /* if the mac is being created as a part of MAC-IP - * route wait for the neigh to be updated or - * created before programming the mac - */ - ctx->mac_dp_update_deferred = true; - else - /* program the local mac in the kernel. when the ES - * change we need to force the dataplane to reset - * the activity as we are yet to establish activity - * locally - */ - zebra_evpn_sync_mac_dp_install( - mac, ctx->mac_inactive, - false /* force_clear_static */, __func__); + if (inform_dataplane && !ipa_len) { + /* program the local mac in the kernel. when the ES + * change we need to force the dataplane to reset + * the activity as we are yet to establish activity + * locally + */ + zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, + false /* force_clear_static */, + __func__); } return mac; @@ -1995,13 +1989,12 @@ void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket, zebra_evpn_print_mac_hash_detail(bucket, ctxt); } -int zebra_evpn_mac_remote_macip_add( - struct zebra_evpn *zevpn, struct zebra_vrf *zvrf, - const struct ethaddr *macaddr, uint16_t ipa_len, - const struct ipaddr *ipaddr, struct zebra_mac **macp, - struct in_addr vtep_ip, uint8_t flags, uint32_t seq, const esi_t *esi) +int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, + struct zebra_vrf *zvrf, + const struct ethaddr *macaddr, + struct in_addr vtep_ip, uint8_t flags, + uint32_t seq, const esi_t *esi) { - char buf1[INET6_ADDRSTRLEN]; bool sticky; bool remote_gw; int update_mac = 0; @@ -2023,11 +2016,8 @@ int zebra_evpn_mac_remote_macip_add( && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Ignore remote MACIP ADD VNI %u MAC %pEA%s%s as MAC is already configured as gateway MAC", - zevpn->vni, macaddr, - ipa_len ? " IP " : "", - ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1)) - : ""); + "Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC", + zevpn->vni, macaddr); return -1; } @@ -2048,10 +2038,6 @@ int zebra_evpn_mac_remote_macip_add( if (!mac) { mac = zebra_evpn_mac_add(zevpn, macaddr); zebra_evpn_es_mac_ref(mac, esi); - - /* Is this MAC created for a MACIP? */ - if (ipa_len) - SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); } else { /* When host moves but changes its (MAC,IP) * binding, BGP may install a MACIP entry that @@ -2061,8 +2047,8 @@ int zebra_evpn_mac_remote_macip_add( * the sequence number and ignore this update * if appropriate. */ - if (!zebra_evpn_mac_is_bgp_seq_ok( - zevpn, mac, seq, ipa_len, ipaddr, false)) + if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, + false)) return -1; old_es_present = !!mac->es; @@ -2146,12 +2132,7 @@ int zebra_evpn_mac_remote_macip_add( /* Update seq number. */ mac->rem_seq = seq; - /* If there is no IP, return after clearing AUTO flag of MAC. */ - if (!ipa_len) { - UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); - return -1; - } - *macp = mac; + UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); return 0; } diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h index b727ac1f98..9b4ea2b79e 100644 --- a/zebra/zebra_evpn_mac.h +++ b/zebra/zebra_evpn_mac.h @@ -176,17 +176,6 @@ struct rmac_walk_ctx { struct json_object *json; }; -/* temporary datastruct to pass info between the mac-update and - * neigh-update while handling mac-ip routes - */ -struct sync_mac_ip_ctx { - bool ignore_macip; - bool mac_created; - bool mac_inactive; - bool mac_dp_update_deferred; - struct zebra_mac *mac; -}; - /**************************** SYNC MAC handling *****************************/ /* if the mac has been added of a mac-route from the peer * or if it is being referenced by a neigh added by the @@ -232,6 +221,8 @@ struct zebra_mac *zebra_evpn_mac_lookup(struct zebra_evpn *zevi, const struct ethaddr *mac); struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevi, const struct ethaddr *macaddr); +struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevi, + const struct ethaddr *macaddr); int zebra_evpn_mac_del(struct zebra_evpn *zevi, struct zebra_mac *mac); int zebra_evpn_macip_send_msg_to_client(uint32_t id, const struct ethaddr *macaddr, @@ -255,20 +246,22 @@ int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr, int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr, uint32_t flags, bool force); void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevi); -struct zebra_mac *zebra_evpn_proc_sync_mac_update( - struct zebra_evpn *zevi, const struct ethaddr *macaddr, - uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags, - uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx); +struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevi, + const struct ethaddr *macaddr, + uint16_t ipa_len, + const struct ipaddr *ipaddr, + uint8_t flags, uint32_t seq, + const esi_t *esi); void zebra_evpn_sync_mac_del(struct zebra_mac *mac); void zebra_evpn_rem_mac_del(struct zebra_evpn *zevi, struct zebra_mac *mac); void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt); void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket, void *ctxt); -int zebra_evpn_mac_remote_macip_add( - struct zebra_evpn *zevpn, struct zebra_vrf *zvrf, - const struct ethaddr *macaddr, uint16_t ipa_len, - const struct ipaddr *ipaddr, struct zebra_mac **macp, - struct in_addr vtep_ip, uint8_t flags, uint32_t seq, const esi_t *esi); +int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, + struct zebra_vrf *zvrf, + const struct ethaddr *macaddr, + struct in_addr vtep_ip, uint8_t flags, + uint32_t seq, const esi_t *esi); int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, struct zebra_evpn *zevpn, diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 7b5f1fc240..470bbdb60b 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -626,11 +626,10 @@ void zebra_evpn_sync_neigh_del(struct zebra_neigh *n) struct zebra_neigh *zebra_evpn_proc_sync_neigh_update( struct zebra_evpn *zevpn, struct zebra_neigh *n, uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq, - const esi_t *esi, struct sync_mac_ip_ctx *ctx) + const esi_t *esi, struct zebra_mac *mac) { struct interface *ifp = NULL; bool is_router; - struct zebra_mac *mac = ctx->mac; uint32_t tmp_seq; bool old_router = false; bool old_bgp_ready = false; @@ -791,8 +790,8 @@ struct zebra_neigh *zebra_evpn_proc_sync_neigh_update( inform_bgp = true; new_mac_static = zebra_evpn_mac_is_static(mac); - if ((old_mac_static != new_mac_static) || ctx->mac_dp_update_deferred) - zebra_evpn_sync_mac_dp_install(mac, ctx->mac_inactive, + if (old_mac_static != new_mac_static) + zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, false /* force_clear_static */, __func__); @@ -1286,10 +1285,12 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn, zlog_debug("AUTO MAC %pEA created for neigh %pIA on VNI %u", macaddr, ip, zevpn->vni); - zmac = zebra_evpn_mac_add(zevpn, macaddr); - zebra_evpn_mac_clear_fwd_info(zmac); - memset(&zmac->flags, 0, sizeof(uint32_t)); - SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO); + zmac = zebra_evpn_mac_add_auto(zevpn, macaddr); + if (!zmac) { + zlog_debug("Failed to add MAC %pEA VNI %u", macaddr, + zevpn->vni); + return -1; + } } else { if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) { /* diff --git a/zebra/zebra_evpn_neigh.h b/zebra/zebra_evpn_neigh.h index c779109e0a..9271817440 100644 --- a/zebra/zebra_evpn_neigh.h +++ b/zebra/zebra_evpn_neigh.h @@ -231,7 +231,7 @@ void zebra_evpn_sync_neigh_del(struct zebra_neigh *n); struct zebra_neigh *zebra_evpn_proc_sync_neigh_update( struct zebra_evpn *zevpn, struct zebra_neigh *n, uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq, - const esi_t *esi, struct sync_mac_ip_ctx *ctx); + const esi_t *esi, struct zebra_mac *mac); void zebra_evpn_neigh_del_all(struct zebra_evpn *zevpn, int uninstall, int upd_client, uint32_t flags); struct zebra_neigh *zebra_evpn_neigh_lookup(struct zebra_evpn *zevpn, -- 2.39.5