fib: Table Replace
[vpp.git] / src / vnet / mfib / ip4_mfib.c
index 3ed7cba..4da1be6 100644 (file)
@@ -33,12 +33,13 @@ static const mfib_prefix_t ip4_specials[] = {
 };
 
 static u32
-ip4_create_mfib_with_table_id (u32 table_id)
+ip4_create_mfib_with_table_id (u32 table_id,
+                               mfib_source_t src)
 {
     mfib_table_t *mfib_table;
 
     pool_get_aligned(ip4_main.mfibs, mfib_table, CLIB_CACHE_LINE_BYTES);
-    memset(mfib_table, 0, sizeof(*mfib_table));
+    clib_memset(mfib_table, 0, sizeof(*mfib_table));
 
     mfib_table->mft_proto = FIB_PROTOCOL_IP4;
     mfib_table->mft_index =
@@ -53,7 +54,7 @@ ip4_create_mfib_with_table_id (u32 table_id)
         mfib_table->v4.table_id =
             table_id;
 
-    mfib_table_lock(mfib_table->mft_index, FIB_PROTOCOL_IP4);
+    mfib_table_lock(mfib_table->mft_index, FIB_PROTOCOL_IP4, src);
 
     /*
      * add the special entries into the new FIB
@@ -113,14 +114,15 @@ ip4_mfib_table_destroy (ip4_mfib_t *mfib)
 }
 
 u32
-ip4_mfib_table_find_or_create_and_lock (u32 table_id)
+ip4_mfib_table_find_or_create_and_lock (u32 table_id,
+                                        mfib_source_t src)
 {
     u32 index;
 
     index = ip4_mfib_index_from_table_id(table_id);
     if (~0 == index)
-        return ip4_create_mfib_with_table_id(table_id);
-    mfib_table_lock(index, FIB_PROTOCOL_IP4);
+        return ip4_create_mfib_with_table_id(table_id, src);
+    mfib_table_lock(index, FIB_PROTOCOL_IP4, src);
 
     return (index);
 }
@@ -208,7 +210,7 @@ ip4_mfib_table_lookup (const ip4_mfib_t *mfib,
         }
     }
 
-    for (mask_len = 32; mask_len >= 0; mask_len--)
+    for (mask_len = (len == 64 ? 32 : len); mask_len >= 0; mask_len--)
     {
         hash = mfib->fib_entry_by_dst_address[mask_len];
         IP4_MFIB_MK_GRP_KEY(grp, mask_len, key);
@@ -222,6 +224,38 @@ ip4_mfib_table_lookup (const ip4_mfib_t *mfib,
     return (FIB_NODE_INDEX_INVALID);
 }
 
+fib_node_index_t
+ip4_mfib_table_get_less_specific (const ip4_mfib_t *mfib,
+                                  const ip4_address_t *src,
+                                  const ip4_address_t *grp,
+                                  u32 len)
+{
+    u32 mask_len;
+
+    /*
+     * in the absence of a tree structure for the table that allows for an O(1)
+     * parent get, a cheeky way to find the cover is to LPM for the prefix with
+     * mask-1.
+     * there should always be a cover, though it may be the default route. the
+     * default route's cover is the default route.
+     */
+    if (len == 64)
+    {
+        /* go from (S,G) to (*,G*) */
+        mask_len = 32;
+    }
+    else if (len != 0)
+    {
+       mask_len = len - 1;
+    }
+    else
+    {
+        mask_len = len;
+    }
+
+    return (ip4_mfib_table_lookup(mfib, src, grp, mask_len));
+}
+
 void
 ip4_mfib_table_entry_insert (ip4_mfib_t *mfib,
                              const ip4_address_t *grp,
@@ -269,7 +303,7 @@ ip4_mfib_table_entry_remove (ip4_mfib_t *mfib,
     if (NULL == result)
     {
         /*
-         * removing a non-existant entry. i'll allow it.
+         * removing a non-existent entry. i'll allow it.
          */
     }
     else
@@ -303,6 +337,42 @@ ip4_mfib_table_walk (ip4_mfib_t *mfib,
     }
 }
 
+u8 *
+format_ip4_mfib_table_memory (u8 * s, va_list * args)
+{
+    mfib_table_t *mfib_table;
+    u64 total_memory;
+
+    total_memory = 0;
+
+    pool_foreach (mfib_table, ip4_main.mfibs,
+    ({
+        ip4_mfib_t *mfib = &mfib_table->v4;
+        uword mfib_size;
+        int i;
+
+        mfib_size = 0;
+
+        for (i = 0; i < ARRAY_LEN (mfib->fib_entry_by_dst_address); i++)
+        {
+            uword * hash = mfib->fib_entry_by_dst_address[i];
+
+            if (NULL != hash)
+            {
+                mfib_size += hash_bytes(hash);
+            }
+        }
+
+        total_memory += mfib_size;
+    }));
+
+    s = format(s, "%=30s %=6d %=12ld\n",
+               "IPv4 multicast",
+               pool_elts(ip4_main.mfibs), total_memory);
+
+    return (s);
+}
+
 static void
 ip4_mfib_table_show_all (ip4_mfib_t *mfib,
                          vlib_main_t * vm)
@@ -361,20 +431,23 @@ ip4_show_mfib (vlib_main_t * vm,
 {
     ip4_main_t * im4 = &ip4_main;
     mfib_table_t *mfib_table;
-    int verbose, matching;
+    int verbose, matching, memory;
     ip4_address_t grp, src = {{0}};
     u32 mask = 32;
+    u64 total_hash_memory;
     int i, table_id = -1, fib_index = ~0;
 
     verbose = 1;
-    matching = 0;
+    memory = matching = 0;
+    total_hash_memory = 0;
 
     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
         if (unformat (input, "brief") || unformat (input, "summary")
             || unformat (input, "sum"))
             verbose = 0;
-
+        else if (unformat (input, "mem") || unformat (input, "memory"))
+            memory = 1;
         else if (unformat (input, "%U %U",
                            unformat_ip4_address, &src,
                            unformat_ip4_address, &grp))
@@ -382,14 +455,17 @@ ip4_show_mfib (vlib_main_t * vm,
             matching = 1;
             mask = 64;
         }
+        else if (unformat (input, "%U/%d", unformat_ip4_address, &grp, &mask))
+        {
+            clib_memset(&src, 0, sizeof(src));
+            matching = 1;
+        }
         else if (unformat (input, "%U", unformat_ip4_address, &grp))
         {
+            clib_memset(&src, 0, sizeof(src));
             matching = 1;
             mask = 32;
         }
-        else if (unformat (input, "%U/%d",
-                           unformat_ip4_address, &grp, &mask))
-            matching = 1;
         else if (unformat (input, "table %d", &table_id))
             ;
         else if (unformat (input, "index %d", &fib_index))
@@ -407,9 +483,33 @@ ip4_show_mfib (vlib_main_t * vm,
         if (fib_index != ~0 && fib_index != (int)mfib->index)
             continue;
 
-        vlib_cli_output (vm, "%U, fib_index %d",
+        if (memory)
+        {
+            uword hash_size;
+
+            hash_size = 0;
+
+           for (i = 0; i < ARRAY_LEN (mfib->fib_entry_by_dst_address); i++)
+           {
+               uword * hash = mfib->fib_entry_by_dst_address[i];
+                if (NULL != hash)
+                {
+                    hash_size += hash_bytes(hash);
+                }
+            }
+            if (verbose)
+                vlib_cli_output (vm, "%U hash:%d",
+                                 format_mfib_table_name, mfib->index,
+                                 FIB_PROTOCOL_IP4,
+                                 hash_size);
+            total_hash_memory += hash_size;
+            continue;
+        }
+
+        vlib_cli_output (vm, "%U, fib_index:%d flags:%U",
                          format_mfib_table_name, mfib->index, FIB_PROTOCOL_IP4,
-                         mfib->index);
+                         mfib->index,
+                         format_mfib_table_flags, mfib_table->mft_flags);
 
         /* Show summary? */
         if (! verbose)
@@ -434,6 +534,8 @@ ip4_show_mfib (vlib_main_t * vm,
             ip4_mfib_table_show_one(mfib, vm, &src, &grp, mask);
         }
     }));
+    if (memory)
+        vlib_cli_output (vm, "totals: hash:%ld", total_hash_memory);
 
     return 0;
 }