Include allocated table memory in 'sh fib mem' output

DBGvpp# sh fib mem
FIB memory
  Tables:
             SAFI              Number   Bytes
         IPv4 unicast             2    673066
         IPv6 unicast             2    1054608
             MPLS                 1    4194312
        IPv4 multicast            2     2322
        IPv6 multicast            2      ???
  Nodes:
             Name               Size  in-use /allocated   totals
             Entry               96     20   /    20      1920/1920
         Entry Source            32      0   /    0       0/0
     Entry Path-Extensions       60      0   /    0       0/0
        multicast-Entry         192     12   /    12      2304/2304
           Path-list             40     28   /    28      1120/1120
           uRPF-list             16     20   /    20      320/320
             Path                72     28   /    28      2016/2016
      Node-list elements         20     28   /    28      560/560
        Node-list heads          8      30   /    30      240/240

Change-Id: I8c8f6f1c87502a40265bf4f302d0daef111a4a4e
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/src/vnet/fib/fib_node.c b/src/vnet/fib/fib_node.c
index 54c300a..d2e3f04 100644
--- a/src/vnet/fib/fib_node.c
+++ b/src/vnet/fib/fib_node.c
@@ -15,6 +15,8 @@
 
 #include <vnet/fib/fib_node.h>
 #include <vnet/fib/fib_node_list.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/mfib/mfib_table.h>
 
 /*
  * The per-type vector of virtual function tables
@@ -234,6 +236,11 @@
     fib_node_vft_t *vft;
 
     vlib_cli_output (vm, "FIB memory");
+    vlib_cli_output (vm, "  Tables:");
+    vlib_cli_output (vm, "%=30s %=6s %=8s", "SAFI", "Number", "Bytes");
+    vlib_cli_output (vm, "%U", format_fib_table_memory);
+    vlib_cli_output (vm, "%U", format_mfib_table_memory);
+    vlib_cli_output (vm, "  Nodes:");
     vlib_cli_output (vm, "%=30s %=5s %=8s/%=9s   totals",
 		     "Name","Size", "in-use", "allocated");
 
@@ -255,15 +262,25 @@
  *
  * @cliexpar
  * @cliexstart{show fib memory}
- * FIB memory
- *             Name               Size  in-use /allocated   totals
- *             Entry              120     11   /    11      1320/1320
- *         Entry Source            32     11   /    11      352/352
- *     Entry Path-Extensions       44      0   /    0       0/0
- *           Path-list             40     11   /    11      440/440
- *             Path                88     11   /    11      968/968
- *      Node-list elements         20     11   /    11      220/220
- *        Node-list heads          8      13   /    13      104/104
+ *FIB memory
+ * Tables:
+ *            SAFI              Number   Bytes
+ *        IPv4 unicast             2    673066
+ *        IPv6 unicast             2    1054608
+ *            MPLS                 1    4194312
+ *       IPv4 multicast            2     2322
+ *       IPv6 multicast            2      ???
+ * Nodes:
+ *            Name               Size  in-use /allocated   totals
+ *            Entry               96     20   /    20      1920/1920
+ *        Entry Source            32      0   /    0       0/0
+ *    Entry Path-Extensions       60      0   /    0       0/0
+ *       multicast-Entry         192     12   /    12      2304/2304
+ *          Path-list             40     28   /    28      1120/1120
+ *          uRPF-list             16     20   /    20      320/320
+ *            Path                72     28   /    28      2016/2016
+ *     Node-list elements         20     28   /    28      560/560
+ *       Node-list heads          8      30   /    30      240/240
  * @cliexend
 ?*/
 VLIB_CLI_COMMAND (show_fib_memory, static) = {
diff --git a/src/vnet/fib/fib_table.c b/src/vnet/fib/fib_table.c
index 4dd6e7c..80e5a0f 100644
--- a/src/vnet/fib/fib_table.c
+++ b/src/vnet/fib/fib_table.c
@@ -1296,3 +1296,13 @@
 
     vec_free(ctx.ftf_entries);
 }
+
+u8 *
+format_fib_table_memory (u8 *s, va_list *args)
+{
+    s = format(s, "%U", format_ip4_fib_table_memory);
+    s = format(s, "%U", format_ip6_fib_table_memory);
+    s = format(s, "%U", format_mpls_fib_table_memory);
+
+    return (s);
+}
diff --git a/src/vnet/fib/fib_table.h b/src/vnet/fib/fib_table.h
index d2522aa..8a0c739 100644
--- a/src/vnet/fib/fib_table.h
+++ b/src/vnet/fib/fib_table.h
@@ -808,4 +808,9 @@
                            fib_table_walk_fn_t fn,
                            void *ctx);
 
+/**
+ * @brief format (display) the memory used by the FIB tables
+ */
+extern u8 *format_fib_table_memory(u8 *s, va_list *args);
+
 #endif
diff --git a/src/vnet/fib/ip4_fib.c b/src/vnet/fib/ip4_fib.c
index 36cf6e7..45f1974 100644
--- a/src/vnet/fib/ip4_fib.c
+++ b/src/vnet/fib/ip4_fib.c
@@ -481,6 +481,43 @@
                      FIB_ENTRY_FORMAT_DETAIL));
 }
 
+u8 *
+format_ip4_fib_table_memory (u8 * s, va_list * args)
+{
+    fib_table_t *fib_table;
+    u64 total_memory;
+
+    total_memory = 0;
+
+    pool_foreach (fib_table, ip4_main.fibs,
+    ({
+	ip4_fib_t *fib;
+        uword fib_size;
+        int i;
+
+        fib = pool_elt_at_index(ip4_main.v4_fibs, fib_table->ft_index);
+        fib_size = ip4_fib_mtrie_memory_usage(&fib->mtrie);
+
+        for (i = 0; i < ARRAY_LEN (fib->fib_entry_by_dst_address); i++)
+        {
+            uword * hash = fib->fib_entry_by_dst_address[i];
+
+            if (NULL != hash)
+            {
+                fib_size += hash_bytes(hash);
+            }
+        }
+
+        total_memory += fib_size;
+    }));
+
+    s = format(s, "%=30s %=6d %=8ld\n",
+               "IPv4 unicast",
+               pool_elts(ip4_main.fibs), total_memory);
+
+    return (s);
+}
+
 static clib_error_t *
 ip4_show_fib (vlib_main_t * vm,
 	      unformat_input_t * input,
@@ -488,15 +525,17 @@
 {
     ip4_main_t * im4 = &ip4_main;
     fib_table_t * fib_table;
-    int verbose, matching, mtrie;
+    u64 total_mtrie_memory, total_hash_memory;
+    int verbose, matching, mtrie, memory;
     ip4_address_t matching_address;
     u32 matching_mask = 32;
     int i, table_id = -1, fib_index = ~0;
     int detail = 0;
 
     verbose = 1;
-    matching = 0;
-    mtrie = 0;
+    matching = mtrie = memory = 0;
+    total_hash_memory = total_mtrie_memory = 0;
+
     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
 	if (unformat (input, "brief") || unformat (input, "summary")
@@ -509,6 +548,10 @@
 	else if (unformat (input, "mtrie"))
 	    mtrie = 1;
 
+        else if (unformat (input, "mem") ||
+                 unformat (input, "memory"))
+	    memory = 1;
+
 	else if (unformat (input, "%U/%d",
 			   unformat_ip4_address, &matching_address, &matching_mask))
 	    matching = 1;
@@ -535,6 +578,32 @@
 	if (fib_index != ~0 && fib_index != (int)fib->index)
 	    continue;
 
+        if (memory)
+        {
+            uword mtrie_size, hash_size;
+
+            mtrie_size = ip4_fib_mtrie_memory_usage(&fib->mtrie);
+            hash_size = 0;
+
+	    for (i = 0; i < ARRAY_LEN (fib->fib_entry_by_dst_address); i++)
+	    {
+		uword * hash = fib->fib_entry_by_dst_address[i];
+                if (NULL != hash)
+                {
+                    hash_size += hash_bytes(hash);
+                }
+            }
+            if (verbose)
+                vlib_cli_output (vm, "%U mtrie:%d hash:%d",
+                                 format_fib_table_name, fib->index,
+                                 FIB_PROTOCOL_IP4,
+                                 mtrie_size,
+                                 hash_size);
+            total_mtrie_memory += mtrie_size;
+            total_hash_memory += hash_size;
+            continue;
+        }
+
 	s = format(s, "%U, fib_index:%d, flow hash:[%U] locks:[",
                    format_fib_table_name, fib->index,
                    FIB_PROTOCOL_IP4,
@@ -584,6 +653,12 @@
 	}
     }));
 
+    if (memory)
+        vlib_cli_output (vm, "totals: mtrie:%ld hash:%ld all:%ld",
+                         total_mtrie_memory,
+                         total_hash_memory,
+                         total_mtrie_memory + total_hash_memory);
+
     return 0;
 }
 
diff --git a/src/vnet/fib/ip4_fib.h b/src/vnet/fib/ip4_fib.h
index 495b45c..438eb24 100644
--- a/src/vnet/fib/ip4_fib.h
+++ b/src/vnet/fib/ip4_fib.h
@@ -131,6 +131,7 @@
                                                  fib_source_t src);
 extern u32 ip4_fib_table_create_and_lock(fib_source_t src);
 
+extern u8 *format_ip4_fib_table_memory(u8 * s, va_list * args);
 
 static inline 
 u32 ip4_fib_index_from_table_id (u32 table_id)
diff --git a/src/vnet/fib/ip6_fib.c b/src/vnet/fib/ip6_fib.c
index f37ae0d..3400987 100644
--- a/src/vnet/fib/ip6_fib.c
+++ b/src/vnet/fib/ip6_fib.c
@@ -524,6 +524,18 @@
                      FIB_ENTRY_FORMAT_DETAIL));
 }
 
+u8 *
+format_ip6_fib_table_memory (u8 * s, va_list * args)
+{
+    s = format(s, "%=30s %=6d %=8ld\n",
+               "IPv6 unicast",
+               pool_elts(ip6_main.fibs),
+               mheap_bytes(ip6_main.ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash.mheap) +
+               mheap_bytes(ip6_main.ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash.mheap));
+
+    return (s);
+}
+
 typedef struct {
   u32 fib_index;
   u64 count_by_prefix_length[129];
diff --git a/src/vnet/fib/ip6_fib.h b/src/vnet/fib/ip6_fib.h
index 9728eec..eda5362 100644
--- a/src/vnet/fib/ip6_fib.h
+++ b/src/vnet/fib/ip6_fib.h
@@ -148,6 +148,8 @@
                                                  fib_source_t src);
 extern u32 ip6_fib_table_create_and_lock(fib_source_t src);
 
+extern u8 *format_ip6_fib_table_memory(u8 * s, va_list * args);
+
 static inline ip6_fib_t *
 ip6_fib_get (fib_node_index_t index)
 {
diff --git a/src/vnet/fib/mpls_fib.c b/src/vnet/fib/mpls_fib.c
index 4eeef7a..1593120 100644
--- a/src/vnet/fib/mpls_fib.c
+++ b/src/vnet/fib/mpls_fib.c
@@ -359,6 +359,18 @@
     }));
 }
 
+u8 *
+format_mpls_fib_table_memory (u8 * s, va_list * args)
+{
+    u64 n_tables, mem;
+
+    n_tables = pool_elts(mpls_main.fibs);
+    mem = n_tables * sizeof(mpls_fib_t);
+    s = format(s, "%=30s %=6ld %=8ld\n", "MPLS", n_tables, mem);
+
+    return (s);
+}
+
 static void
 mpls_fib_table_show_all (const mpls_fib_t *mpls_fib,
 			 vlib_main_t * vm)
diff --git a/src/vnet/fib/mpls_fib.h b/src/vnet/fib/mpls_fib.h
index 29cd1d2..9e0c7d7 100644
--- a/src/vnet/fib/mpls_fib.h
+++ b/src/vnet/fib/mpls_fib.h
@@ -105,6 +105,8 @@
                                 fib_table_walk_fn_t fn,
                                 void *ctx);
 
+extern u8 *format_mpls_fib_table_memory(u8 * s, va_list * args);
+
 /**
  * @brief
  *  Lookup a label and EOS bit in the MPLS_FIB table to retrieve the
diff --git a/src/vnet/ip/ip4_mtrie.c b/src/vnet/ip/ip4_mtrie.c
index f114da0..5b78cbe 100644
--- a/src/vnet/ip/ip4_mtrie.c
+++ b/src/vnet/ip/ip4_mtrie.c
@@ -683,8 +683,8 @@
 }
 
 /* Returns number of bytes of memory used by mtrie. */
-static uword
-mtrie_memory_usage (ip4_fib_mtrie_t * m)
+uword
+ip4_fib_mtrie_memory_usage (ip4_fib_mtrie_t * m)
 {
   uword bytes, i;
 
@@ -771,7 +771,9 @@
 
   s = format (s, "%d plies, memory usage %U\n",
 	      pool_elts (ip4_ply_pool),
-	      format_memory_size, mtrie_memory_usage (m));
+	      format_memory_size, ip4_fib_mtrie_memory_usage (m));
+  s = format (s, "root-ply");
+  p = &m->root_ply;
 
   if (verbose)
     {
diff --git a/src/vnet/ip/ip4_mtrie.h b/src/vnet/ip/ip4_mtrie.h
index be262c2..34b97dc 100644
--- a/src/vnet/ip/ip4_mtrie.h
+++ b/src/vnet/ip/ip4_mtrie.h
@@ -162,6 +162,11 @@
 			      u32 cover_address_length, u32 cover_adj_index);
 
 /**
+ * @brief return the memory used by the table
+ */
+uword ip4_fib_mtrie_memory_usage (ip4_fib_mtrie_t * m);
+
+/**
  * @brief Format/display the contents of the mtrie
  */
 format_function_t format_ip4_fib_mtrie;
diff --git a/src/vnet/mfib/ip4_mfib.c b/src/vnet/mfib/ip4_mfib.c
index b248258..7040fa7 100644
--- a/src/vnet/mfib/ip4_mfib.c
+++ b/src/vnet/mfib/ip4_mfib.c
@@ -305,6 +305,42 @@
     }
 }
 
+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 %=8ld\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)
@@ -363,20 +399,23 @@
 {
     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))
@@ -412,6 +451,29 @@
         if (fib_index != ~0 && fib_index != (int)mfib->index)
             continue;
 
+        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",
                          format_mfib_table_name, mfib->index, FIB_PROTOCOL_IP4,
                          mfib->index);
@@ -439,6 +501,8 @@
             ip4_mfib_table_show_one(mfib, vm, &src, &grp, mask);
         }
     }));
+    if (memory)
+        vlib_cli_output (vm, "totals: hash:%ld", total_hash_memory);
 
     return 0;
 }
diff --git a/src/vnet/mfib/ip4_mfib.h b/src/vnet/mfib/ip4_mfib.h
index e31fb74..7767d79 100644
--- a/src/vnet/mfib/ip4_mfib.h
+++ b/src/vnet/mfib/ip4_mfib.h
@@ -98,8 +98,13 @@
  * @param fn The function to invoke on each entry visited
  * @param ctx A context passed in the visit function
  */
-extern void ip4_mfib_table_walk (ip4_mfib_t *mfib,
-                                 mfib_table_walk_fn_t fn,
-                                 void *ctx);
+extern void ip4_mfib_table_walk(ip4_mfib_t *mfib,
+                                mfib_table_walk_fn_t fn,
+                                void *ctx);
+
+/**
+ * @brief format (display) the memory usage for IP4 mfibs
+ */
+extern u8 * format_ip4_mfib_table_memory(u8 * s, va_list * args);
 
 #endif
diff --git a/src/vnet/mfib/ip6_mfib.c b/src/vnet/mfib/ip6_mfib.c
index e486133..1c1f5db 100644
--- a/src/vnet/mfib/ip6_mfib.c
+++ b/src/vnet/mfib/ip6_mfib.c
@@ -472,6 +472,16 @@
 
 VLIB_INIT_FUNCTION(ip6_mfib_module_init);
 
+u8 *
+format_ip6_mfib_table_memory (u8 * s, va_list * args)
+{
+    s = format(s, "%=30s %=6d %=8s\n",
+               "IPv6 multicast",
+               pool_elts(ip6_main.mfibs), "???");
+
+    return (s);
+}
+
 static void
 ip6_mfib_table_show_one (ip6_mfib_t *mfib,
                          vlib_main_t * vm,
@@ -566,7 +576,7 @@
                unformat_input_t * input,
                vlib_cli_command_t * cmd)
 {
-    ip6_main_t * im4 = &ip6_main;
+    ip6_main_t * im6 = &ip6_main;
     mfib_table_t *mfib_table;
     int verbose, matching;
     ip6_address_t grp, src = {{0}};
@@ -608,7 +618,7 @@
             break;
     }
 
-    pool_foreach (mfib_table, im4->mfibs,
+    pool_foreach (mfib_table, im6->mfibs,
     ({
         ip6_mfib_t *mfib = &mfib_table->v6;
 
@@ -649,7 +659,7 @@
 }
 
 /*
- * This command displays the IPv4 MulticasrFIB Tables (VRF Tables) and
+ * This command displays the IPv6 MulticasrFIB Tables (VRF Tables) and
  * the route entries for each table.
  *
  * @note This command will run for a long time when the FIB tables are
@@ -657,9 +667,9 @@
  * a single table or summary mode.
  *
  * @cliexpar
- * Example of how to display all the IPv4 Multicast FIB tables:
+ * Example of how to display all the IPv6 Multicast FIB tables:
  * @cliexstart{show ip fib}
- * ipv4-VRF:0, fib_index 0
+ * ipv6-VRF:0, fib_index 0
  * (*, 0.0.0.0/0):  flags:D,
  *  Interfaces:
  *  multicast-ip6-chain
@@ -671,18 +681,18 @@
  *  test-eth0: Accept,
  * multicast-ip6-chain
  * [@2]: dpo-replicate: [index:1 buckets:2 to:[0:0]]
- *   [0] [@1]: ipv4-mcast: test-eth1: IP6: d0:d1:d2:d3:d4:01 -> 01:00:05:00:00:00
- *   [1] [@1]: ipv4-mcast: test-eth2: IP6: d0:d1:d2:d3:d4:02 -> 01:00:05:00:00:00
+ *   [0] [@1]: ipv6-mcast: test-eth1: IP6: d0:d1:d2:d3:d4:01 -> 01:00:05:00:00:00
+ *   [1] [@1]: ipv6-mcast: test-eth2: IP6: d0:d1:d2:d3:d4:02 -> 01:00:05:00:00:00
  *
  * @cliexend
- * Example of how to display a summary of all IPv4 FIB tables:
+ * Example of how to display a summary of all IPv6 FIB tables:
  * @cliexstart{show ip fib summary}
- * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
+ * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
  *     Prefix length         Count
  *                    0               1
  *                    8               2
  *                   32               4
- * ipv4-VRF:7, fib_index 1, flow hash: src dst sport dport proto
+ * ipv6-VRF:7, fib_index 1, flow hash: src dst sport dport proto
  *     Prefix length         Count
  *                    0               1
  *                    8               2
diff --git a/src/vnet/mfib/ip6_mfib.h b/src/vnet/mfib/ip6_mfib.h
index ea81b55..5ebdd0a 100644
--- a/src/vnet/mfib/ip6_mfib.h
+++ b/src/vnet/mfib/ip6_mfib.h
@@ -117,5 +117,10 @@
                                  mfib_table_walk_fn_t fn,
                                  void *ctx);
 
+/**
+ * @brief format (display) ipv6 MFIB mempry usage
+ */
+extern u8 *format_ip6_mfib_table_memory(u8 * s, va_list * args);
+
 #endif
 
diff --git a/src/vnet/mfib/mfib_table.c b/src/vnet/mfib/mfib_table.c
index efeadef..dc51b7c 100644
--- a/src/vnet/mfib/mfib_table.c
+++ b/src/vnet/mfib/mfib_table.c
@@ -628,6 +628,15 @@
     return (s);
 }
 
+u8 *
+format_mfib_table_memory (u8 *s, va_list *args)
+{
+    s = format(s, "%U", format_ip4_mfib_table_memory);
+    s = format(s, "%U", format_ip6_mfib_table_memory);
+
+    return (s);
+}
+
 static clib_error_t *
 mfib_module_init (vlib_main_t * vm)
 {
diff --git a/src/vnet/mfib/mfib_table.h b/src/vnet/mfib/mfib_table.h
index 6a58102..63af25b 100644
--- a/src/vnet/mfib/mfib_table.h
+++ b/src/vnet/mfib/mfib_table.h
@@ -420,5 +420,9 @@
                             fib_protocol_t proto,
                             mfib_table_walk_fn_t fn,
                             void *ctx);
+/**
+ * @brief format (display) the memory usage for mfibs
+ */
+extern u8 * format_mfib_table_memory(u8 * s, va_list * args);
 
 #endif