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);