diff options
-rw-r--r-- | bgpd/bgp_evpn.c | 858 | ||||
-rw-r--r-- | bgpd/bgp_evpn_mh.c | 4 | ||||
-rw-r--r-- | bgpd/bgp_evpn_private.h | 92 | ||||
-rw-r--r-- | bgpd/bgp_evpn_vty.c | 729 | ||||
-rw-r--r-- | bgpd/bgp_evpn_vty.h | 6 | ||||
-rw-r--r-- | bgpd/bgp_route.h | 5 | ||||
-rw-r--r-- | lib/command.h | 2 | ||||
-rw-r--r-- | zebra/zebra_evpn.c | 58 | ||||
-rw-r--r-- | zebra/zebra_evpn_mac.c | 131 | ||||
-rw-r--r-- | zebra/zebra_evpn_mac.h | 33 | ||||
-rw-r--r-- | zebra/zebra_evpn_neigh.c | 17 | ||||
-rw-r--r-- | 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 f50a45e94..6d402a4fe 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,24 +677,97 @@ 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. */ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, @@ -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,12 +2961,160 @@ 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 a0ab0881e..2a5c5d7ec 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 9b4405afe..eb78a755d 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 fc2271ed7..f8110117e 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; @@ -2373,6 +2418,32 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, } /* + * 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). */ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, @@ -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] [<detail$detail|json$uj>]", + 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] [<detail$detail|json$uj>]", + 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] [<detail$detail|json$uj>]", + 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] [<detail$detail|json$uj>]", + 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 <A.B.C.D|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 + "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 137365ddb..6b17a83b7 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 48e154716..1b04bfc71 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 70e52708a..b701d4d0e 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 168f0b2ce..e37f56f0e 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 4300b55c3..f0d256e28 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 b727ac1f9..9b4ea2b79 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 7b5f1fc24..470bbdb60 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 c779109e0..927181744 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, |