diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 0bca00ced3..d0d3c38a22 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -44,6 +44,7 @@ #include "zebra/interface.h" #include "zebra/zapi_msg.h" #include "zebra/rib.h" +#include "zebra/zebra_vxlan.h" DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry"); DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected"); @@ -1922,10 +1923,42 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop, } /* - * When resolving a recursive nexthop, capture backup nexthop(s) also - * so they can be conveyed through the dataplane to the FIB. We'll look - * at the backups in the resolving nh 'nexthop' and its nhe, and copy them - * into the route's resolved nh 'resolved' and its nhe 'nhe'. + * Downstream VNI and Single VXlan device check. + * + * If it has nexthop VNI labels at this point it must be D-VNI allocated + * and all the nexthops have to be on an SVD. + * + * If SVD is not available, mark as inactive. + */ +static bool nexthop_set_evpn_dvni_svd(vrf_id_t re_vrf_id, + struct nexthop *nexthop) +{ + if (!is_vrf_l3vni_svd_backed(re_vrf_id)) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) { + struct vrf *vrf = vrf_lookup_by_id(re_vrf_id); + + zlog_debug( + "nexthop %pNHv D-VNI but route's vrf %s(%u) doesn't use SVD", + nexthop, VRF_LOGNAME(vrf), re_vrf_id); + } + + return false; + } + + nexthop->ifindex = get_l3vni_vxlan_ifindex(re_vrf_id); + nexthop->vrf_id = 0; + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("nexthop %pNHv using SVD", nexthop); + + return true; +} + +/* + * Given a nexthop we need to properly recursively resolve + * the route. As such, do a table lookup to find and match + * if at all possible. Set the nexthop->ifindex and resolved_id + * as appropriate */ static int resolve_backup_nexthops(const struct nexthop *nexthop, const struct nhg_hash_entry *nhe, @@ -2195,6 +2228,12 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, * sure the nexthop's interface is known and is operational. */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) { + /* DVNI/SVD Checks for EVPN routes */ + if (nexthop->nh_label && + nexthop->nh_label_type == ZEBRA_LSP_EVPN && + !nexthop_set_evpn_dvni_svd(vrf_id, nexthop)) + return 0; + ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); if (!ifp) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) @@ -2706,6 +2745,47 @@ done: return valid; } +/* Checks if the first nexthop is EVPN. If not, early return. + * + * This is used to determine if there is a mismatch between l3VNI + * of the route's vrf and the nexthops in use's VNI labels. + * + * If there is a mismatch, we keep the labels as these MUST be DVNI nexthops. + * + * IF there is no mismatch, we remove the labels and handle the routes as + * we have traditionally with evpn. + */ +static bool nexthop_list_set_evpn_dvni(struct route_entry *re, + struct nexthop_group *nhg) +{ + struct nexthop *nexthop; + vni_t re_vrf_vni; + vni_t nh_vni; + bool use_dvni = false; + + nexthop = nhg->nexthop; + + if (!nexthop->nh_label || nexthop->nh_label_type != ZEBRA_LSP_EVPN) + return false; + + re_vrf_vni = get_l3vni_vni(re->vrf_id); + + for (; nexthop; nexthop = nexthop->next) { + nh_vni = label2vni(&nexthop->nh_label->label[0]); + + if (nh_vni != re_vrf_vni) + use_dvni = true; + } + + /* Using traditional way, no VNI encap - remove labels */ + if (!use_dvni) { + for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next) + nexthop_del_labels(nexthop); + } + + return use_dvni; +} + /* * Process a list of nexthops, given an nhe, determining * whether each one is ACTIVE/installable at this time. @@ -2721,12 +2801,16 @@ static uint32_t nexthop_list_active_update(struct route_node *rn, uint32_t counter = 0; struct nexthop *nexthop; struct nexthop_group *nhg = &nhe->nhg; + bool vni_removed = false; nexthop = nhg->nexthop; /* Init recursive nh mtu */ re->nexthop_mtu = 0; + /* Handler for dvni evpn nexthops. Has to be done at nhg level */ + vni_removed = !nexthop_list_set_evpn_dvni(re, nhg); + /* Process nexthops one-by-one */ for ( ; nexthop; nexthop = nexthop->next) { @@ -2773,7 +2857,8 @@ static uint32_t nexthop_list_active_update(struct route_node *rn, && nexthop->type < NEXTHOP_TYPE_BLACKHOLE) && !(IPV6_ADDR_SAME(&prev_src.ipv6, &nexthop->rmap_src.ipv6))) - || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) + || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED) + || vni_removed) SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); }