IP Flow Hash Config fixes
[vpp.git] / src / vnet / fib / fib_table.c
index 76db42d..d50f17f 100644 (file)
@@ -47,7 +47,7 @@ fib_table_lookup_i (fib_table_t *fib_table,
     switch (prefix->fp_proto)
     {
     case FIB_PROTOCOL_IP4:
-       return (ip4_fib_table_lookup(&fib_table->v4,
+       return (ip4_fib_table_lookup(ip4_fib_get(fib_table->ft_index),
                                     &prefix->fp_addr.ip4,
                                     prefix->fp_len));
     case FIB_PROTOCOL_IP6:
@@ -55,7 +55,7 @@ fib_table_lookup_i (fib_table_t *fib_table,
                                     &prefix->fp_addr.ip6,
                                     prefix->fp_len));
     case FIB_PROTOCOL_MPLS:
-       return (mpls_fib_table_lookup(&fib_table->mpls,
+       return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
                                      prefix->fp_label,
                                      prefix->fp_eos));
     }
@@ -76,7 +76,7 @@ fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
     switch (prefix->fp_proto)
     {
     case FIB_PROTOCOL_IP4:
-       return (ip4_fib_table_lookup_exact_match(&fib_table->v4,
+       return (ip4_fib_table_lookup_exact_match(ip4_fib_get(fib_table->ft_index),
                                                 &prefix->fp_addr.ip4,
                                                 prefix->fp_len));
     case FIB_PROTOCOL_IP6:
@@ -84,7 +84,7 @@ fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
                                                 &prefix->fp_addr.ip6,
                                                 prefix->fp_len));
     case FIB_PROTOCOL_MPLS:
-       return (mpls_fib_table_lookup(&fib_table->mpls,
+       return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
                                      prefix->fp_label,
                                      prefix->fp_eos));
     }
@@ -148,7 +148,7 @@ fib_table_entry_remove (fib_table_t *fib_table,
     switch (prefix->fp_proto)
     {
     case FIB_PROTOCOL_IP4:
-       ip4_fib_table_entry_remove(&fib_table->v4,
+       ip4_fib_table_entry_remove(ip4_fib_get(fib_table->ft_index),
                                   &prefix->fp_addr.ip4,
                                   prefix->fp_len);
        break;
@@ -158,7 +158,7 @@ fib_table_entry_remove (fib_table_t *fib_table,
                                   prefix->fp_len);
        break;
     case FIB_PROTOCOL_MPLS:
-       mpls_fib_table_entry_remove(&fib_table->mpls,
+       mpls_fib_table_entry_remove(mpls_fib_get(fib_table->ft_index),
                                    prefix->fp_label,
                                    prefix->fp_eos);
        break;
@@ -208,7 +208,7 @@ fib_table_entry_insert (fib_table_t *fib_table,
     switch (prefix->fp_proto)
     {
     case FIB_PROTOCOL_IP4:
-       ip4_fib_table_entry_insert(&fib_table->v4,
+       ip4_fib_table_entry_insert(ip4_fib_get(fib_table->ft_index),
                                   &prefix->fp_addr.ip4,
                                   prefix->fp_len,
                                   fib_entry_index);
@@ -220,7 +220,7 @@ fib_table_entry_insert (fib_table_t *fib_table,
                                   fib_entry_index);
        break;
     case FIB_PROTOCOL_MPLS:
-       mpls_fib_table_entry_insert(&fib_table->mpls,
+       mpls_fib_table_entry_insert(mpls_fib_get(fib_table->ft_index),
                                    prefix->fp_label,
                                    prefix->fp_eos,
                                    fib_entry_index);
@@ -270,7 +270,9 @@ fib_table_fwding_dpo_remove (u32 fib_index,
        return (ip4_fib_table_fwding_dpo_remove(ip4_fib_get(fib_index),
                                                &prefix->fp_addr.ip4,
                                                prefix->fp_len,
-                                               dpo));
+                                               dpo,
+                                                fib_table_get_less_specific(fib_index,
+                                                                            prefix)));
     case FIB_PROTOCOL_IP6:
        return (ip6_fib_table_fwding_dpo_remove(fib_index,
                                                &prefix->fp_addr.ip6,
@@ -369,23 +371,12 @@ fib_node_index_t
 fib_table_entry_special_add (u32 fib_index,
                             const fib_prefix_t *prefix,
                             fib_source_t source,
-                            fib_entry_flag_t flags,
-                            adj_index_t adj_index)
+                            fib_entry_flag_t flags)
 {
     fib_node_index_t fib_entry_index;
     dpo_id_t tmp_dpo = DPO_INVALID;
 
-    if (ADJ_INDEX_INVALID != adj_index)
-    {
-        dpo_set(&tmp_dpo,
-                DPO_ADJACENCY,
-                FIB_PROTOCOL_MAX,
-                adj_index);
-    }
-    else
-    {
-        dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
-    }
+    dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
  
     fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
                                                       flags, &tmp_dpo);
@@ -473,15 +464,41 @@ fib_table_entry_special_remove (u32 fib_index,
  */
 static void
 fib_table_route_path_fixup (const fib_prefix_t *prefix,
+                            fib_entry_flag_t eflags,
                            fib_route_path_t *path)
 {
+    /*
+     * not all zeros next hop &&
+     * is recursive path &&
+     * nexthop is same as the route's address
+     */
+    if ((!ip46_address_is_zero(&path->frp_addr)) &&
+        (~0 == path->frp_sw_if_index) &&
+        (0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr)))
+    {
+        /* Prefix recurses via itse;f */
+       path->frp_flags |= FIB_ROUTE_PATH_DROP;
+    }
     if (fib_prefix_is_host(prefix) &&
        ip46_address_is_zero(&path->frp_addr) &&
        path->frp_sw_if_index != ~0)
     {
        path->frp_addr = prefix->fp_addr;
+        path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
+    }
+    if (eflags & FIB_ENTRY_FLAG_DROP)
+    {
+       path->frp_flags |= FIB_ROUTE_PATH_DROP;
     }
-}                
+    if (eflags & FIB_ENTRY_FLAG_LOCAL)
+    {
+       path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
+    }
+    if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
+    {
+       path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
+    }
+}
 
 fib_node_index_t
 fib_table_entry_path_add (u32 fib_index,
@@ -533,7 +550,7 @@ fib_table_entry_path_add2 (u32 fib_index,
 
     for (ii = 0; ii < vec_len(rpath); ii++)
     {
-       fib_table_route_path_fixup(prefix, &rpath[ii]);
+       fib_table_route_path_fixup(prefix, flags, &rpath[ii]);
     }
 
     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
@@ -580,11 +597,6 @@ fib_table_entry_path_remove2 (u32 fib_index,
     fib_table = fib_table_get(fib_index, prefix->fp_proto);
     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
 
-    for (ii = 0; ii < vec_len(rpath); ii++)
-    {
-       fib_table_route_path_fixup(prefix, &rpath[ii]);
-    }
-
     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
     {
        /*
@@ -596,11 +608,28 @@ fib_table_entry_path_remove2 (u32 fib_index,
        fib_entry_src_flag_t src_flag;
         int was_sourced;
 
-       /*
+        /*
+         * if it's not sourced, then there's nowt to remove
+         */
+        was_sourced = fib_entry_is_sourced(fib_entry_index, source);
+        if (!was_sourced)
+        {
+            return;
+        }
+
+        /*
         * don't nobody go nowhere
         */
        fib_entry_lock(fib_entry_index);
-        was_sourced = fib_entry_is_sourced(fib_entry_index, source);
+
+        for (ii = 0; ii < vec_len(rpath); ii++)
+        {
+            fib_table_route_path_fixup(
+                prefix,
+                fib_entry_get_flags_for_source(fib_entry_index,
+                                               source),
+                &rpath[ii]);
+        }
 
        src_flag = fib_entry_path_remove(fib_entry_index, source, rpath);
 
@@ -658,7 +687,6 @@ fib_table_entry_path_remove (u32 fib_index,
     };
     fib_route_path_t *paths = NULL;
 
-    fib_table_route_path_fixup(prefix, &path);
     vec_add1(paths, path);
 
     fib_table_entry_path_remove2(fib_index, prefix, source, paths);
@@ -689,7 +717,7 @@ fib_table_entry_update (u32 fib_index,
 
     for (ii = 0; ii < vec_len(paths); ii++)
     {
-       fib_table_route_path_fixup(prefix, &paths[ii]);
+       fib_table_route_path_fixup(prefix, flags, &paths[ii]);
     }
     /*
      * sort the paths provided by the control plane. this means
@@ -747,7 +775,6 @@ fib_table_entry_update_one_path (u32 fib_index,
     };
     fib_route_path_t *paths = NULL;
 
-    fib_table_route_path_fixup(prefix, &path);
     vec_add1(paths, path);
 
     fib_entry_index = 
@@ -918,18 +945,52 @@ flow_hash_config_t
 fib_table_get_flow_hash_config (u32 fib_index,
                                fib_protocol_t proto)
 {
-    switch (proto)
-    {
-    case FIB_PROTOCOL_IP4:
-       return (ip4_fib_table_get_flow_hash_config(fib_index));
-    case FIB_PROTOCOL_IP6:
-       return (ip6_fib_table_get_flow_hash_config(fib_index));
-    case FIB_PROTOCOL_MPLS:
-       return (mpls_fib_table_get_flow_hash_config(fib_index));
-    }
-    return (0);
+    fib_table_t *fib;
+
+    fib = fib_table_get(fib_index, proto);
+
+    return (fib->ft_flow_hash_config);
+}
+
+/**
+ * @brief Table set flow hash config context.
+ */
+typedef struct fib_table_set_flow_hash_config_ctx_t_
+{
+    /**
+     * the flow hash config to set
+     */
+    flow_hash_config_t hash_config;
+} fib_table_set_flow_hash_config_ctx_t;
+
+static int
+fib_table_set_flow_hash_config_cb (fib_node_index_t fib_entry_index,
+                                   void *arg)
+{
+    fib_table_set_flow_hash_config_ctx_t *ctx = arg;
+
+    fib_entry_set_flow_hash_config(fib_entry_index, ctx->hash_config);
+
+    return (1);
 }
 
+void
+fib_table_set_flow_hash_config (u32 fib_index,
+                                fib_protocol_t proto,
+                                flow_hash_config_t hash_config)
+{
+    fib_table_set_flow_hash_config_ctx_t ctx = {
+        .hash_config = hash_config,
+    };
+    fib_table_t *fib;
+
+    fib = fib_table_get(fib_index, proto);
+    fib->ft_flow_hash_config = hash_config;
+
+    fib_table_walk(fib_index, proto,
+                   fib_table_set_flow_hash_config_cb,
+                   &ctx);
+}
 
 u32
 fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
@@ -1033,13 +1094,33 @@ fib_table_destroy (fib_table_t *fib_table)
     switch (fib_table->ft_proto)
     {
     case FIB_PROTOCOL_IP4:
-       ip4_fib_table_destroy(&fib_table->v4);
+       ip4_fib_table_destroy(fib_table->ft_index);
        break;
     case FIB_PROTOCOL_IP6:
        ip6_fib_table_destroy(fib_table->ft_index);
        break;
     case FIB_PROTOCOL_MPLS:
-       mpls_fib_table_destroy(&fib_table->mpls);
+       mpls_fib_table_destroy(fib_table->ft_index);
+       break;
+    }
+}
+
+void
+fib_table_walk (u32 fib_index,
+                fib_protocol_t proto,
+                fib_table_walk_fn_t fn,
+                void *ctx)
+{
+    switch (proto)
+    {
+    case FIB_PROTOCOL_IP4:
+       ip4_fib_table_walk(ip4_fib_get(fib_index), fn, ctx);
+       break;
+    case FIB_PROTOCOL_IP6:
+       ip6_fib_table_walk(fib_index, fn, ctx);
+       break;
+    case FIB_PROTOCOL_MPLS:
+       mpls_fib_table_walk(mpls_fib_get(fib_index), fn, ctx);
        break;
     }
 }
@@ -1094,11 +1175,56 @@ format_fib_table_name (u8* s, va_list ap)
     return (s);
 }
 
+/**
+ * @brief Table flush context. Store the indicies of matching FIB entries
+ * that need to be removed.
+ */
+typedef struct fib_table_flush_ctx_t_
+{
+    /**
+     * The list of entries to flush
+     */
+    fib_node_index_t *ftf_entries;
+
+    /**
+     * The source we are flushing
+     */
+    fib_source_t ftf_source;
+} fib_table_flush_ctx_t;
+
+static int
+fib_table_flush_cb (fib_node_index_t fib_entry_index,
+                    void *arg)
+{
+    fib_table_flush_ctx_t *ctx = arg;
+
+    if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
+    {
+        vec_add1(ctx->ftf_entries, fib_entry_index);
+    }
+    return (1);
+}
+
+
 void
 fib_table_flush (u32 fib_index,
                 fib_protocol_t proto,
                 fib_source_t source)
 {
-    // FIXME
-    ASSERT(0);
+    fib_node_index_t *fib_entry_index;
+    fib_table_flush_ctx_t ctx = {
+        .ftf_entries = NULL,
+        .ftf_source = source,
+    };
+
+    fib_table_walk(fib_index, proto,
+                   fib_table_flush_cb,
+                   &ctx);
+
+    vec_foreach(fib_entry_index, ctx.ftf_entries)
+    {
+        fib_table_entry_delete_index(*fib_entry_index, source);
+    }
+
+    vec_free(ctx.ftf_entries);
 }