From 7d99ad7f93e42ca2f58023374843d70039a8310f Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 6 Jul 2021 10:59:35 -0400 Subject: [PATCH 01/15] zebra: add knob to accept lower seq in evpn Add a knob to accept lower seq number in evpn updates from BGP in Zebra. Note: Knob is enabled by default Signed-off-by: Stephen Worley --- zebra/zebra_evpn_mac.c | 17 ++++++----------- zebra/zebra_evpn_neigh.c | 4 +--- zebra/zebra_vty.c | 26 ++++++++++++++++++++++++++ zebra/zebra_vxlan.c | 14 ++++++++++++++ zebra/zebra_vxlan.h | 3 +++ 5 files changed, 50 insertions(+), 14 deletions(-) diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index cbdc17653b..c58b55abdf 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -1597,6 +1597,7 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, bool sync) { char ipbuf[INET6_ADDRSTRLEN]; + char mac_buf[MAC_BUF_SIZE]; uint32_t tmp_seq; const char *n_type; @@ -1611,19 +1612,14 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, if (seq < tmp_seq) { /* if the mac was never advertised to bgp we must accept * whatever sequence number bgp sends - * XXX - check with Vivek */ - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) - && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC - || IS_ZEBRA_DEBUG_VXLAN) { - char mac_buf[MAC_BUF_SIZE]; - + if (zebra_vxlan_accept_bgp_seq()) { + 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", sync ? "sync" : "rem", zevpn->vni, - n_type, - &mac->macaddr, + n_type, &mac->macaddr, ipa_len ? " IP " : "", ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) @@ -1637,8 +1633,6 @@ 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) { - char mac_buf[MAC_BUF_SIZE]; - zlog_debug( "%s-macip ignore vni %u %s-mac %pEA%s%s as existing has higher seq %u f %s", sync ? "sync" : "rem", zevpn->vni, n_type, @@ -1651,6 +1645,7 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, zebra_evpn_zebra_mac_flag_dump( mac, mac_buf, sizeof(mac_buf))); } + return false; } diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 6d90a603f7..c187b5947f 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -513,10 +513,8 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(struct zebra_evpn *zevpn, if (seq < tmp_seq) { /* if the neigh was never advertised to bgp we must accept * whatever sequence number bgp sends - * XXX - check with Vivek */ - if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) - && !zebra_evpn_neigh_is_ready_for_bgp(n)) { + if (zebra_vxlan_accept_bgp_seq()) { if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH || IS_ZEBRA_DEBUG_VXLAN) zlog_debug( diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 525e0366e7..a95e07d952 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -3740,6 +3740,27 @@ DEFPY (clear_evpn_dup_addr, return ret; } +DEFPY_HIDDEN (evpn_accept_bgp_seq, + evpn_accept_bgp_seq_cmd, + "evpn accept-bgp-seq", + "EVPN\n" + "Accept all sequence numbers from BGP\n") +{ + zebra_vxlan_set_accept_bgp_seq(true); + return CMD_SUCCESS; +} + +DEFPY_HIDDEN (no_evpn_accept_bgp_seq, + no_evpn_accept_bgp_seq_cmd, + "no evpn accept-bgp-seq", + NO_STR + "EVPN\n" + "Accept all sequence numbers from BGP\n") +{ + zebra_vxlan_set_accept_bgp_seq(false); + return CMD_SUCCESS; +} + /* Static ip route configuration write function. */ static int zebra_ip_config(struct vty *vty) { @@ -3945,6 +3966,9 @@ static int config_write_protocol(struct vty *vty) zebra_pbr_config_write(vty); + if (!zebra_vxlan_accept_bgp_seq()) + vty_out(vty, "no evpn accept-bgp-seq\n"); + /* Include nexthop-group config */ if (!zebra_nhg_kernel_nexthops_enabled()) vty_out(vty, "no zebra nexthop kernel enable\n"); @@ -4582,6 +4606,8 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_evpn_neigh_vni_dad_cmd); install_element(VIEW_NODE, &show_evpn_neigh_vni_all_dad_cmd); install_element(ENABLE_NODE, &clear_evpn_dup_addr_cmd); + install_element(CONFIG_NODE, &evpn_accept_bgp_seq_cmd); + install_element(CONFIG_NODE, &no_evpn_accept_bgp_seq_cmd); install_element(VIEW_NODE, &show_neigh_cmd); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 34cce71cd7..6954c63af0 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -69,6 +69,9 @@ DEFINE_HOOK(zebra_rmac_update, const char *reason), (rmac, zl3vni, delete, reason)); +/* config knobs */ +static bool accept_bgp_seq = true; + /* static function declarations */ static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket, void **args); @@ -6284,6 +6287,17 @@ extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx) return; } +/* Config knob for accepting lower sequence numbers */ +void zebra_vxlan_set_accept_bgp_seq(bool set) +{ + accept_bgp_seq = set; +} + +bool zebra_vxlan_accept_bgp_seq(void) +{ + return accept_bgp_seq; +} + /* Cleanup BGP EVPN configuration upon client disconnect */ extern void zebra_evpn_init(void) { diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 757c65d185..1d777e39f8 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -225,6 +225,9 @@ extern int zebra_vxlan_dp_network_mac_del(struct interface *ifp, struct ethaddr *macaddr, vlanid_t vid); +extern void zebra_vxlan_set_accept_bgp_seq(bool set); +extern bool zebra_vxlan_accept_bgp_seq(void); + #ifdef __cplusplus } #endif From 34c7f35f0217e16447ca0bc6aedd8aba2e51f877 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 23 Jul 2021 13:35:14 -0400 Subject: [PATCH 02/15] bgpd: rework VNI table for type2/macip routes Use the IP addr of type2/macip routes only for the hash/key of the VNI table and carry the MAC in a path_info_extra attribute. There is exists situations that can be hit during extended MAC mobility events where two MACs could be pointing to the same IP in our global table. It is requires very specific timings. When that happens, BPG would (because we key'd on both MAC and IP) install both into it's VNI table as separate entries, but zebra only knows/needs to know about a single IP -> MAC relationship for it's VNI table's type2 routes. So it was compleletly undeterministic which one zebra would end up with in these timing situations. With these changes, we move BGP's VNI table to key'd the same as Zebra's and now a single IP will have multiple path_info's with a path_info_extra that is carrying the MAC info for each path. BGP will then run best path to deterministically decide which one to send to zebra during the occasions where there exist's two possible MACs. Signed-off-by: Stephen Worley --- bgpd/bgp_evpn.c | 284 ++++++++++++++++++++++++++++------------ bgpd/bgp_evpn_mh.c | 14 +- bgpd/bgp_evpn_private.h | 55 +++++++- bgpd/bgp_evpn_vty.c | 117 +++++++++++++---- bgpd/bgp_route.c | 39 +++--- bgpd/bgp_route.h | 9 +- 6 files changed, 375 insertions(+), 143 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 58f5e9a226..4e5a62ce45 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -552,10 +552,14 @@ static void evpn_convert_nexthop_to_ipv6(struct attr *attr) attr->mp_nexthop_len = IPV6_MAX_BYTELEN; } -struct bgp_dest *bgp_global_evpn_node_get(struct bgp_table *table, afi_t afi, +/* + * Wrapper for node get in global table. + */ +struct bgp_dest *bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi, safi_t safi, const struct prefix_evpn *evp, - struct prefix_rd *prd) + struct prefix_rd *prd, + const struct bgp_path_info *local_pi) { struct prefix_evpn global_p; @@ -565,14 +569,28 @@ struct bgp_dest *bgp_global_evpn_node_get(struct bgp_table *table, afi_t afi, */ evpn_type1_prefix_global_copy(&global_p, evp); evp = &global_p; + } 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. + */ + evpn_type2_prefix_global_copy( + &global_p, evp, + *evpn_type2_path_info_get_mac(local_pi)); + evp = &global_p; } return bgp_afi_node_get(table, afi, safi, (struct prefix *)evp, prd); } -struct bgp_dest *bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi, - safi_t safi, - const struct prefix_evpn *evp, - struct prefix_rd *prd) +/* + * Wrapper for node lookup in global table. + */ +struct bgp_dest * +bgp_evpn_global_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi, + const struct prefix_evpn *evp, + struct prefix_rd *prd, + const struct bgp_path_info *local_pi) { struct prefix_evpn global_p; @@ -582,15 +600,86 @@ struct bgp_dest *bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi, */ evpn_type1_prefix_global_copy(&global_p, evp); evp = &global_p; + } 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. + */ + evpn_type2_prefix_global_copy( + &global_p, evp, + *evpn_type2_path_info_get_mac(local_pi)); + evp = &global_p; } return bgp_afi_node_lookup(table, afi, safi, (struct prefix *)evp, prd); } +/* + * Wrapper for node get in VNI 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 prefix_evpn vni_p; + + if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE && parent_pi) { + /* 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); + evp = &vni_p; + } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && + !is_evpn_prefix_ipaddr_none(evp)) { + /* + * IP prefix in the vni 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); + evp = &vni_p; + } + return bgp_node_get(table, (struct prefix *)evp); +} + +/* + * Wrapper for node lookup in VNI 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 prefix_evpn vni_p; + + if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE && parent_pi) { + /* 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); + evp = &vni_p; + } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && + !is_evpn_prefix_ipaddr_none(evp)) { + /* + * IP prefix in the vni 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); + evp = &vni_p; + } + return bgp_node_lookup(table, (struct prefix *)evp); +} + /* * Add (update) or delete MACIP from zebra. */ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p, + const struct ethaddr *mac, struct in_addr remote_vtep_ip, int add, uint8_t flags, uint32_t seq, esi_t *esi) { @@ -620,7 +709,12 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL, bgp->vrf_id); stream_putl(s, vpn->vni); - stream_put(s, &p->prefix.macip_addr.mac.octet, ETH_ALEN); /* Mac Addr */ + + if (mac) /* Mac Addr */ + stream_put(s, &mac->octet, ETH_ALEN); + else + stream_put(s, &p->prefix.macip_addr.mac.octet, ETH_ALEN); + /* IP address length and IP address, if any. */ if (is_evpn_prefix_ipaddr_none(p)) stream_putw(s, 0); @@ -985,8 +1079,9 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, } ret = bgp_zebra_send_remote_macip( - bgp, vpn, p, pi->attr->nexthop, 1, flags, - seq, bgp_evpn_attr_get_esi(pi->attr)); + bgp, vpn, p, evpn_type2_path_info_get_mac(pi), + pi->attr->nexthop, 1, flags, seq, + bgp_evpn_attr_get_esi(pi->attr)); } else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE) { ret = bgp_evpn_remote_es_evi_add(bgp, vpn, p); } else { @@ -1012,13 +1107,15 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, /* Uninstall EVPN route from zebra. */ static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p, - struct in_addr remote_vtep_ip) + struct bgp_path_info *pi, bool is_sync) { int ret; if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip, - 0, 0, 0, NULL); + ret = bgp_zebra_send_remote_macip( + bgp, vpn, p, evpn_type2_path_info_get_mac(pi), + (is_sync ? zero_vtep_ip : pi->attr->nexthop), 0, 0, 0, + NULL); else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE) ret = bgp_evpn_remote_es_evi_del(bgp, vpn, p); else @@ -1061,9 +1158,10 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn, * this table is a 2-level tree (RD-level + Prefix-level) similar to * L3VPN routes. */ - global_dest = bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi, - (const struct prefix_evpn *)bgp_dest_get_prefix(dest), - &vpn->prd); + global_dest = bgp_evpn_global_node_lookup( + bgp->rib[afi][safi], afi, safi, + (const struct prefix_evpn *)bgp_dest_get_prefix(dest), + &vpn->prd, old_local); if (global_dest) { /* Delete route entry in the global EVPN table. */ delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi); @@ -1176,7 +1274,7 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, bgp, vpn, (const struct prefix_evpn *)bgp_dest_get_prefix( dest), - old_select->attr->nexthop); + old_select, false); } /* Clear any route change flags. */ @@ -1362,9 +1460,8 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, build_evpn_type5_route_extcomm(bgp_vrf, &attr); /* get the route node in global table */ - dest = bgp_global_evpn_node_get(bgp_evpn->rib[afi][safi], afi, safi, - (const struct prefix_evpn *)evp, - &bgp_vrf->vrf_prd); + dest = bgp_evpn_global_node_get(bgp_evpn->rib[afi][safi], afi, safi, + evp, &bgp_vrf->vrf_prd, NULL); assert(dest); /* create or update the route entry within the route node */ @@ -1515,9 +1612,9 @@ static void update_evpn_route_entry_sync_info(struct bgp *bgp, 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, - int add, struct bgp_path_info **pi, - uint8_t flags, uint32_t seq, bool vpn_rt, - bool *old_is_sync) + const struct ethaddr *mac, int add, + struct bgp_path_info **pi, uint8_t flags, + uint32_t seq, bool vpn_rt, bool *old_is_sync) { struct bgp_path_info *tmp_pi; struct bgp_path_info *local_pi; @@ -1589,6 +1686,11 @@ 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); + + /* Mark route as self type-2 route */ if (flags && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP)) tmp_pi->extra->af_flags = BGP_EVPN_MACIP_TYPE_SVI_IP; @@ -1618,6 +1720,10 @@ 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); + /* The attribute has changed. */ /* Add (or update) attribute to hash. */ attr_new = bgp_attr_intern(attr); @@ -1798,12 +1904,12 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, /* First, create (or fetch) route node within the VNI. */ /* NOTE: There is no RD here. */ - dest = bgp_node_get(vpn->route_table, (struct prefix *)p); + dest = bgp_evpn_vni_node_get(vpn->route_table, p, NULL); /* Create or update route entry. */ - route_change = update_evpn_route_entry(bgp, vpn, afi, safi, dest, &attr, - 1, &pi, flags, seq, - true /* setup_sync */, &old_is_sync); + route_change = update_evpn_route_entry( + bgp, vpn, afi, safi, dest, &attr, &p->prefix.macip_addr.mac, 1, + &pi, flags, seq, true /* setup_sync */, &old_is_sync); assert(pi); attr_new = pi->attr; @@ -1841,7 +1947,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, */ new_is_sync = bgp_evpn_attr_is_sync(pi->attr); if (!new_is_sync && old_is_sync) - evpn_zebra_uninstall(bgp, vpn, p, zero_vtep_ip); + evpn_zebra_uninstall(bgp, vpn, p, pi, true); } } bgp_path_info_unlock(pi); @@ -1856,12 +1962,12 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, if (route_change) { struct bgp_path_info *global_pi; - dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi, - (const struct prefix_evpn *)p, - &vpn->prd); - update_evpn_route_entry(bgp, vpn, afi, safi, dest, attr_new, 1, - &global_pi, flags, seq, - false /* setup_sync */, NULL /* old_is_sync */); + 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 */); /* Schedule for processing and unlock node. */ bgp_process(bgp, dest, afi, safi); @@ -1915,8 +2021,8 @@ static int delete_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp) return 0; /* locate the global route entry for this type-5 prefix */ - dest = bgp_global_evpn_node_lookup(bgp_evpn->rib[afi][safi], afi, safi, - (const struct prefix_evpn *)evp, &bgp_vrf->vrf_prd); + dest = bgp_evpn_global_node_lookup(bgp_evpn->rib[afi][safi], afi, safi, + evp, &bgp_vrf->vrf_prd, NULL); if (!dest) return 0; @@ -1944,7 +2050,7 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * is nothing further to do. */ /* NOTE: There is no RD here. */ - dest = bgp_node_lookup(vpn->route_table, (struct prefix *)p); + dest = bgp_evpn_vni_node_lookup(vpn->route_table, p, NULL); if (!dest) return 0; @@ -1952,8 +2058,8 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * this table is a 2-level tree (RD-level + Prefix-level) similar to * L3VPN routes. */ - global_dest = bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi, - (const struct prefix_evpn *)p, &vpn->prd); + global_dest = bgp_evpn_global_node_lookup(bgp->rib[afi][safi], afi, + safi, p, &vpn->prd, NULL); if (global_dest) { /* Delete route entry in the global EVPN table. */ delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi); @@ -1992,14 +2098,20 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, int add_l3_ecomm = 0; struct bgp_dest *global_dest; struct bgp_path_info *global_pi; - struct prefix_evpn *evp = - (struct prefix_evpn *)bgp_dest_get_prefix(dest); + struct prefix_evpn evp; int route_change; bool old_is_sync = false; if (CHECK_FLAG(local_pi->flags, BGP_PATH_REMOVED)) return; + /* + * 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)); + /* * Build attribute per local route as the MAC mobility and * some other values could differ for different routes. The @@ -2014,18 +2126,17 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, attr.es_flags = local_pi->attr->es_flags; if (local_pi->attr->default_gw) { attr.default_gw = 1; - if (is_evpn_prefix_ipaddr_v6(evp)) + if (is_evpn_prefix_ipaddr_v6(&evp)) attr.router_flag = 1; } memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t)); - bgp_evpn_get_rmac_nexthop(vpn, evp, &attr, - local_pi->extra->af_flags); + bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr, local_pi->extra->af_flags); vni2label(vpn->vni, &(attr.label)); /* Add L3 VNI RTs and RMAC for non IPv6 link-local if * using L3 VNI for type-2 routes also. */ add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok( - vpn, evp, + vpn, &evp, (attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL); /* Set up extended community. */ @@ -2039,15 +2150,15 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, "VRF %s vni %u evp %pFX RMAC %pEA nexthop %pI4 esi %s esf 0x%x from %s", vpn->bgp_vrf ? vrf_id_to_name(vpn->bgp_vrf->vrf_id) : " ", - vpn->vni, evp, &attr.rmac, &attr.mp_nexthop_global_in, + vpn->vni, &evp, &attr.rmac, &attr.mp_nexthop_global_in, esi_to_str(&attr.esi, buf3, sizeof(buf3)), attr.es_flags, caller); } /* Update the route entry. */ route_change = update_evpn_route_entry( - bgp, vpn, afi, safi, dest, &attr, 0, &pi, 0, seq, - true /* setup_sync */, &old_is_sync); + bgp, vpn, afi, safi, dest, &attr, NULL /* mac */, 0, &pi, 0, + seq, true /* setup_sync */, &old_is_sync); assert(pi); attr_new = pi->attr; @@ -2082,8 +2193,7 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, */ new_is_sync = bgp_evpn_attr_is_sync(pi->attr); if (!new_is_sync && old_is_sync) - evpn_zebra_uninstall(bgp, vpn, - evp, zero_vtep_ip); + evpn_zebra_uninstall(bgp, vpn, &evp, pi, true); } } @@ -2093,13 +2203,14 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, if (route_change) { /* Update route in global routing table. */ - global_dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, - safi, evp, &vpn->prd); + 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, 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 */, 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); @@ -2400,6 +2511,7 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi, pi->extra->num_labels = parent_pi->extra->num_labels; pi->extra->igpmetric = parent_pi->extra->igpmetric; } + bgp_path_info_add(dest, pi); return pi; @@ -2589,20 +2701,12 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct bgp_path_info *local_pi; struct attr *attr_new; int ret; - struct prefix_evpn ad_evp; bool old_local_es = false; bool new_local_es; - /* EAD prefix in the global table doesn't include the VTEP-IP so - * we need to create a different copy for the VNI - */ - if (p->prefix.route_type == BGP_EVPN_AD_ROUTE) - p = evpn_type1_prefix_vni_copy(&ad_evp, p, - parent_pi->attr->nexthop); - /* Create (or fetch) route within the VNI. */ /* NOTE: There is no RD here. */ - dest = bgp_node_get(vpn->route_table, (struct prefix *)p); + 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) @@ -2614,6 +2718,11 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, /* Create an info */ 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); + new_local_es = bgp_evpn_attr_is_local_es(pi->attr); } else { if (attrhash_cmp(pi->attr, parent_pi->attr) @@ -2765,18 +2874,10 @@ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct bgp_path_info *pi; struct bgp_path_info *local_pi; int ret; - struct prefix_evpn ad_evp; - - /* EAD prefix in the global table doesn't include the VTEP-IP so - * we need to create a different copy for the VNI - */ - if (p->prefix.route_type == BGP_EVPN_AD_ROUTE) - p = evpn_type1_prefix_vni_copy(&ad_evp, p, - parent_pi->attr->nexthop); /* Locate route within the VNI. */ /* NOTE: There is no RD here. */ - dest = bgp_node_lookup(vpn->route_table, (struct prefix *)p); + dest = bgp_evpn_vni_node_lookup(vpn->route_table, p, parent_pi); if (!dest) return 0; @@ -3623,7 +3724,7 @@ 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_node_lookup(vpn->route_table, (struct prefix *)&p); + dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL); if (!dest) /* unexpected */ return 0; for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) @@ -3637,11 +3738,12 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) } attr = pi->attr; - global_dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], - afi, safi, &p, &vpn->prd); - update_evpn_route_entry(bgp, vpn, afi, safi, global_dest, attr, - 1, &pi, 0, mac_mobility_seqnum(attr), - false /* setup_sync */, NULL /* old_is_sync */); + 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), + false /* setup_sync */, NULL /* old_is_sync */); /* Schedule for processing and unlock node. */ bgp_process(bgp, global_dest, afi, safi); @@ -3653,6 +3755,7 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) */ 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); @@ -3672,19 +3775,28 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) 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_global_evpn_node_get(bgp->rib[afi][safi], afi, safi, - evp, &vpn->prd); + 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, 1, - &global_pi, 0, mac_mobility_seqnum(attr), + 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 */ @@ -3724,8 +3836,8 @@ static int delete_withdraw_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) /* Remove type-3 route for this VNI from global table. */ build_evpn_type3_prefix(&p, vpn->originator_ip); - global_dest = bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi, - (const struct prefix_evpn *)&p, &vpn->prd); + global_dest = bgp_evpn_global_node_lookup(bgp->rib[afi][safi], afi, + safi, &p, &vpn->prd, NULL); if (global_dest) { /* Delete route entry in the global EVPN table. */ delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi); @@ -5482,7 +5594,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_node_lookup(vpn->route_table, (struct prefix *)&p); + dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL); if (dest) { evpn_zebra_reinstall_best_route(bgp, vpn, dest); bgp_dest_unlock_node(dest); diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 1d40664aeb..a0ab0881e7 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -498,9 +498,8 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es, /* Next, locate route node in the global EVPN routing table. * Note that this table is a 2-level tree (RD-level + Prefix-level) */ - global_dest = - bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi, - (const struct prefix_evpn *)p, prd); + global_dest = bgp_evpn_global_node_lookup(bgp->rib[afi][safi], afi, + safi, p, prd, NULL); if (global_dest) { /* Delete route entry in the global EVPN table. */ @@ -675,8 +674,9 @@ static int bgp_evpn_type4_route_update(struct bgp *bgp, if (route_changed) { struct bgp_path_info *global_pi; - dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi, - p, &es->es_base_frag->prd); + dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi, + p, &es->es_base_frag->prd, + NULL); bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi, dest, attr_new, &global_pi, &route_changed); @@ -1015,8 +1015,8 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es, if (route_changed) { struct bgp_path_info *global_pi; - dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi, - p, global_rd); + dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi, + p, global_rd, NULL); bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest, attr_new, &global_pi, &route_changed); diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 64fdc29704..9b4405afe7 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -543,6 +543,39 @@ 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) +{ + memcpy(global_p, vni_p, sizeof(*global_p)); + global_p->prefix.macip_addr.mac = mac; +} + +static inline void +evpn_type2_prefix_vni_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)); +} + +/* 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; +} + +/* Set MAC of path_info prefix */ +static inline void evpn_type2_path_info_set_mac(struct bgp_path_info *local_pi, + const struct ethaddr mac) +{ + assert(local_pi->extra); + local_pi->extra->mac = mac; +} + static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi, safi_t safi) { @@ -633,14 +666,24 @@ extern void delete_evpn_route_entry(struct bgp *bgp, afi_t afi, safi_t safi, int vni_list_cmp(void *p1, void *p2); extern int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, struct bgp_dest *dest); -extern struct bgp_dest *bgp_global_evpn_node_get(struct bgp_table *table, - afi_t afi, safi_t safi, - const struct prefix_evpn *evp, - struct prefix_rd *prd); extern struct bgp_dest * -bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi, +bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi, safi_t safi, + const struct prefix_evpn *evp, struct prefix_rd *prd, + const struct bgp_path_info *local_pi); +extern struct bgp_dest * +bgp_evpn_global_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi, const struct prefix_evpn *evp, - struct prefix_rd *prd); + 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, + 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, + 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, struct bgp_node *rn, diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 5ad5cf8bff..fc2271ed72 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -735,7 +735,8 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi, if (detail) route_vty_out_detail( - vty, bgp, rn, pi, AFI_L2VPN, SAFI_EVPN, + vty, bgp, rn, bgp_dest_get_prefix(rn), + pi, AFI_L2VPN, SAFI_EVPN, RPKI_NOT_BEING_USED, json_path); else route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN, @@ -818,6 +819,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, * with code that already exists). */ for (; pi; pi = pi->next) { + struct prefix tmp_p; json_object *json_path = NULL; if (vtep_ip.s_addr != INADDR_ANY @@ -825,16 +827,30 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, &(pi->attr->nexthop))) continue; + 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. + */ + 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)); + + if (json) json_path = json_object_new_array(); if (detail) - route_vty_out_detail(vty, bgp, dest, pi, + route_vty_out_detail(vty, bgp, dest, &tmp_p, pi, AFI_L2VPN, SAFI_EVPN, RPKI_NOT_BEING_USED, json_path); else - route_vty_out(vty, p, pi, 0, SAFI_EVPN, + route_vty_out(vty, &tmp_p, pi, 0, SAFI_EVPN, json_path, false); if (json) @@ -846,6 +862,19 @@ 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", @@ -2371,7 +2400,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_node_lookup(vpn->route_table, (struct prefix *)&p); + dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL); if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) { if (!json) vty_out(vty, "%% Network not in table\n"); @@ -2386,7 +2415,8 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, json_paths = json_object_new_array(); /* Prefix and num paths displayed once per prefix. */ - route_vty_out_detail_header(vty, bgp, dest, NULL, afi, safi, json); + route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest), + NULL, afi, safi, json); /* Display each path for this prefix. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { @@ -2395,8 +2425,9 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out_detail(vty, bgp, dest, pi, afi, safi, - RPKI_NOT_BEING_USED, json_path); + route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), + pi, afi, safi, RPKI_NOT_BEING_USED, + json_path); if (json) json_object_array_add(json_paths, json_path); @@ -2427,6 +2458,7 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, { struct bgpevpn *vpn; struct prefix_evpn p; + struct prefix_evpn tmp_p; struct bgp_dest *dest; struct bgp_path_info *pi; uint32_t path_cnt = 0; @@ -2447,7 +2479,7 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, /* See if route exists. Look for both non-sticky and sticky. */ build_evpn_type2_prefix(&p, mac, ip); - dest = bgp_node_lookup(vpn->route_table, (struct prefix *)&p); + dest = bgp_evpn_vni_node_lookup(vpn->route_table, &p, NULL); if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) { if (!json) vty_out(vty, "%% Network not in table\n"); @@ -2458,21 +2490,54 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, return; } + /* + * 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 (!pi) { + if (!json) + vty_out(vty, "%% Network not in table\n"); + return; + } + if (json) json_paths = json_object_new_array(); /* Prefix and num paths displayed once per prefix. */ - route_vty_out_detail_header(vty, bgp, dest, NULL, afi, safi, json); + route_vty_out_detail_header(vty, bgp, dest, (struct prefix *)&p, NULL, + afi, safi, json); /* 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), + sizeof(*mac)) != 0) + continue; + if (json) json_path = json_object_new_array(); - route_vty_out_detail(vty, bgp, dest, pi, afi, safi, - RPKI_NOT_BEING_USED, json_path); + /* + * VNI table MAC-IP prefixes don't have MAC so + * 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)); + + route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p, + pi, afi, safi, RPKI_NOT_BEING_USED, + json_path); if (json) json_object_array_add(json_paths, json_path); @@ -2568,7 +2633,8 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp, } /* Prefix and num paths displayed once per prefix. */ - route_vty_out_detail_header(vty, bgp, dest, prd, afi, safi, json); + route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest), + prd, afi, safi, json); if (json) json_paths = json_object_new_array(); @@ -2580,8 +2646,9 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out_detail(vty, bgp, dest, pi, afi, safi, - RPKI_NOT_BEING_USED, json_path); + route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), + pi, afi, safi, RPKI_NOT_BEING_USED, + json_path); if (json) json_object_array_add(json_paths, json_path); @@ -2673,8 +2740,9 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, } /* Prefix and num paths displayed once per prefix. */ - route_vty_out_detail_header(vty, bgp, dest, prd, afi, - safi, json_prefix); + route_vty_out_detail_header( + vty, bgp, dest, bgp_dest_get_prefix(dest), prd, + afi, safi, json_prefix); prefix_cnt++; } @@ -2689,8 +2757,9 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out_detail(vty, bgp, dest, pi, afi, safi, - RPKI_NOT_BEING_USED, json_path); + route_vty_out_detail( + vty, bgp, dest, bgp_dest_get_prefix(dest), pi, + afi, safi, RPKI_NOT_BEING_USED, json_path); if (json) json_object_array_add(json_paths, json_path); @@ -2807,7 +2876,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp, } else /* Prefix and num paths displayed once per prefix. */ route_vty_out_detail_header( - vty, bgp, dest, (struct prefix_rd *)rd_destp, + vty, bgp, dest, p, (struct prefix_rd *)rd_destp, AFI_L2VPN, SAFI_EVPN, json_prefix); /* For EVPN, the prefix is displayed for each path (to @@ -2822,7 +2891,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out_detail(vty, bgp, dest, pi, AFI_L2VPN, + route_vty_out_detail(vty, bgp, dest, p, pi, AFI_L2VPN, SAFI_EVPN, RPKI_NOT_BEING_USED, json_path); @@ -2960,6 +3029,7 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, if (detail) route_vty_out_detail_header( vty, bgp, dest, + bgp_dest_get_prefix(dest), (struct prefix_rd *)rd_destp, AFI_L2VPN, SAFI_EVPN, json_prefix); @@ -2979,9 +3049,10 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, if (detail) { route_vty_out_detail( - vty, bgp, dest, pi, AFI_L2VPN, - SAFI_EVPN, RPKI_NOT_BEING_USED, - json_path); + vty, bgp, dest, + bgp_dest_get_prefix(dest), pi, + AFI_L2VPN, SAFI_EVPN, + RPKI_NOT_BEING_USED, json_path); } else route_vty_out(vty, p, pi, 0, SAFI_EVPN, json_path, false); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 7d4110029e..7ec2484572 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10003,7 +10003,8 @@ static void route_vty_out_detail_es_info(struct vty *vty, } void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, - struct bgp_path_info *path, afi_t afi, safi_t safi, + const struct prefix *p, struct bgp_path_info *path, + afi_t afi, safi_t safi, enum rpki_states rpki_curr_state, json_object *json_paths) { @@ -10048,7 +10049,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, if (safi == SAFI_EVPN) { if (!json_paths) - vty_out(vty, " Route %pRN", bn); + vty_out(vty, " Route %pFX", p); } if (path->extra) { @@ -10209,10 +10210,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, /* Line2 display Next-hop, Neighbor, Router-id */ /* Display the nexthop */ - const struct prefix *bn_p = bgp_dest_get_prefix(bn); - if ((bn_p->family == AF_INET || bn_p->family == AF_ETHERNET || - bn_p->family == AF_EVPN) && + if ((p->family == AF_INET || p->family == AF_ETHERNET || + p->family == AF_EVPN) && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN || !BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) { if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP @@ -10325,7 +10325,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, /* This path was originated locally */ if (path->peer == bgp->peer_self) { - if (safi == SAFI_EVPN || (bn_p->family == AF_INET && + if (safi == SAFI_EVPN || (p->family == AF_INET && !BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) { if (json_paths) json_object_string_add(json_peer, "peerId", @@ -11340,8 +11340,9 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, prd = bgp_rd_from_dest(dest, safi); route_vty_out_detail_header( - vty, bgp, dest, prd, table->afi, - safi, jtemp); + vty, bgp, dest, + bgp_dest_get_prefix(dest), prd, + table->afi, safi, jtemp); json_object_array_add(json_paths, jtemp); @@ -11367,7 +11368,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, else { if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_DETAIL)) route_vty_out_detail( - vty, bgp, dest, pi, + vty, bgp, dest, + bgp_dest_get_prefix(dest), pi, family2afi(dest_p->family), safi, RPKI_NOT_BEING_USED, json_paths); @@ -11588,12 +11590,11 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi, /* Header of detailed BGP route information */ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, - struct bgp_dest *dest, - const struct prefix_rd *prd, - afi_t afi, safi_t safi, json_object *json) + struct bgp_dest *dest, const struct prefix *p, + const struct prefix_rd *prd, afi_t afi, + safi_t safi, json_object *json) { struct bgp_path_info *pi; - const struct prefix *p; struct peer *peer; struct listnode *node, *nnode; char buf1[RD_ADDRSTRLEN]; @@ -11623,7 +11624,6 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, mpls_lse_decode(dest->local_label, &label, &ttl, &exp, &bos); - p = bgp_dest_get_prefix(dest); has_valid_label = bgp_is_valid_label(&label); if (safi == SAFI_EVPN) { @@ -11831,8 +11831,9 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd, if (header) { route_vty_out_detail_header( - vty, bgp, bgp_node, pfx_rd, - AFI_IP, safi, json_header); + vty, bgp, bgp_node, + bgp_dest_get_prefix(bgp_node), pfx_rd, AFI_IP, + safi, json_header); header = 0; } (*display)++; @@ -11843,8 +11844,10 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd, || (pathtype == BGP_PATH_SHOW_MULTIPATH && (CHECK_FLAG(pi->flags, BGP_PATH_MULTIPATH) || CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)))) - route_vty_out_detail(vty, bgp, bgp_node, pi, AFI_IP, - safi, rpki_curr_state, json_paths); + route_vty_out_detail(vty, bgp, bgp_node, + bgp_dest_get_prefix(bgp_node), pi, + AFI_IP, safi, rpki_curr_state, + json_paths); } if (json && json_paths) { diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index ddef4ca1bb..48e1547166 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -214,9 +214,11 @@ struct bgp_path_info_extra { } vnc; #endif - /* For imported routes into a VNI (or VRF), this points to the parent. + /* + * For imported routes into a VNI (or VRF) */ - void *parent; + void *parent; /* parent from global table */ + struct ethaddr mac; /* MAC set here for VNI table */ /* * Some tunnelish parameters follow. Maybe consolidate into an @@ -827,10 +829,11 @@ extern bool bgp_zebra_has_route_changed(struct bgp_path_info *selected); extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, struct bgp_dest *dest, + const struct prefix *p, const struct prefix_rd *prd, afi_t afi, safi_t safi, json_object *json); extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, - struct bgp_dest *bn, + struct bgp_dest *bn, const struct prefix *p, struct bgp_path_info *path, afi_t afi, safi_t safi, enum rpki_states, json_object *json_paths); From 1e1398e3daa4c63c18da8e1f49b3c20bac6a3490 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 26 Oct 2021 17:48:49 -0400 Subject: [PATCH 03/15] zebra: special sync routes lower seq handling Add some special handling to accept lower seq routes for local known routes when not ready. This aligns the code back a bit more to where it was before to fix seen issues with sync routes. Signed-off-by: Stephen Worley --- zebra/zebra_evpn_mac.c | 15 ++++++++++++++- zebra/zebra_evpn_neigh.c | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index c58b55abdf..4300b55c3b 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -1600,20 +1600,33 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, char mac_buf[MAC_BUF_SIZE]; uint32_t tmp_seq; const char *n_type; + bool is_local = false; if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { tmp_seq = mac->loc_seq; n_type = "local"; + is_local = true; } else { tmp_seq = mac->rem_seq; n_type = "remote"; } if (seq < tmp_seq) { + + if (is_local && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) { + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x", + sync ? "sync" : "rem", zevpn->vni, + n_type, &mac->macaddr, tmp_seq, + mac->flags); + return true; + } + /* if the mac was never advertised to bgp we must accept * whatever sequence number bgp sends */ - if (zebra_vxlan_accept_bgp_seq()) { + if (!is_local && zebra_vxlan_accept_bgp_seq()) { if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) { zlog_debug( diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index c187b5947f..7b5f1fc240 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -501,20 +501,33 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(struct zebra_evpn *zevpn, { uint32_t tmp_seq; const char *n_type; + bool is_local = false; if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { tmp_seq = n->loc_seq; n_type = "local"; + is_local = true; } else { tmp_seq = n->rem_seq; n_type = "remote"; } if (seq < tmp_seq) { + if (is_local && !zebra_evpn_neigh_is_ready_for_bgp(n)) { + if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH || + IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%s-macip not ready vni %u %s mac %pEA IP %pIA lower seq %u f 0x%x", + sync ? "sync" : "remote", zevpn->vni, + n_type, macaddr, &n->ip, tmp_seq, + n->flags); + return true; + } + /* if the neigh was never advertised to bgp we must accept * whatever sequence number bgp sends */ - if (zebra_vxlan_accept_bgp_seq()) { + if (!is_local && zebra_vxlan_accept_bgp_seq()) { if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH || IS_ZEBRA_DEBUG_VXLAN) zlog_debug( From 90f30caa242299c0c86e4161702cc1a70c8a6f75 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Tue, 17 Aug 2021 11:27:35 -0700 Subject: [PATCH 04/15] bgpd: include ESI in the zebra update log Log changes only; no functional change. Signed-off-by: Anuradha Karuppiah --- bgpd/bgp_evpn.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 4e5a62ce45..8430e7d9d9 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -686,6 +686,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, struct stream *s; uint16_t ipa_len; static struct in_addr zero_remote_vtep_ip; + bool esi_valid; /* Check socket. */ if (!zclient || zclient->sock < 0) @@ -727,10 +728,13 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, /* If the ESI is valid that becomes the nexthop; tape out the * VTEP-IP for that case */ - if (bgp_evpn_is_esi_valid(esi)) + if (bgp_evpn_is_esi_valid(esi)) { + esi_valid = true; stream_put_in_addr(s, &zero_remote_vtep_ip); - else + } else { + esi_valid = false; stream_put_in_addr(s, &remote_vtep_ip); + } /* TX flags - MAC sticky status and/or gateway mac */ /* Also TX the sequence number of the best route. */ @@ -742,12 +746,19 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, stream_putw_at(s, 0, stream_get_endp(s)); - if (bgp_debug_zebra(NULL)) + if (bgp_debug_zebra(NULL)) { + char esi_buf[ESI_STR_LEN]; + + if (esi_valid) + esi_to_str(esi, esi_buf, sizeof(esi_buf)); + else + snprintf(esi_buf, sizeof(esi_buf), "-"); zlog_debug( - "Tx %s MACIP, VNI %u MAC %pEA IP %pIA flags 0x%x seq %u remote VTEP %pI4", + "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); + flags, seq, &remote_vtep_ip, esi_buf); + } frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip, esi); From 36bac85c7f7b059818a8bc60c08e383369453750 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Mon, 23 Aug 2021 10:11:05 -0700 Subject: [PATCH 05/15] bgpd: sync seq numbers only if the MAC address is the same We locate the sync path with the highest seq number for normalizing local path to the same seq. With the change to maintain the VNI RT table by IP address (instead of MAC&IP) we need additional changes to skip paths with a different mac address than the local one we are trying to normalize. Signed-off-by: Anuradha Karuppiah --- bgpd/bgp_evpn.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 8430e7d9d9..f50a45e940 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1494,13 +1494,22 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi, struct bgp_dest *dest, uint32_t loc_seq, uint32_t *max_sync_seq, bool *active_on_peer, - bool *peer_router, bool *proxy_from_peer) + bool *peer_router, bool *proxy_from_peer, + const struct ethaddr *mac) { struct bgp_path_info *tmp_pi; struct bgp_path_info *second_best_path = NULL; uint32_t tmp_mm_seq = 0; esi_t *tmp_esi; int paths_eq; + struct ethaddr *tmp_mac; + bool mac_cmp = false; + struct prefix_evpn *evp = (struct prefix_evpn *)&dest->p; + + + /* mac comparison is not needed for MAC-only routes */ + if (mac && !is_evpn_prefix_ipaddr_none(evp)) + mac_cmp = true; /* find the best non-local path. a local path can only be present * as best path @@ -1511,6 +1520,13 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi, !CHECK_FLAG(tmp_pi->flags, BGP_PATH_VALID)) continue; + /* ignore paths that have a different mac */ + if (mac_cmp) { + tmp_mac = evpn_type2_path_info_get_mac(tmp_pi); + if (memcmp(mac, tmp_mac, sizeof(*mac))) + continue; + } + if (bgp_evpn_path_info_cmp(bgp, tmp_pi, second_best_path, &paths_eq)) second_best_path = tmp_pi; @@ -1555,7 +1571,8 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi, static void update_evpn_route_entry_sync_info(struct bgp *bgp, struct bgp_dest *dest, struct attr *attr, - uint32_t loc_seq, bool setup_sync) + uint32_t loc_seq, bool setup_sync, + const struct ethaddr *mac) { esi_t *esi; struct prefix_evpn *evp = @@ -1574,7 +1591,8 @@ static void update_evpn_route_entry_sync_info(struct bgp *bgp, bgp_evpn_get_sync_info(bgp, esi, dest, loc_seq, &max_sync_seq, &active_on_peer, - &peer_router, &proxy_from_peer); + &peer_router, &proxy_from_peer, + mac); attr->mm_sync_seqnum = max_sync_seq; if (active_on_peer) attr->es_flags |= ATTR_ES_PEER_ACTIVE; @@ -1656,7 +1674,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, /* if a local path is being added with a non-zero esi look * for SYNC paths from ES peers and bubble up the sync-info */ - update_evpn_route_entry_sync_info(bgp, dest, attr, seq, vpn_rt); + update_evpn_route_entry_sync_info(bgp, dest, attr, seq, vpn_rt, mac); /* For non-GW MACs, update MAC mobility seq number, if needed. */ if (seq && !CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) From 852d9f97570045dc4186940d424c856995999fbb Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 26 Oct 2021 17:55:54 -0400 Subject: [PATCH 06/15] 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 | 890 +++++++++++++++++++++++++++------------ bgpd/bgp_evpn_mh.c | 4 +- bgpd/bgp_evpn_private.h | 94 ++++- 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, 1490 insertions(+), 481 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,51 +612,31 @@ 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 prefix_evpn vni_p; - - if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE && parent_pi) { - /* 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); - evp = &vni_p; - } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && - !is_evpn_prefix_ipaddr_none(evp)) { - /* - * IP prefix in the vni 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); - evp = &vni_p; - } - return bgp_node_get(table, (struct prefix *)evp); -} - -/* - * Wrapper for node lookup in VNI table. - */ -struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgp_table *const table, +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) { @@ -657,23 +646,127 @@ 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_get(table, (struct prefix *)evp); +} + +/* + * Wrapper for node lookup in VNI IP table. + */ +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; + + if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE && parent_pi) { + /* 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_ip_copy(&vni_p, evp, + parent_pi->attr->nexthop); + evp = &vni_p; + } 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); + + /* + * prefix in the vni IP table doesn't include MAC so + * we need to create a different copy of the prefix. + */ + 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); + for (dest = bgp_table_top(vpn->mac_table); dest; + dest = bgp_route_next(dest)) + update_type2_route(bgp, vpn, 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__); - } - - 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; + int ret = 0; - /* 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; + 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); - /* 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; + ret = uninstall_evpn_route_entry_in_vni_ip(bgp, vpn, p, parent_pi); - if (!pi) { - bgp_dest_unlock_node(dest); - return 0; + 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); + + return ret; } - bgp_evpn_remote_ip_hash_del(vpn, pi); + ret = uninstall_evpn_route_entry_in_vni_mac(bgp, vpn, p, parent_pi); - /* Mark entry for deletion */ - bgp_path_info_delete(dest, pi); + 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); - /* 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__); - - /* 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); + for (dest = bgp_table_top(vpn->mac_table); dest; + dest = bgp_route_next(dest)) + update_advertise_vni_route(bgp, vpn, 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); - } - - 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, - const struct bgp_path_info *parent_pi); -extern struct bgp_dest * -bgp_evpn_vni_node_lookup(const struct bgp_table *const table, +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 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,13 +931,49 @@ 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, json_object *json) { @@ -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; + + zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr, + flags, seq, esi, mac); } - - 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); } /************************** 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, From 0653625d3b8ba939b8b1cf1785a2dc12baecee74 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 9 Nov 2021 17:32:17 -0500 Subject: [PATCH 07/15] zebra: add some neigh del not found debugs Add some neigh deletion debugs for when the neigh isn't found or there is a MAC mismatch on what was sent and found. Signed-off-by: Stephen Worley --- zebra/zebra_evpn.c | 9 +++++++-- zebra/zebra_evpn_neigh.c | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index e37f56f0eb..f207477445 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -1528,7 +1528,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr, if (n && !mac) { zlog_warn( - "Failed to locate MAC %pEA for neigh %pIA VNI %u upon remote MACIP DEL", + "Failed to locate MAC %pEA for Neigh %pIA VNI %u upon remote MACIP DEL", macaddr, ipaddr, vni); return; } @@ -1536,8 +1536,13 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr, /* If the remote mac or neighbor doesn't exist there is nothing * more to do. Otherwise, uninstall the entry and then remove it. */ - if (!mac && !n) + if (!mac && !n) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Failed to locate MAC %pEA & Neigh %pIA VNI %u upon remote MACIP DEL", + macaddr, ipaddr, vni); return; + } zvrf = zevpn->vxlan_if->vrf->info; diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 470bbdb60b..5044d2f6c2 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -2245,6 +2245,12 @@ void zebra_evpn_neigh_remote_uninstall(struct zebra_evpn *zevpn, zebra_evpn_neigh_del(zevpn, n); zebra_evpn_deref_ip2mac(zevpn, mac); } + } else { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%s: IP %pIA MAC %pEA (flags 0x%x) found doesn't match MAC %pEA, ignoring Neigh DEL", + __func__, ipaddr, &n->emac, n->flags, + &mac->macaddr); } } From 15919b89154199f59a60f439e426ced4cd602d2a Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 9 Nov 2021 17:52:03 -0500 Subject: [PATCH 08/15] bgpd: add show bgp vni json commands Add add show bgp vni json commands. This is very similar to the old `show bgp evpn l2vpn vni route json` commands but adds a new `macTable` object under the normal output. This may change in the future but doing it like this for now VNI ALL: ``` { "1002":{ "vni":1002, "[2]:[0]:[48]:[00:00:00:00:00:00]:[128]:[fe80::202:ff:fe00:9]":{ "prefix":"[2]:[0]:[48]:[00:00:00:00:00:00]:[128]:[fe80::202:ff:fe00:9]", "prefixLen":352, "paths":[ [ { "valid":true, "pathFrom":"external", ... ... ... "numPrefix":4, "numPaths":7, "macTable":{ "[2]:[0]:[48]:[00:02:00:00:00:09]":{ "prefix":"[2]:[0]:[48]:[00:02:00:00:00:09]", "prefixLen":352, "paths":[ [ { "valid":true, "pathFrom":"external", ``` VNI 1002: ``` { "[2]:[0]:[48]:[00:00:00:00:00:00]:[128]:[fe80::202:ff:fe00:9]":{ "prefix":"[2]:[0]:[48]:[00:00:00:00:00:00]:[128]:[fe80::202:ff:fe00:9]", "prefixLen":352, "paths":[ [ { "valid":true, "pathFrom":"external", ... ... ... "numPrefix":4, "numPaths":7, "macTable":{ "[2]:[0]:[48]:[00:02:00:00:00:09]":{ "prefix":"[2]:[0]:[48]:[00:02:00:00:00:09]", "prefixLen":352, "paths":[ [ { "valid":true, "pathFrom":"external", ``` Signed-off-by: Stephen Worley --- bgpd/bgp_evpn_vty.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index f8110117ec..5d16b55d57 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -5241,14 +5241,15 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all, */ DEFPY(show_bgp_vni_all, show_bgp_vni_all_cmd, - "show bgp vni all [vtep A.B.C.D$addr] [detail$detail]", + "show bgp vni all [vtep A.B.C.D$addr] [detail$detail] [json$uj]", SHOW_STR BGP_STR VNI_HELP_STR VNI_ALL_HELP_STR VTEP_HELP_STR VTEP_IP_HELP_STR - DETAIL_HELP_STR) + DETAIL_HELP_STR + JSON_STR) { struct bgp *bgp; json_object *json = NULL; @@ -5258,21 +5259,17 @@ DEFPY(show_bgp_vni_all, 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; } @@ -5452,23 +5449,43 @@ DEFPY(show_bgp_vni_all_imet, */ DEFPY(show_bgp_vni, show_bgp_vni_cmd, - "show bgp vni "CMD_VNI_RANGE"$vni [vtep A.B.C.D$addr]", + "show bgp vni "CMD_VNI_RANGE"$vni [vtep A.B.C.D$addr] [json$uj]", SHOW_STR BGP_STR VNI_HELP_STR VNI_NUM_HELP_STR VTEP_HELP_STR - VTEP_IP_HELP_STR) + VTEP_IP_HELP_STR + JSON_STR) { struct bgp *bgp; + json_object *json = NULL; + json_object *json_mac = NULL; 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); + /* check if we need json output */ + if (uj) { + json = json_object_new_object(); + json_mac = json_object_new_object(); + } + + evpn_show_routes_vni(vty, bgp, vni, 0, false, addr, json); + + if (!uj) + vty_out(vty, "\n\nMAC Table:\n\n"); + + evpn_show_routes_vni(vty, bgp, vni, 0, true, addr, json_mac); + + if (uj) { + json_object_object_add(json, "macTable", json_mac); + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } From b5118501acea0d571bbc90a077f90a29a3e6a93d Mon Sep 17 00:00:00 2001 From: Trey Aspelund Date: Mon, 11 Jul 2022 18:17:39 -0400 Subject: [PATCH 09/15] bgpd: don't unlock bgp_dest twice Both install_evpn_route_entry_in_vni_mac() and install_evpn_route_entry_in_vni_ip() will unlock the bgp_dest when install_evpn_route_entry_in_vni_common() returns, so there's no need to unlock the bgp_dest inside the _common function. Let's let the new wrappers handle the cleanup of the dest. Ticket: #3119673 Signed-off-by: Trey Aspelund --- bgpd/bgp_evpn.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 6d402a4fef..90e04a042d 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2906,11 +2906,15 @@ static int install_evpn_route_entry_in_vni_common( new_local_es = bgp_evpn_attr_is_local_es(pi->attr); } else { - if (attrhash_cmp(pi->attr, parent_pi->attr) - && !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) { - bgp_dest_unlock_node(dest); + /* Return early if attributes haven't changed + * and dest isn't flagged for removal. + * dest will be unlocked by either + * install_evpn_route_entry_in_vni_mac() or + * install_evpn_route_entry_in_vni_ip() + */ + if (attrhash_cmp(pi->attr, parent_pi->attr) && + !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) return 0; - } /* The attribute has changed. */ /* Add (or update) attribute to hash. */ attr_new = bgp_attr_intern(parent_pi->attr); From 8476d11c49c286c035b3a6ae7c0a777ceeb0dea7 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 7 Oct 2022 15:14:06 -0400 Subject: [PATCH 10/15] doc: add new `show bgp vni ...` command to docs Add new `show bgp vni ...` command to docs. This command is used to show the per-VNI EVPN tables in BGP. Signed-off-by: Stephen Worley --- doc/user/bgp.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index f136ea4ae1..da3718fce2 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -3750,6 +3750,10 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`. EVPN prefixes can also be filtered by EVPN route type. +.. clicmd:: show bgp vni [vtep VTEP] [type ] [] + + Display per-VNI EVPN routing table in bgp. Filter route-type, vtep, or VNI. + .. clicmd:: show bgp [afi] [safi] [all] summary [json] Show a bgp peer summary for the specified address family, and subsequent From 100290e449093bd90a085e918caa3a11637a79d3 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Fri, 7 Oct 2022 17:04:39 -0400 Subject: [PATCH 11/15] bgpd: fix vni table output broken by 8304dabfab906 Fix vni table output broken by 8304dabfab9063fe5720e8e714476ed2e9127540 The "Imported from" output was not getting delimitted by a newline after the mentioned commit. This fixes that and retains the output wanted by the original change. Before: ''' Route [2]:[0]:[48]:[b6:3a:cc:d5:a1:cd]:[128]:[fe80::b43a:ccff:fed5:a1cd] VNI 30/10 Imported from 2.2.2.2:4:[2]:[0]:[48]:[b6:3a:cc:d5:a1:cd]:[128]:[fe80::b43a:ccff:fed5:a1cd], VNI 30/10 2 2.2.2.2(alfred) from alfred(veth1) (2.2.2.2) Origin IGP, valid, external, bestpath-from-AS 2, best (First path received) Extended Community: RT:2:30 ET:8 Last update: Fri Oct 7 16:04:59 2022 ''' After: ''' Route [2]:[0]:[48]:[b2:cf:96:70:4f:b6]:[128]:[fe80::b0cf:96ff:fe70:4fb6] VNI 30/10 Imported from 2.2.2.2:4:[2]:[0]:[48]:[b2:cf:96:70:4f:b6]:[128]:[fe80::b0cf:96ff:fe70:4fb6], VNI 30/10 2 2.2.2.2(alfred) from alfred(veth1) (2.2.2.2) Origin IGP, valid, external, bestpath-from-AS 2, best (First path received) Extended Community: RT:2:30 ET:8 Last update: Fri Oct 7 17:02:28 2022 ''' Signed-off-by: Stephen Worley --- bgpd/bgp_route.c | 77 ++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 7ec2484572..839d3fb1e4 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10010,6 +10010,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, { char buf[INET6_ADDRSTRLEN]; char buf1[BUFSIZ]; + char tag_buf[30]; struct attr *attr = path->attr; time_t tbuf; json_object *json_bestpath = NULL; @@ -10040,6 +10041,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, uint32_t bos = 0; uint32_t exp = 0; mpls_label_t label = MPLS_INVALID_LABEL; + tag_buf[0] = '\0'; if (json_paths) { json_path = json_object_new_object(); @@ -10053,9 +10055,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } if (path->extra) { - char tag_buf[30]; - - tag_buf[0] = '\0'; if (path->extra && path->extra->num_labels) { bgp_evpn_label2str(path->extra->label, path->extra->num_labels, tag_buf, @@ -10074,44 +10073,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } } } - - if (path->extra && path->extra->parent && !json_paths) { - struct bgp_path_info *parent_ri; - struct bgp_dest *dest, *pdest; - - parent_ri = (struct bgp_path_info *)path->extra->parent; - dest = parent_ri->net; - if (dest && dest->pdest) { - pdest = dest->pdest; - if (is_pi_family_evpn(parent_ri)) { - vty_out(vty, - " Imported from %pRD:%pFX, VNI %s", - (struct prefix_rd *) - bgp_dest_get_prefix( - pdest), - (struct prefix_evpn *) - bgp_dest_get_prefix( - dest), - tag_buf); - if (attr->es_flags & ATTR_ES_L3_NHG) - vty_out(vty, ", L3NHG %s", - (attr->es_flags - & ATTR_ES_L3_NHG_ACTIVE) - ? "active" - : "inactive"); - vty_out(vty, "\n"); - - } else - vty_out(vty, - " Imported from %pRD:%pFX\n", - (struct prefix_rd *) - bgp_dest_get_prefix( - pdest), - (struct prefix_evpn *) - bgp_dest_get_prefix( - dest)); - } - } } if (safi == SAFI_EVPN @@ -10131,6 +10092,40 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, if (safi == SAFI_EVPN && !json_path) vty_out(vty, "\n"); + + if (path->extra && path->extra->parent && !json_paths) { + struct bgp_path_info *parent_ri; + struct bgp_dest *dest, *pdest; + + parent_ri = (struct bgp_path_info *)path->extra->parent; + dest = parent_ri->net; + if (dest && dest->pdest) { + pdest = dest->pdest; + if (is_pi_family_evpn(parent_ri)) { + vty_out(vty, + " Imported from %pRD:%pFX, VNI %s", + (struct prefix_rd *)bgp_dest_get_prefix( + pdest), + (struct prefix_evpn *) + bgp_dest_get_prefix(dest), + tag_buf); + if (attr->es_flags & ATTR_ES_L3_NHG) + vty_out(vty, ", L3NHG %s", + (attr->es_flags & + ATTR_ES_L3_NHG_ACTIVE) + ? "active" + : "inactive"); + vty_out(vty, "\n"); + + } else + vty_out(vty, " Imported from %pRD:%pFX\n", + (struct prefix_rd *)bgp_dest_get_prefix( + pdest), + (struct prefix_evpn *) + bgp_dest_get_prefix(dest)); + } + } + /* Line1 display AS-path, Aggregator */ if (attr->aspath) { if (json_paths) { From da823882a5fb2295efdfed3154fa6130e3227e58 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 1 Nov 2022 14:09:15 -0400 Subject: [PATCH 12/15] zebra: use "get" naming for bgp accept lower knob Use "get" as the name for checking the status of the bgp accept lower seq knob. This already has an equivalent "set" so makes sense to keep it consistent. Signed-off-by: Stephen Worley --- zebra/zebra_evpn_mac.c | 2 +- zebra/zebra_evpn_neigh.c | 2 +- zebra/zebra_vty.c | 2 +- zebra/zebra_vxlan.c | 2 +- zebra/zebra_vxlan.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index f0d256e28a..218184ad0d 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -1642,7 +1642,7 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, /* if the mac was never advertised to bgp we must accept * whatever sequence number bgp sends */ - if (!is_local && zebra_vxlan_accept_bgp_seq()) { + if (!is_local && zebra_vxlan_get_accept_bgp_seq()) { if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) { zlog_debug( diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 5044d2f6c2..684720bb4d 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -527,7 +527,7 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(struct zebra_evpn *zevpn, /* if the neigh was never advertised to bgp we must accept * whatever sequence number bgp sends */ - if (!is_local && zebra_vxlan_accept_bgp_seq()) { + if (!is_local && zebra_vxlan_get_accept_bgp_seq()) { if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH || IS_ZEBRA_DEBUG_VXLAN) zlog_debug( diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index a95e07d952..77922d2fc4 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -3966,7 +3966,7 @@ static int config_write_protocol(struct vty *vty) zebra_pbr_config_write(vty); - if (!zebra_vxlan_accept_bgp_seq()) + if (!zebra_vxlan_get_accept_bgp_seq()) vty_out(vty, "no evpn accept-bgp-seq\n"); /* Include nexthop-group config */ diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 6954c63af0..f1c7debe11 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -6293,7 +6293,7 @@ void zebra_vxlan_set_accept_bgp_seq(bool set) accept_bgp_seq = set; } -bool zebra_vxlan_accept_bgp_seq(void) +bool zebra_vxlan_get_accept_bgp_seq(void) { return accept_bgp_seq; } diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 1d777e39f8..121e5633d6 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -226,7 +226,7 @@ extern int zebra_vxlan_dp_network_mac_del(struct interface *ifp, vlanid_t vid); extern void zebra_vxlan_set_accept_bgp_seq(bool set); -extern bool zebra_vxlan_accept_bgp_seq(void); +extern bool zebra_vxlan_get_accept_bgp_seq(void); #ifdef __cplusplus } From 6012963ecd82a4abb63e5c4396af9af8d69b81a9 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 1 Nov 2022 14:26:54 -0400 Subject: [PATCH 13/15] bgpd: use CHECK_FLAG for es_flags in route detail Use CHECK_FLAG for es_flags in vtysh output for route detail. Signed-off-by: Stephen Worley --- bgpd/bgp_route.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 839d3fb1e4..61976834f4 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10109,10 +10109,11 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, (struct prefix_evpn *) bgp_dest_get_prefix(dest), tag_buf); - if (attr->es_flags & ATTR_ES_L3_NHG) + if (CHECK_FLAG(attr->es_flags, ATTR_ES_L3_NHG)) vty_out(vty, ", L3NHG %s", - (attr->es_flags & - ATTR_ES_L3_NHG_ACTIVE) + CHECK_FLAG( + attr->es_flags, + ATTR_ES_L3_NHG_ACTIVE) ? "active" : "inactive"); vty_out(vty, "\n"); From 339af96e386b3e126208ec7873d7e3ea65724c78 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 1 Nov 2022 14:33:36 -0400 Subject: [PATCH 14/15] bgpd: vni_t is uint32_t so print it as such in vty vni_t is a uint32_t so print is as such in vty output. Signed-off-by: Stephen Worley --- bgpd/bgp_evpn_vty.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 5d16b55d57..435bce17ca 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -519,7 +519,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json) json, "sviInterface", ifindex2ifname(vpn->svi_ifindex, vpn->tenant_vrf_id)); } else { - vty_out(vty, "VNI: %d", vpn->vni); + vty_out(vty, "VNI: %u", vpn->vni); if (is_vni_live(vpn)) vty_out(vty, " (known to the kernel)"); vty_out(vty, "\n"); @@ -923,12 +923,12 @@ static void show_vni_routes_hash(struct hash_bucket *bucket, void *arg) json_object *json_vni = NULL; char vni_str[VNI_STR_LEN]; - snprintf(vni_str, sizeof(vni_str), "%d", vpn->vni); + snprintf(vni_str, sizeof(vni_str), "%u", 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); + vty_out(vty, "\nVNI: %u\n\n", vpn->vni); } show_vni_routes(wctx->bgp, vpn, wctx->vty, wctx->type, wctx->mac_table, @@ -948,12 +948,12 @@ static void show_vni_routes_all_hash(struct hash_bucket *bucket, void *arg) json_object *json_vni_mac = NULL; char vni_str[VNI_STR_LEN]; - snprintf(vni_str, sizeof(vni_str), "%d", vpn->vni); + snprintf(vni_str, sizeof(vni_str), "%u", 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); + vty_out(vty, "\nVNI: %u\n\n", vpn->vni); } show_vni_routes(wctx->bgp, vpn, wctx->vty, 0, false, wctx->vtep_ip, @@ -965,7 +965,7 @@ static void show_vni_routes_all_hash(struct hash_bucket *bucket, void *arg) if (json) json_vni_mac = json_object_new_object(); else - vty_out(vty, "\nVNI: %d MAC Table\n\n", vpn->vni); + vty_out(vty, "\nVNI: %u MAC Table\n\n", vpn->vni); show_vni_routes(wctx->bgp, vpn, wctx->vty, 0, true, wctx->vtep_ip, json_vni_mac, wctx->detail); @@ -3456,7 +3456,7 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn) struct ecommunity *ecom; if (is_vni_configured(vpn)) { - vty_out(vty, " vni %d\n", vpn->vni); + vty_out(vty, " vni %u\n", vpn->vni); if (is_rd_configured(vpn)) vty_out(vty, " rd %pRD\n", &vpn->prd); From d950d2246db240816162bbade29f4fb6cea14988 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 1 Nov 2022 14:46:51 -0400 Subject: [PATCH 15/15] bgpd: use vty_json() in show bpg vni json output Use vty_json() in show bgp vni json output. Signed-off-by: Stephen Worley --- bgpd/bgp_evpn_vty.c | 93 +++++++++++---------------------------------- 1 file changed, 23 insertions(+), 70 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 435bce17ca..12fe65c72b 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -5264,12 +5264,8 @@ DEFPY(show_bgp_vni_all, 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); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5306,12 +5302,8 @@ DEFPY(show_bgp_vni_all_ead, 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); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5349,12 +5341,8 @@ DEFPY(show_bgp_vni_all_macip_mac, 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); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5392,12 +5380,8 @@ DEFPY(show_bgp_vni_all_macip_ip, 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); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5434,12 +5418,8 @@ DEFPY(show_bgp_vni_all_imet, 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); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5481,10 +5461,7 @@ DEFPY(show_bgp_vni, if (uj) { json_object_object_add(json, "macTable", json_mac); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } return CMD_SUCCESS; @@ -5521,12 +5498,8 @@ DEFPY(show_bgp_vni_ead, 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); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5563,12 +5536,8 @@ DEFPY(show_bgp_vni_macip_mac, 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); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5605,12 +5574,8 @@ DEFPY(show_bgp_vni_macip_ip, 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); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5646,12 +5611,8 @@ DEFPY(show_bgp_vni_imet, 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); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5686,12 +5647,8 @@ DEFPY(show_bgp_vni_macip_mac_addr, 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); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5728,12 +5685,8 @@ DEFPY(show_bgp_vni_macip_ip_addr, show_bgp_vni_macip_ip_addr_cmd, } 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); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; }