diff options
Diffstat (limited to 'zebra/zebra_nhg.c')
| -rw-r--r-- | zebra/zebra_nhg.c | 117 |
1 files changed, 103 insertions, 14 deletions
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 0bca00ced3..d321ab4949 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,51 @@ 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) { + if (!nexthop->nh_label || + nexthop->nh_label_type != ZEBRA_LSP_EVPN) + continue; + + 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 +2805,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) { @@ -2764,16 +2852,17 @@ static uint32_t nexthop_list_active_update(struct route_node *rn, counter++; /* Check for changes to the nexthop - set ROUTE_ENTRY_CHANGED */ - if (prev_active != new_active || prev_index != nexthop->ifindex - || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX - && nexthop->type < NEXTHOP_TYPE_IPV6) - && prev_src.ipv4.s_addr - != nexthop->rmap_src.ipv4.s_addr) - || ((nexthop->type >= NEXTHOP_TYPE_IPV6 - && nexthop->type < NEXTHOP_TYPE_BLACKHOLE) - && !(IPV6_ADDR_SAME(&prev_src.ipv6, - &nexthop->rmap_src.ipv6))) - || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) + if (prev_active != new_active || + prev_index != nexthop->ifindex || + ((nexthop->type >= NEXTHOP_TYPE_IFINDEX && + nexthop->type < NEXTHOP_TYPE_IPV6) && + prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr) || + ((nexthop->type >= NEXTHOP_TYPE_IPV6 && + nexthop->type < NEXTHOP_TYPE_BLACKHOLE) && + !(IPV6_ADDR_SAME(&prev_src.ipv6, + &nexthop->rmap_src.ipv6))) || + CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED) || + vni_removed) SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); } |
