fib: Table Replace
[vpp.git] / src / vnet / mfib / mfib_entry.c
index ac37665..448e6c5 100644 (file)
@@ -38,6 +38,7 @@ static mfib_path_ext_t *mfib_path_ext_pool;
  * String names for each source
  */
 static const char *mfib_source_names[] = MFIB_SOURCE_NAMES;
+static const char *mfib_src_attribute_names[] = MFIB_ENTRY_SRC_ATTRIBUTES;
 
 /*
  * Pool for all fib_entries
@@ -101,6 +102,26 @@ format_mfib_entry_path_ext (u8 * s, va_list * args)
                    format_mfib_itf_flags, path_ext->mfpe_flags));
 }
 
+u8 *
+format_mfib_entry_src_flags (u8 *s, va_list *args)
+{
+    mfib_entry_src_attribute_t sattr;
+    mfib_entry_src_flags_t flag = va_arg(*args, int);
+
+    if (!flag)
+    {
+        return format(s, "none");
+    }
+
+    FOR_EACH_MFIB_SRC_ATTRIBUTE(sattr) {
+        if ((1 << sattr) & flag) {
+            s = format (s, "%s,", mfib_src_attribute_names[sattr]);
+        }
+    }
+
+    return (s);
+}
+
 u8 *
 format_mfib_entry (u8 * s, va_list * args)
 {
@@ -127,14 +148,15 @@ format_mfib_entry (u8 * s, va_list * args)
         s = format (s, " locks:%d\n", mfib_entry->mfe_node.fn_locks);
         vec_foreach(msrc, mfib_entry->mfe_srcs)
         {
-            s = format (s, "  src:%s locks:%d:",
+            s = format (s, "  src:%s flags:%U locks:%d:",
                         mfib_source_names[msrc->mfes_src],
+                        format_mfib_entry_src_flags, msrc->mfes_flags,
                         msrc->mfes_ref_count);
             if (msrc->mfes_cover != FIB_NODE_INDEX_INVALID)
             {
                 s = format (s, " cover:%d", msrc->mfes_cover);
             }
-            s = format (s, " %U\n", format_mfib_entry_flags, msrc->mfes_flags);
+            s = format (s, " %U\n", format_mfib_entry_flags, msrc->mfes_route_flags);
             if (FIB_NODE_INDEX_INVALID != msrc->mfes_pl)
             {
                 s = fib_path_list_format(msrc->mfes_pl, s);
@@ -201,7 +223,7 @@ mfib_entry_src_init (mfib_entry_t *mfib_entry,
 {
     mfib_entry_src_t esrc = {
         .mfes_pl = FIB_NODE_INDEX_INVALID,
-        .mfes_flags = MFIB_ENTRY_FLAG_NONE,
+        .mfes_route_flags = MFIB_ENTRY_FLAG_NONE,
         .mfes_src = source,
         .mfes_cover = FIB_NODE_INDEX_INVALID,
         .mfes_sibling = FIB_NODE_INDEX_INVALID,
@@ -215,8 +237,8 @@ mfib_entry_src_init (mfib_entry_t *mfib_entry,
 
 static mfib_entry_src_t *
 mfib_entry_src_find (const mfib_entry_t *mfib_entry,
-                    mfib_source_t source,
-                    u32 *index)
+                     mfib_source_t source,
+                     u32 *index)
 
 {
     mfib_entry_src_t *esrc;
@@ -269,8 +291,9 @@ mfib_entry_src_update (mfib_entry_t *mfib_entry,
 
     msrc = mfib_entry_src_find_or_create(mfib_entry, source);
 
-    msrc->mfes_flags = entry_flags;
+    msrc->mfes_route_flags = entry_flags;
     msrc->mfes_rpf_id = rpf_id;
+    msrc->mfes_flags &= ~MFIB_ENTRY_SRC_FLAG_STALE;
 
     return (msrc);
 }
@@ -286,6 +309,7 @@ mfib_entry_src_update_and_lock (mfib_entry_t *mfib_entry,
     msrc = mfib_entry_src_update(mfib_entry, source, rpf_id, entry_flags);
 
     msrc->mfes_ref_count++;
+    msrc->mfes_flags &= ~MFIB_ENTRY_SRC_FLAG_STALE;
 
     return (msrc);
 }
@@ -331,6 +355,44 @@ mfib_entry_is_sourced (fib_node_index_t mfib_entry_index,
     return (NULL != mfib_entry_src_find(mfib_entry, source, NULL));
 }
 
+int
+mfib_entry_is_marked (fib_node_index_t mfib_entry_index,
+                      mfib_source_t source)
+{
+    mfib_entry_t *mfib_entry;
+    mfib_entry_src_t *esrc;
+
+    mfib_entry = mfib_entry_get(mfib_entry_index);
+
+    esrc = mfib_entry_src_find(mfib_entry, source, NULL);
+
+    if (NULL == esrc)
+    {
+        return (0);
+    }
+    else
+    {
+        return (!!(esrc->mfes_flags & MFIB_ENTRY_SRC_FLAG_STALE));
+    }
+}
+
+void
+mfib_entry_mark (fib_node_index_t fib_entry_index,
+                 mfib_source_t source)
+{
+    mfib_entry_t *mfib_entry;
+    mfib_entry_src_t *esrc;
+
+    mfib_entry = mfib_entry_get(fib_entry_index);
+
+    esrc = mfib_entry_src_find(mfib_entry, source, NULL);
+
+    if (NULL != esrc)
+    {
+        esrc->mfes_flags |= MFIB_ENTRY_SRC_FLAG_STALE;
+    }
+}
+
 int
 mfib_entry_is_host (fib_node_index_t mfib_entry_index)
 {
@@ -578,7 +640,7 @@ mfib_entry_stack (mfib_entry_t *mfib_entry,
          * updates to recalculate forwarding.
          */
         mfib_entry->mfe_pl = msrc->mfes_pl;
-        mfib_entry->mfe_flags = msrc->mfes_flags;
+        mfib_entry->mfe_flags = msrc->mfes_route_flags;
         mfib_entry->mfe_itfs = msrc->mfes_itfs;
         mfib_entry->mfe_rpf_id = msrc->mfes_rpf_id;
 
@@ -633,16 +695,25 @@ mfib_entry_stack (mfib_entry_t *mfib_entry,
         {
             /*
              * for exclusive routes the source provided a replicate DPO
-             * we we stashed inthe special path list with one path
+             * which we stashed in the special path list with one path,
              * so we can stack directly on that.
              */
             ASSERT(1 == vec_len(ctx.next_hops));
 
-            dpo_stack(DPO_MFIB_ENTRY, dp,
-                      &mfib_entry->mfe_rep,
-                      &ctx.next_hops[0].path_dpo);
-            dpo_reset(&ctx.next_hops[0].path_dpo);
-            vec_free(ctx.next_hops);
+            if (NULL != ctx.next_hops)
+            {
+                dpo_stack(DPO_MFIB_ENTRY, dp,
+                          &mfib_entry->mfe_rep,
+                          &ctx.next_hops[0].path_dpo);
+                dpo_reset(&ctx.next_hops[0].path_dpo);
+                vec_free(ctx.next_hops);
+            }
+            else
+            {
+                dpo_stack(DPO_MFIB_ENTRY, dp,
+                          &mfib_entry->mfe_rep,
+                          drop_dpo_get(dp));
+            }
         }
     }
     else
@@ -664,20 +735,13 @@ mfib_entry_stack (mfib_entry_t *mfib_entry,
                   &bw_ctx);
 }
 
-static fib_node_index_t
-mfib_entry_src_path_add (mfib_entry_src_t *msrc,
-                         const fib_route_path_t *rpath)
+static fib_node_index_t*
+mfib_entry_src_paths_add (mfib_entry_src_t *msrc,
+                          const fib_route_path_t *rpaths)
 {
-    fib_node_index_t path_index;
-    fib_route_path_t *rpaths;
-
-    ASSERT(!(MFIB_ENTRY_FLAG_EXCLUSIVE & msrc->mfes_flags));
+    ASSERT(!(MFIB_ENTRY_FLAG_EXCLUSIVE & msrc->mfes_route_flags));
 
-    /*
-     * path-lists require a vector of paths
-     */
-    rpaths = NULL;
-    vec_add1(rpaths, rpath[0]);
+    msrc->mfes_flags &= ~MFIB_ENTRY_SRC_FLAG_STALE;
 
     if (FIB_NODE_INDEX_INVALID == msrc->mfes_pl)
     {
@@ -687,33 +751,18 @@ mfib_entry_src_path_add (mfib_entry_src_t *msrc,
         fib_path_list_lock(msrc->mfes_pl);
     }
 
-    path_index = fib_path_list_path_add(msrc->mfes_pl, rpaths);
-
-    vec_free(rpaths);
-
-    return (path_index);
+    return (fib_path_list_paths_add(msrc->mfes_pl, rpaths));
 }
 
-static fib_node_index_t
-mfib_entry_src_path_remove (mfib_entry_src_t *msrc,
-                            const fib_route_path_t *rpath)
+static fib_node_index_t*
+mfib_entry_src_paths_remove (mfib_entry_src_t *msrc,
+                             const fib_route_path_t *rpaths)
 {
-    fib_node_index_t path_index;
-    fib_route_path_t *rpaths;
+    ASSERT(!(MFIB_ENTRY_FLAG_EXCLUSIVE & msrc->mfes_route_flags));
 
-    ASSERT(!(MFIB_ENTRY_FLAG_EXCLUSIVE & msrc->mfes_flags));
+    msrc->mfes_flags &= ~MFIB_ENTRY_SRC_FLAG_STALE;
 
-    /*
-     * path-lists require a vector of paths
-     */
-    rpaths = NULL;
-    vec_add1(rpaths, rpath[0]);
-
-    path_index = fib_path_list_path_remove(msrc->mfes_pl, rpaths);
-
-    vec_free(rpaths);
-
-    return (path_index);
+    return (fib_path_list_paths_remove(msrc->mfes_pl, rpaths));
 }
 
 static void
@@ -809,8 +858,13 @@ static int
 mfib_entry_src_ok_for_delete (const mfib_entry_src_t *msrc)
 {
     return ((INDEX_INVALID == msrc->mfes_cover &&
-             MFIB_ENTRY_FLAG_NONE == msrc->mfes_flags &&
-             0 == fib_path_list_get_n_paths(msrc->mfes_pl)));
+             MFIB_ENTRY_FLAG_NONE == msrc->mfes_route_flags &&
+             0 == fib_path_list_get_n_paths(msrc->mfes_pl)) &&
+            (0 == hash_elts(msrc->mfes_itfs)));
+
+    /* return ((MFIB_ENTRY_FLAG_NONE == msrc->mfes_route_flags) && */
+    /*         (0 == fib_path_list_get_n_paths(msrc->mfes_pl)) && */
+    /*         (0 == hash_elts(msrc->mfes_itfs))); */
 }
 
 
@@ -922,18 +976,26 @@ mfib_entry_itf_remove (mfib_entry_src_t *msrc,
     hash_unset(msrc->mfes_itfs, sw_if_index);
 }
 
+static int
+mfib_entry_path_itf_based (const fib_route_path_t *rpath)
+{
+    return (!(rpath->frp_flags & FIB_ROUTE_PATH_BIER_IMP) &&
+            ~0 != rpath->frp_sw_if_index);
+}
+
 void
 mfib_entry_path_update (fib_node_index_t mfib_entry_index,
                         mfib_source_t source,
-                        const fib_route_path_t *rpath,
-                        mfib_itf_flags_t itf_flags)
+                        const fib_route_path_t *rpaths)
 {
-    fib_node_index_t path_index;
+    fib_node_index_t* path_indices, path_index;
+    const fib_route_path_t *rpath;
     mfib_source_t current_best;
     mfib_path_ext_t *path_ext;
     mfib_entry_t *mfib_entry;
     mfib_entry_src_t *msrc;
     mfib_itf_flags_t old;
+    u32 ii;
 
     mfib_entry = mfib_entry_get(mfib_entry_index);
     ASSERT(NULL != mfib_entry);
@@ -944,61 +1006,73 @@ mfib_entry_path_update (fib_node_index_t mfib_entry_index,
      * add the path to the path-list. If it's a duplicate we'll get
      * back the original path.
      */
-    path_index = mfib_entry_src_path_add(msrc, rpath);
-
-    /*
-     * find the path extension for that path
-     */
-    path_ext = mfib_entry_path_ext_find(msrc->mfes_exts, path_index);
+    path_indices = mfib_entry_src_paths_add(msrc, rpaths);
 
-    if (NULL == path_ext)
+    vec_foreach_index(ii, path_indices)
     {
-        old = MFIB_ITF_FLAG_NONE;
-        path_ext = mfib_path_ext_add(msrc, path_index, itf_flags);
-    }
-    else
-    {
-        old = path_ext->mfpe_flags;
-        path_ext->mfpe_flags = itf_flags;
-    }
+        path_index = path_indices[ii];
+        rpath = &rpaths[ii];
 
-    /*
-     * Has the path changed its contribution to the input interface set.
-     * Which only paths with interfaces can do...
-     */
-    if (~0 != rpath[0].frp_sw_if_index)
-    {
-        mfib_itf_t *mfib_itf;
+        if (FIB_NODE_INDEX_INVALID == path_index)
+            continue;
 
-        if (old != itf_flags)
+        /*
+         * find the path extension for that path
+         */
+        path_ext = mfib_entry_path_ext_find(msrc->mfes_exts, path_index);
+
+        if (NULL == path_ext)
         {
-            /*
-             * change of flag contributions
-             */
-            mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
-                                           rpath[0].frp_sw_if_index);
+            old = MFIB_ITF_FLAG_NONE;
+            path_ext = mfib_path_ext_add(msrc, path_index,
+                                         rpath->frp_mitf_flags);
+        }
+        else
+        {
+            old = path_ext->mfpe_flags;
+            path_ext->mfpe_flags = rpath->frp_mitf_flags;
+        }
 
-            if (NULL == mfib_itf)
-            {
-                mfib_entry_itf_add(msrc,
-                                   rpath[0].frp_sw_if_index,
-                                   mfib_itf_create(path_index, itf_flags));
-            }
-            else
+        /*
+         * Has the path changed its contribution to the input interface set.
+         * Which only paths with interfaces can do...
+         */
+        if (mfib_entry_path_itf_based(rpath))
+        {
+            mfib_itf_t *mfib_itf;
+
+            if (old != rpath->frp_mitf_flags)
             {
-                if (mfib_itf_update(mfib_itf,
-                                    path_index,
-                                    itf_flags))
+                /*
+                 * change of flag contributions
+                 */
+                mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
+                                               rpath->frp_sw_if_index);
+
+                if (NULL == mfib_itf)
+                {
+                    mfib_entry_itf_add(msrc,
+                                       rpath->frp_sw_if_index,
+                                       mfib_itf_create(path_index,
+                                                       rpath->frp_mitf_flags));
+                }
+                else
                 {
-                    /*
-                     * no more interface flags on this path, remove
-                     * from the data-plane set
-                     */
-                    mfib_entry_itf_remove(msrc, rpath[0].frp_sw_if_index);
+                    if (mfib_itf_update(mfib_itf,
+                                        path_index,
+                                        rpath->frp_mitf_flags))
+                    {
+                        /*
+                         * no more interface flags on this path, remove
+                         * from the data-plane set
+                         */
+                        mfib_entry_itf_remove(msrc, rpath->frp_sw_if_index);
+                    }
                 }
             }
         }
     }
+    vec_free(path_indices);
 
     mfib_entry_recalculate_forwarding(mfib_entry, current_best);
 }
@@ -1012,12 +1086,14 @@ mfib_entry_path_update (fib_node_index_t mfib_entry_index,
 int
 mfib_entry_path_remove (fib_node_index_t mfib_entry_index,
                         mfib_source_t source,
-                        const fib_route_path_t *rpath)
+                        const fib_route_path_t *rpaths)
 {
-    fib_node_index_t path_index;
+    fib_node_index_t path_index, *path_indices;
+    const fib_route_path_t *rpath;
     mfib_source_t current_best;
     mfib_entry_t *mfib_entry;
     mfib_entry_src_t *msrc;
+    u32 ii;
 
     mfib_entry = mfib_entry_get(mfib_entry_index);
     ASSERT(NULL != mfib_entry);
@@ -1033,23 +1109,29 @@ mfib_entry_path_remove (fib_node_index_t mfib_entry_index,
     }
 
     /*
-     * remove the path from the path-list. If it's not there we'll get
-     * back invalid
+     * remove the paths from the path-list. If it's not there we'll get
+     * back an empty vector
      */
-    path_index = mfib_entry_src_path_remove(msrc, rpath);
+    path_indices = mfib_entry_src_paths_remove(msrc, rpaths);
 
-    if (FIB_NODE_INDEX_INVALID != path_index)
+    vec_foreach_index(ii, path_indices)
     {
+        path_index = path_indices[ii];
+        rpath = &rpaths[ii];
+
+        if (FIB_NODE_INDEX_INVALID == path_index)
+            continue;
+      
         /*
          * don't need the extension, nor the interface anymore
          */
         mfib_path_ext_remove(msrc, path_index);
-        if (~0 != rpath[0].frp_sw_if_index)
+        if (mfib_entry_path_itf_based(rpath))
         {
             mfib_itf_t *mfib_itf;
 
             mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
-                                           rpath[0].frp_sw_if_index);
+                                           rpath->frp_sw_if_index);
 
             if (mfib_itf_update(mfib_itf,
                                 path_index,
@@ -1059,19 +1141,20 @@ mfib_entry_path_remove (fib_node_index_t mfib_entry_index,
                  * no more interface flags on this path, remove
                  * from the data-plane set
                  */
-                mfib_entry_itf_remove(msrc, rpath[0].frp_sw_if_index);
+                mfib_entry_itf_remove(msrc, rpath->frp_sw_if_index);
             }
         }
-    }
 
-    if (mfib_entry_src_ok_for_delete(msrc))
-    {
-        /*
-         * this source has no interfaces and no flags.
-         * it has nothing left to give - remove it
-         */
-        mfib_entry_src_remove(mfib_entry, source);
+        if (mfib_entry_src_ok_for_delete(msrc))
+        {
+            /*
+             * this source has no interfaces and no flags.
+             * it has nothing left to give - remove it
+             */
+            mfib_entry_src_remove(mfib_entry, source);
+        }
     }
+    vec_free(path_indices);
 
     mfib_entry_recalculate_forwarding(mfib_entry, current_best);
 
@@ -1312,11 +1395,14 @@ mfib_entry_module_init (void)
     mfib_entry_logger = vlib_log_register_class("mfib", "entry");
 }
 
-void
-mfib_entry_encode (fib_node_index_t mfib_entry_index,
-                  fib_route_path_encode_t **api_rpaths)
+fib_route_path_t*
+mfib_entry_encode (fib_node_index_t mfib_entry_index)
 {
+    fib_path_encode_ctx_t ctx = {
+        .rpaths = NULL,
+    };
     mfib_entry_t *mfib_entry;
+    fib_route_path_t *rpath;
     mfib_entry_src_t *bsrc;
 
     mfib_entry = mfib_entry_get(mfib_entry_index);
@@ -1327,8 +1413,22 @@ mfib_entry_encode (fib_node_index_t mfib_entry_index,
         fib_path_list_walk_w_ext(bsrc->mfes_pl,
                                  NULL,
                                  fib_path_encode,
-                                 api_rpaths);
+                                 &ctx);
     }
+
+    vec_foreach(rpath, ctx.rpaths)
+    {
+        mfib_itf_t *mfib_itf;
+
+        mfib_itf = mfib_entry_itf_find(bsrc->mfes_itfs,
+                                       rpath->frp_sw_if_index);
+        if (mfib_itf)
+        {
+            rpath->frp_mitf_flags = mfib_itf->mfi_flags;
+        }
+    }
+
+    return (ctx.rpaths);
 }
 
 const mfib_prefix_t *