VXLAN multicast dst (remote) address support
[vpp.git] / vnet / vnet / fib / fib_path_list.c
index 1df7396..4d695d6 100644 (file)
@@ -23,6 +23,7 @@
 #include <vnet/fib/fib_internal.h>
 #include <vnet/fib/fib_node_list.h>
 #include <vnet/fib/fib_walk.h>
+#include <vnet/fib/fib_urpf_list.h>
 
 /**
  * FIB path-list
@@ -47,10 +48,15 @@ typedef struct fib_path_list_t_ {
     fib_protocol_t fpl_nh_proto;
 
     /**
-     * Vector of paths indecies for all configured paths.
+     * Vector of paths indicies for all configured paths.
      * For shareable path-lists this list MUST not change.
      */
     fib_node_index_t *fpl_paths;
+
+    /**
+     * the RPF list calculated for this path list
+     */
+    fib_node_index_t fpl_urpf;
 } fib_path_list_t;
 
 /*
@@ -138,6 +144,8 @@ format_fib_path_list (u8 * s, va_list * args)
            }
        }
     }
+    s = format (s, " %U\n", format_fib_urpf_list, path_list->fpl_urpf);
+
     vec_foreach (path_index, path_list->fpl_paths)
     {
        s = fib_path_format(*path_index, s);
@@ -321,9 +329,10 @@ fib_path_list_destroy (fib_path_list_t *path_list)
     vec_foreach (path_index, path_list->fpl_paths)
     {
        fib_path_destroy(*path_index);
-    }    
+    }
 
     vec_free(path_list->fpl_paths);
+    fib_urpf_list_unlock(path_list->fpl_urpf);
 
     fib_node_deinit(&path_list->fpl_node);
     pool_put(fib_path_list_pool, path_list);
@@ -353,7 +362,7 @@ fib_path_list_last_lock_gone (fib_node_t *node)
  */
 static void
 fib_path_list_mk_lb (fib_path_list_t *path_list,
-                    fib_forward_chain_type_t type,
+                    fib_forward_chain_type_t fct,
                     dpo_id_t *dpo)
 {
     load_balance_path_t *hash_key;
@@ -361,6 +370,19 @@ fib_path_list_mk_lb (fib_path_list_t *path_list,
 
     hash_key  = NULL;
 
+    if (!dpo_id_is_valid(dpo))
+    {
+        /*
+         * first time create
+         */
+        dpo_set(dpo,
+                DPO_LOAD_BALANCE,
+                fib_forw_chain_type_to_dpo_proto(fct),
+                load_balance_create(0,
+                                   fib_forw_chain_type_to_dpo_proto(fct),
+                                   0 /* FIXME FLOW HASH */));
+    }
+
     /*
      * We gather the DPOs from resolved paths.
      */
@@ -368,7 +390,7 @@ fib_path_list_mk_lb (fib_path_list_t *path_list,
     {
        hash_key = fib_path_append_nh_for_multipath_hash(
                       *path_index,
-                      type,
+                      fct,
                       hash_key);
     }
 
@@ -383,6 +405,60 @@ fib_path_list_mk_lb (fib_path_list_t *path_list,
     vec_free(hash_key);
 }
 
+/**
+ * @brief [re]build the path list's uRPF list
+ */
+static void
+fib_path_list_mk_urpf (fib_path_list_t *path_list)
+{
+    fib_node_index_t *path_index;
+
+    /*
+     * ditch the old one. by iterating through all paths we are going
+     * to re-find all the adjs that were in the old one anyway. If we
+     * keep the old one, then the |sort|uniq requires more work.
+     * All users of the RPF list have their own lock, so we can release
+     * immediately.
+     */
+    fib_urpf_list_unlock(path_list->fpl_urpf);
+    path_list->fpl_urpf = fib_urpf_list_alloc_and_lock();
+
+    vec_foreach (path_index, path_list->fpl_paths)
+    {
+       fib_path_contribute_urpf(*path_index, path_list->fpl_urpf);
+    }
+
+    fib_urpf_list_bake(path_list->fpl_urpf);
+}
+
+/**
+ * @brief Contribute (add) this path list's uRPF list. This allows the child
+ * to construct an aggregate list.
+ */
+void
+fib_path_list_contribute_urpf (fib_node_index_t path_list_index,
+                              index_t urpf)
+{
+    fib_path_list_t *path_list;
+
+    path_list = fib_path_list_get(path_list_index);
+
+    fib_urpf_list_combine(urpf, path_list->fpl_urpf);
+}
+
+/**
+ * @brief Return the the child the RPF list pre-built for this path list
+ */
+index_t
+fib_path_list_get_urpf (fib_node_index_t path_list_index)
+{
+    fib_path_list_t *path_list;
+
+    path_list = fib_path_list_get(path_list_index);
+
+    return (path_list->fpl_urpf);
+}
+
 /*
  * fib_path_list_back_walk
  *
@@ -397,6 +473,8 @@ fib_path_list_back_walk (fib_node_index_t path_list_index,
 
     path_list = fib_path_list_get(path_list_index);
 
+    fib_path_list_mk_urpf(path_list);
+
     /*
      * propagate the backwalk further
      */
@@ -438,6 +516,19 @@ fib_path_list_back_walk_notify (fib_node_t *node,
     return (FIB_NODE_BACK_WALK_CONTINUE);
 }
 
+/*
+ * Display the path-list memory usage
+ */
+static void
+fib_path_list_memory_show (void)
+{
+    fib_show_memory_usage("Path-list",
+                         pool_elts(fib_path_list_pool),
+                         pool_len(fib_path_list_pool),
+                         sizeof(fib_path_list_t));
+    fib_urpf_list_show_mem();
+}
+
 /*
  * The FIB path-list's graph node virtual function table
  */
@@ -445,6 +536,7 @@ static const fib_node_vft_t fib_path_list_vft = {
     .fnv_get = fib_path_list_get_node,
     .fnv_last_lock = fib_path_list_last_lock_gone,
     .fnv_back_walk = fib_path_list_back_walk_notify,
+    .fnv_mem_show = fib_path_list_memory_show,
 };
 
 static fib_path_list_t *
@@ -457,6 +549,7 @@ fib_path_list_alloc (fib_node_index_t *path_list_index)
 
     fib_node_init(&path_list->fpl_node,
                  FIB_NODE_TYPE_PATH_LIST);
+    path_list->fpl_urpf = INDEX_INVALID;
 
     if (NULL != path_list_index)
     {
@@ -493,6 +586,7 @@ fib_path_list_resolve (fib_path_list_t *path_list)
     path_list = fib_path_list_get(path_list_index);
 
     FIB_PATH_LIST_DBG(path_list, "resovled");
+    fib_path_list_mk_urpf(path_list);
 
     return (path_list);
 }
@@ -668,8 +762,9 @@ fib_path_list_copy_and_path_add (fib_node_index_t orig_path_list_index,
                                 fib_path_list_flags_t flags,
                                 const fib_route_path_t *rpaths)
 {
-    fib_node_index_t path_index, path_list_index, *orig_path_index;
+    fib_node_index_t path_index, new_path_index, *orig_path_index;
     fib_path_list_t *path_list, *orig_path_list;
+    fib_node_index_t path_list_index;
     fib_node_index_t pi;
 
     ASSERT(1 == vec_len(rpaths));
@@ -690,16 +785,30 @@ fib_path_list_copy_and_path_add (fib_node_index_t orig_path_list_index,
     vec_validate(path_list->fpl_paths, vec_len(orig_path_list->fpl_paths));
     pi = 0;
 
+    new_path_index = fib_path_create(path_list_index,
+                                     path_list->fpl_nh_proto,
+                                     fib_path_list_flags_2_path_flags(flags),
+                                     rpaths);
+
     vec_foreach (orig_path_index, orig_path_list->fpl_paths)
     {
-       path_index = fib_path_copy(*orig_path_index, path_list_index);
-       path_list->fpl_paths[pi++] = path_index;
+        /*
+         * don't add duplicate paths
+         * In the unlikely event the path is a duplicate, then we'll
+         * find a matching path-list later and this one will be toast.
+         */
+       if (0 != fib_path_cmp(new_path_index, *orig_path_index))
+        {
+            path_index = fib_path_copy(*orig_path_index, path_list_index);
+            path_list->fpl_paths[pi++] = path_index;
+        }
+        else
+        {
+            _vec_len(path_list->fpl_paths) = vec_len(orig_path_list->fpl_paths);
+        }
     }
-    path_index = fib_path_create(path_list_index,
-                                path_list->fpl_nh_proto,
-                                fib_path_list_flags_2_path_flags(flags),
-                                rpaths);
-    path_list->fpl_paths[pi] = path_index;
+
+    path_list->fpl_paths[pi] = new_path_index;
 
     /*
      * we sort the paths since the key for the path-list is
@@ -1094,7 +1203,7 @@ show_fib_path_list_command (vlib_main_t * vm,
 }
 
 VLIB_CLI_COMMAND (show_fib_path_list, static) = {
-  .path = "show fib path list",
+  .path = "show fib path-lists",
   .function = show_fib_path_list_command,
-  .short_help = "show fib path list",
+  .short_help = "show fib path-lists",
 };