IP6-MFIB: replace the radix tree with bihash (VPP-1526)
[vpp.git] / src / vnet / ip / ip6_forward.c
index f4c51e2..56cef4a 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <vnet/vnet.h>
 #include <vnet/ip/ip.h>
+#include <vnet/ip/ip_frag.h>
 #include <vnet/ip/ip6_neighbor.h>
 #include <vnet/ethernet/ethernet.h>    /* for ethernet_header_t */
 #include <vnet/srp/srp.h>      /* for srp_hw_interface_class */
@@ -200,6 +201,7 @@ ip6_add_del_interface_address (vlib_main_t * vm,
   clib_error_t *error;
   u32 if_address_index;
   ip6_address_fib_t ip6_af, *addr_fib = 0;
+  ip6_address_t ll_addr;
 
   /* local0 interface doesn't support IP addressing */
   if (sw_if_index == 0)
@@ -208,6 +210,36 @@ ip6_add_del_interface_address (vlib_main_t * vm,
        clib_error_create ("local0 interface doesn't support IP addressing");
     }
 
+  if (ip6_address_is_link_local_unicast (address))
+    {
+      if (address_length != 128)
+       {
+         vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
+         return
+           clib_error_create
+           ("prefix length of link-local address must be 128");
+       }
+      if (!is_del)
+       {
+         return ip6_neighbor_set_link_local_address (vm, sw_if_index,
+                                                     address);
+       }
+      else
+       {
+         ll_addr = ip6_neighbor_get_link_local_address (sw_if_index);
+         if (ip6_address_is_equal (&ll_addr, address))
+           {
+             vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_DELETABLE;
+             return clib_error_create ("address not deletable");
+           }
+         else
+           {
+             vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
+             return clib_error_create ("address not found");
+           }
+       }
+    }
+
   vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
   vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
 
@@ -339,6 +371,7 @@ VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
 {
   .arc_name  = "ip6-unicast",
   .start_nodes = VNET_FEATURES ("ip6-input"),
+  .last_in_arc = "ip6-lookup",
   .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
 };
 
@@ -360,13 +393,13 @@ VNET_FEATURE_INIT (ip6_policer_classify, static) =
 {
   .arc_name = "ip6-unicast",
   .node_name = "ip6-policer-classify",
-  .runs_before = VNET_FEATURES ("ipsec-input-ip6"),
+  .runs_before = VNET_FEATURES ("ipsec6-input-feature"),
 };
 
 VNET_FEATURE_INIT (ip6_ipsec, static) =
 {
   .arc_name = "ip6-unicast",
-  .node_name = "ipsec-input-ip6",
+  .node_name = "ipsec6-input-feature",
   .runs_before = VNET_FEATURES ("l2tp-decap"),
 };
 
@@ -410,6 +443,7 @@ VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
 {
   .arc_name  = "ip6-multicast",
   .start_nodes = VNET_FEATURES ("ip6-input"),
+  .last_in_arc = "ip6-mfib-forward-lookup",
   .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
 };
 
@@ -436,18 +470,19 @@ VNET_FEATURE_ARC_INIT (ip6_output, static) =
 {
   .arc_name  = "ip6-output",
   .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain", "ip6-dvr-dpo"),
+  .last_in_arc = "interface-output",
   .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
 };
 
 VNET_FEATURE_INIT (ip6_outacl, static) = {
   .arc_name = "ip6-output",
   .node_name = "ip6-outacl",
-  .runs_before = VNET_FEATURES ("ipsec-output-ip6"),
+  .runs_before = VNET_FEATURES ("ipsec6-output-feature"),
 };
 
 VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
   .arc_name = "ip6-output",
-  .node_name = "ipsec-output-ip6",
+  .node_name = "ipsec6-output-feature",
   .runs_before = VNET_FEATURES ("interface-output"),
 };
 
@@ -521,23 +556,20 @@ VLIB_REGISTER_NODE (ip6_lookup_node) =
 
 VLIB_NODE_FUNCTION_MULTIARCH (ip6_lookup_node, ip6_lookup);
 
-always_inline uword
+static uword
 ip6_load_balance (vlib_main_t * vm,
                  vlib_node_runtime_t * node, vlib_frame_t * frame)
 {
   vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters;
   u32 n_left_from, n_left_to_next, *from, *to_next;
   ip_lookup_next_t next;
-  u32 thread_index = vlib_get_thread_index ();
+  u32 thread_index = vm->thread_index;
   ip6_main_t *im = &ip6_main;
 
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
   next = node->cached_next_index;
 
-  if (node->flags & VLIB_NODE_FLAG_TRACE)
-    ip6_forward_next_trace (vm, node, frame, VLIB_TX);
-
   while (n_left_from > 0)
     {
       vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
@@ -735,6 +767,9 @@ ip6_load_balance (vlib_main_t * vm,
       vlib_put_next_frame (vm, node, next, n_left_to_next);
     }
 
+  if (node->flags & VLIB_NODE_FLAG_TRACE)
+    ip6_forward_next_trace (vm, node, frame, VLIB_TX);
+
   return frame->n_vectors;
 }
 
@@ -851,9 +886,9 @@ ip6_forward_next_trace (vlib_main_t * vm,
            vec_elt (im->fib_index_by_sw_if_index,
                     vnet_buffer (b0)->sw_if_index[VLIB_RX]);
 
-         clib_memcpy (t0->packet_data,
-                      vlib_buffer_get_current (b0),
-                      sizeof (t0->packet_data));
+         clib_memcpy_fast (t0->packet_data,
+                           vlib_buffer_get_current (b0),
+                           sizeof (t0->packet_data));
        }
       if (b1->flags & VLIB_BUFFER_IS_TRACED)
        {
@@ -866,9 +901,9 @@ ip6_forward_next_trace (vlib_main_t * vm,
            vec_elt (im->fib_index_by_sw_if_index,
                     vnet_buffer (b1)->sw_if_index[VLIB_RX]);
 
-         clib_memcpy (t1->packet_data,
-                      vlib_buffer_get_current (b1),
-                      sizeof (t1->packet_data));
+         clib_memcpy_fast (t1->packet_data,
+                           vlib_buffer_get_current (b1),
+                           sizeof (t1->packet_data));
        }
       from += 2;
       n_left -= 2;
@@ -895,9 +930,9 @@ ip6_forward_next_trace (vlib_main_t * vm,
            vec_elt (im->fib_index_by_sw_if_index,
                     vnet_buffer (b0)->sw_if_index[VLIB_RX]);
 
-         clib_memcpy (t0->packet_data,
-                      vlib_buffer_get_current (b0),
-                      sizeof (t0->packet_data));
+         clib_memcpy_fast (t0->packet_data,
+                           vlib_buffer_get_current (b0),
+                           sizeof (t0->packet_data));
        }
       from += 1;
       n_left -= 1;
@@ -1213,23 +1248,15 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
                        ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
            }
 
-         /* TODO maybe move to lookup? */
          vnet_buffer (p0)->ip.fib_index =
-           vec_elt (im->fib_index_by_sw_if_index,
-                    vnet_buffer (p0)->sw_if_index[VLIB_RX]);
-         vnet_buffer (p0)->ip.fib_index =
-           (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
-            (u32) ~ 0) ? vnet_buffer (p0)->ip.
-           fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
+           vnet_buffer (p0)->sw_if_index[VLIB_TX] != ~0 ?
+           vnet_buffer (p0)->sw_if_index[VLIB_TX] :
+           vnet_buffer (p0)->ip.fib_index;
 
          vnet_buffer (p1)->ip.fib_index =
-           vec_elt (im->fib_index_by_sw_if_index,
-                    vnet_buffer (p1)->sw_if_index[VLIB_RX]);
-         vnet_buffer (p1)->ip.fib_index =
-           (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
-            (u32) ~ 0) ? vnet_buffer (p1)->ip.
-           fib_index : vnet_buffer (p1)->sw_if_index[VLIB_TX];
-
+           vnet_buffer (p1)->sw_if_index[VLIB_TX] != ~0 ?
+           vnet_buffer (p1)->sw_if_index[VLIB_TX] :
+           vnet_buffer (p1)->ip.fib_index;
 
        skip_checks:
 
@@ -1345,12 +1372,9 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
            }
 
          vnet_buffer (p0)->ip.fib_index =
-           vec_elt (im->fib_index_by_sw_if_index,
-                    vnet_buffer (p0)->sw_if_index[VLIB_RX]);
-         vnet_buffer (p0)->ip.fib_index =
-           (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
-            (u32) ~ 0) ? vnet_buffer (p0)->ip.
-           fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
+           vnet_buffer (p0)->sw_if_index[VLIB_TX] != ~0 ?
+           vnet_buffer (p0)->sw_if_index[VLIB_TX] :
+           vnet_buffer (p0)->ip.fib_index;
 
        skip_check:
 
@@ -1399,6 +1423,7 @@ VLIB_REGISTER_NODE (ip6_local_node, static) =
     [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
     [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
     [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
+    [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-reassembly",
   },
 };
 /* *INDENT-ON* */
@@ -1445,7 +1470,8 @@ ip6_register_protocol (u32 protocol, u32 node_index)
 }
 
 clib_error_t *
-ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
+ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index,
+                   u8 refresh)
 {
   vnet_main_t *vnm = vnet_get_main ();
   ip6_main_t *im = &ip6_main;
@@ -1485,6 +1511,8 @@ ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
     vlib_packet_template_get_packet (vm,
                                     &im->discover_neighbor_packet_template,
                                     &bi);
+  if (!h)
+    return clib_error_return (0, "ICMP6 NS packet allocation failed");
 
   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
 
@@ -1505,8 +1533,8 @@ ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
                                sw_if_index);
     }
 
-  clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
-              vec_len (hi->hw_address));
+  clib_memcpy_fast (h->link_layer_option.ethernet_address, hi->hw_address,
+                   vec_len (hi->hw_address));
 
   h->neighbor.icmp.checksum =
     ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
@@ -1526,7 +1554,7 @@ ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
   adj = adj_get (ai);
 
   /* Peer has been previously resolved, retrieve glean adj instead */
-  if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
+  if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE && refresh == 0)
     {
       adj_unlock (ai);
       ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP6,
@@ -1553,6 +1581,8 @@ typedef enum
 {
   IP6_REWRITE_NEXT_DROP,
   IP6_REWRITE_NEXT_ICMP_ERROR,
+  IP6_REWRITE_NEXT_FRAGMENT,
+  IP6_REWRITE_N_NEXT           /* Last */
 } ip6_rewrite_next_t;
 
 /**
@@ -1563,14 +1593,26 @@ typedef enum
 
 always_inline void
 ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
-              u16 adj_packet_bytes, u32 * next, u32 * error)
+              u16 adj_packet_bytes, bool is_locally_generated,
+              u32 * next, u32 * error)
 {
   if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
     {
-      *error = IP6_ERROR_MTU_EXCEEDED;
-      icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
-                                  adj_packet_bytes);
-      *next = IP6_REWRITE_NEXT_ICMP_ERROR;
+      if (is_locally_generated)
+       {
+         /* IP fragmentation */
+         ip_frag_set_vnet_buffer (b, adj_packet_bytes,
+                                  IP6_FRAG_NEXT_IP6_REWRITE, 0);
+         *next = IP6_REWRITE_NEXT_FRAGMENT;
+         *error = IP6_ERROR_MTU_EXCEEDED;
+       }
+      else
+       {
+         *error = IP6_ERROR_MTU_EXCEEDED;
+         icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
+                                      adj_packet_bytes);
+         *next = IP6_REWRITE_NEXT_ICMP_ERROR;
+       }
     }
 }
 
@@ -1588,7 +1630,7 @@ ip6_rewrite_inline (vlib_main_t * vm,
 
   n_left_from = frame->n_vectors;
   next_index = node->cached_next_index;
-  u32 thread_index = vlib_get_thread_index ();
+  u32 thread_index = vm->thread_index;
 
   while (n_left_from > 0)
     {
@@ -1602,6 +1644,7 @@ ip6_rewrite_inline (vlib_main_t * vm,
          u32 pi0, rw_len0, next0, error0, adj_index0;
          u32 pi1, rw_len1, next1, error1, adj_index1;
          u32 tx_sw_if_index0, tx_sw_if_index1;
+         bool is_locally_originated0, is_locally_originated1;
 
          /* Prefetch next iteration. */
          {
@@ -1640,7 +1683,9 @@ ip6_rewrite_inline (vlib_main_t * vm,
          error0 = error1 = IP6_ERROR_NONE;
          next0 = next1 = IP6_REWRITE_NEXT_DROP;
 
-         if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
+         is_locally_originated0 =
+           p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
+         if (PREDICT_TRUE (!is_locally_originated0))
            {
              i32 hop_limit0 = ip0->hop_limit;
 
@@ -1669,7 +1714,9 @@ ip6_rewrite_inline (vlib_main_t * vm,
            {
              p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
            }
-         if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
+         is_locally_originated1 =
+           p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
+         if (PREDICT_TRUE (!is_locally_originated1))
            {
              i32 hop_limit1 = ip1->hop_limit;
 
@@ -1722,11 +1769,11 @@ ip6_rewrite_inline (vlib_main_t * vm,
          ip6_mtu_check (p0, clib_net_to_host_u16 (ip0->payload_length) +
                         sizeof (ip6_header_t),
                         adj0[0].rewrite_header.max_l3_packet_bytes,
-                        &next0, &error0);
+                        is_locally_originated0, &next0, &error0);
          ip6_mtu_check (p1, clib_net_to_host_u16 (ip1->payload_length) +
                         sizeof (ip6_header_t),
                         adj1[0].rewrite_header.max_l3_packet_bytes,
-                        &next1, &error1);
+                        is_locally_originated1, &next1, &error1);
 
          /* Don't adjust the buffer for hop count issue; icmp-error node
           * wants to see the IP headerr */
@@ -1800,6 +1847,7 @@ ip6_rewrite_inline (vlib_main_t * vm,
          u32 pi0, rw_len0;
          u32 adj_index0, next0, error0;
          u32 tx_sw_if_index0;
+         bool is_locally_originated0;
 
          pi0 = to_next[0] = from[0];
 
@@ -1815,7 +1863,9 @@ ip6_rewrite_inline (vlib_main_t * vm,
          next0 = IP6_REWRITE_NEXT_DROP;
 
          /* Check hop limit */
-         if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
+         is_locally_originated0 =
+           p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
+         if (PREDICT_TRUE (!is_locally_originated0))
            {
              i32 hop_limit0 = ip0->hop_limit;
 
@@ -1863,7 +1913,7 @@ ip6_rewrite_inline (vlib_main_t * vm,
          ip6_mtu_check (p0, clib_net_to_host_u16 (ip0->payload_length) +
                         sizeof (ip6_header_t),
                         adj0[0].rewrite_header.max_l3_packet_bytes,
-                        &next0, &error0);
+                        is_locally_originated0, &next0, &error0);
 
          /* Don't adjust the buffer for hop count issue; icmp-error node
           * wants to see the IP header */
@@ -1929,6 +1979,16 @@ ip6_rewrite (vlib_main_t * vm,
     return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
 }
 
+static uword
+ip6_rewrite_bcast (vlib_main_t * vm,
+                  vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  if (adj_are_counters_enabled ())
+    return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
+  else
+    return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
+}
+
 static uword
 ip6_rewrite_mcast (vlib_main_t * vm,
                   vlib_node_runtime_t * node, vlib_frame_t * frame)
@@ -1968,29 +2028,36 @@ VLIB_REGISTER_NODE (ip6_midchain_node) =
   .format_trace = format_ip6_forward_next_trace,
   .sibling_of = "ip6-rewrite",
   };
-/* *INDENT-ON* */
 
 VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (ip6_rewrite_node) =
 {
   .function = ip6_rewrite,
   .name = "ip6-rewrite",
   .vector_size = sizeof (u32),
   .format_trace = format_ip6_rewrite_trace,
-  .n_next_nodes = 2,
+  .n_next_nodes = IP6_REWRITE_N_NEXT,
   .next_nodes =
   {
     [IP6_REWRITE_NEXT_DROP] = "ip6-drop",
     [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
+    [IP6_REWRITE_NEXT_FRAGMENT] = "ip6-frag",
   },
 };
-/* *INDENT-ON* */
 
 VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
 
-/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ip6_rewrite_bcast_node) = {
+  .function = ip6_rewrite_bcast,
+  .name = "ip6-rewrite-bcast",
+  .vector_size = sizeof (u32),
+
+  .format_trace = format_ip6_rewrite_trace,
+  .sibling_of = "ip6-rewrite",
+};
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_bcast_node, ip6_rewrite_bcast)
+
 VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
 {
   .function = ip6_rewrite_mcast,
@@ -1999,11 +2066,9 @@ VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
   .format_trace = format_ip6_rewrite_trace,
   .sibling_of = "ip6-rewrite",
 };
-/* *INDENT-ON* */
 
 VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
 {
   .function = ip6_mcast_midchain,
@@ -2012,9 +2077,9 @@ VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
   .format_trace = format_ip6_rewrite_trace,
   .sibling_of = "ip6-rewrite",
 };
-/* *INDENT-ON* */
 
 VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
+/* *INDENT-ON* */
 
 /*
  * Hop-by-Hop handling
@@ -2353,7 +2418,7 @@ ip6_hop_by_hop (vlib_main_t * vm,
                    ARRAY_LEN (t->option_data) ? trace_len :
                    ARRAY_LEN (t->option_data);
                  t->trace_len = trace_len;
-                 clib_memcpy (t->option_data, hbh0, trace_len);
+                 clib_memcpy_fast (t->option_data, hbh0, trace_len);
                }
              if (b1->flags & VLIB_BUFFER_IS_TRACED)
                {
@@ -2367,7 +2432,7 @@ ip6_hop_by_hop (vlib_main_t * vm,
                    ARRAY_LEN (t->option_data) ? trace_len :
                    ARRAY_LEN (t->option_data);
                  t->trace_len = trace_len;
-                 clib_memcpy (t->option_data, hbh1, trace_len);
+                 clib_memcpy_fast (t->option_data, hbh1, trace_len);
                }
 
            }
@@ -2448,7 +2513,7 @@ ip6_hop_by_hop (vlib_main_t * vm,
                ARRAY_LEN (t->option_data) ? trace_len :
                ARRAY_LEN (t->option_data);
              t->trace_len = trace_len;
-             clib_memcpy (t->option_data, hbh0, trace_len);
+             clib_memcpy_fast (t->option_data, hbh0, trace_len);
            }
 
          b0->error = error_node->errors[error0];
@@ -2483,8 +2548,8 @@ static clib_error_t *
 ip6_hop_by_hop_init (vlib_main_t * vm)
 {
   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
-  memset (hm->options, 0, sizeof (hm->options));
-  memset (hm->trace, 0, sizeof (hm->trace));
+  clib_memset (hm->options, 0, sizeof (hm->options));
+  clib_memset (hm->trace, 0, sizeof (hm->trace));
   hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
   return (0);
 }
@@ -2593,12 +2658,15 @@ ip6_lookup_init (vlib_main_t * vm)
   if (im->lookup_table_size == 0)
     im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
 
-  BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
+  clib_bihash_init_24_8 (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
                         "ip6 FIB fwding table",
                         im->lookup_table_nbuckets, im->lookup_table_size);
-  BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
+  clib_bihash_init_24_8 (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
                         "ip6 FIB non-fwding table",
                         im->lookup_table_nbuckets, im->lookup_table_size);
+  clib_bihash_init_40_8 (&im->ip6_mtable.ip6_mhash,
+                        "ip6 mFIB table",
+                        im->lookup_table_nbuckets, im->lookup_table_size);
 
   /* Create FIB with index 0 and table id of 0. */
   fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
@@ -2618,7 +2686,7 @@ ip6_lookup_init (vlib_main_t * vm)
   {
     icmp6_neighbor_solicitation_header_t p;
 
-    memset (&p, 0, sizeof (p));
+    clib_memset (&p, 0, sizeof (p));
 
     p.ip.ip_version_traffic_class_and_flow_label =
       clib_host_to_net_u32 (0x6 << 28);