]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/zebra_nhg.c
Merge pull request #12780 from opensourcerouting/spdx-license-id
[mirror_frr.git] / zebra / zebra_nhg.c
index 5e0d3ed4fd6e3c92bd1fd07343a6bb8b00504be0..654cf50d49c267ff3c914a5878beeb77a89bb7f4 100644 (file)
@@ -28,6 +28,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");
@@ -1906,10 +1907,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,
@@ -2179,6 +2212,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)
@@ -2690,6 +2729,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.
@@ -2705,12 +2789,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) {
 
@@ -2748,16 +2836,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);
        }