IP Multicast FIB (mfib)

 - IPv[46] mfib tables with support for (*,G/m), (*,G) and (S,G) exact and longest prefix match
 - Replication represented via a new replicate DPO.
 - RPF configuration and data-plane checking
 - data-plane signals sent to listening control planes.

The functions of multicast forwarding entries differ from their unicast conterparts, so we introduce a new mfib_table_t and mfib_entry_t objects. However, we re-use the fib_path_list to resolve and build the entry's output list. the fib_path_list provides the service to construct a replicate DPO for multicast.

'make tests' is added to with two new suites; TEST=mfib, this is invocation of the CLI command 'test mfib' which deals with many path add/remove, flag set/unset scenarios, TEST=ip-mcast, data-plane forwarding tests.

Updated applications to use the new MIFB functions;
  - IPv6 NS/RA.
  - DHCPv6
 unit tests for these are undated accordingly.

Change-Id: I49ec37b01f1b170335a5697541c8fd30e6d3a961
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c
index 0298541..8f07fa5 100644
--- a/src/vnet/ethernet/arp.c
+++ b/src/vnet/ethernet/arp.c
@@ -23,6 +23,7 @@
 #include <vppinfra/mhash.h>
 #include <vnet/fib/ip4_fib.h>
 #include <vnet/adj/adj_nbr.h>
+#include <vnet/adj/adj_mcast.h>
 #include <vnet/mpls/mpls.h>
 
 /**
@@ -438,33 +439,74 @@
   arp_int = &am->ethernet_arp_by_sw_if_index[sw_if_index];
   e = arp_entry_find (arp_int, &adj->sub_type.nbr.next_hop.ip4);
 
-  if (NULL != e)
+  switch (adj->lookup_next_index)
     {
-      adj_nbr_walk_nh4 (sw_if_index,
-			&e->ip4_address, arp_mk_complete_walk, e);
-    }
-  else
-    {
+    case IP_LOOKUP_NEXT_ARP:
+    case IP_LOOKUP_NEXT_GLEAN:
+      if (NULL != e)
+	{
+	  adj_nbr_walk_nh4 (sw_if_index,
+			    &e->ip4_address, arp_mk_complete_walk, e);
+	}
+      else
+	{
+	  /*
+	   * no matching ARP entry.
+	   * construct the rewrite required to for an ARP packet, and stick
+	   * that in the adj's pipe to smoke.
+	   */
+	  adj_nbr_update_rewrite
+	    (ai,
+	     ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
+	     ethernet_build_rewrite
+	     (vnm,
+	      sw_if_index,
+	      VNET_LINK_ARP,
+	      VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
+
+	  /*
+	   * since the FIB has added this adj for a route, it makes sense it
+	   * may want to forward traffic sometime soon. Let's send a
+	   * speculative ARP. just one. If we were to do periodically that
+	   * wouldn't be bad either, but that's more code than i'm prepared to
+	   * write at this time for relatively little reward.
+	   */
+	  arp_nbr_probe (adj);
+	}
+      break;
+    case IP_LOOKUP_NEXT_MCAST:
       /*
-       * no matching ARP entry.
-       * construct the rewire required to for an ARP packet, and stick
-       * that in the adj's pipe to smoke.
+       * Construct a partial rewrite from the known ethernet mcast dest MAC
        */
-      adj_nbr_update_rewrite (ai,
-			      ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
-			      ethernet_build_rewrite (vnm,
-						      sw_if_index,
-						      VNET_LINK_ARP,
-						      VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
+      adj_mcast_update_rewrite
+	(ai,
+	 ethernet_build_rewrite (vnm,
+				 sw_if_index,
+				 adj->ia_link,
+				 ethernet_ip4_mcast_dst_addr ()));
 
       /*
-       * since the FIB has added this adj for a route, it makes sense it may
-       * want to forward traffic sometime soon. Let's send a speculative ARP.
-       * just one. If we were to do periodically that wouldn't be bad either,
-       * but that's more code than i'm prepared to write at this time for
-       * relatively little reward.
+       * Complete the remaining fields of the adj's rewrite to direct the
+       * complete of the rewrite at switch time by copying in the IP
+       * dst address's bytes.
+       * Ofset is 11 bytes from the end of the MAC header - which is three
+       * bytes into the desintation address. And we write 3 bytes.
        */
-      arp_nbr_probe (adj);
+      adj->rewrite_header.dst_mcast_offset = 11;
+      adj->rewrite_header.dst_mcast_n_bytes = 3;
+
+      break;
+
+    case IP_LOOKUP_NEXT_DROP:
+    case IP_LOOKUP_NEXT_PUNT:
+    case IP_LOOKUP_NEXT_LOCAL:
+    case IP_LOOKUP_NEXT_REWRITE:
+    case IP_LOOKUP_NEXT_LOAD_BALANCE:
+    case IP_LOOKUP_NEXT_MIDCHAIN:
+    case IP_LOOKUP_NEXT_ICMP_ERROR:
+    case IP_LOOKUP_N_NEXT:
+      ASSERT (0);
+      break;
     }
 }