Mcast rewrite no memcpy
[vpp.git] / src / vnet / ethernet / arp.c
index d8ae844..2f81da3 100644 (file)
@@ -479,28 +479,30 @@ arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
        }
       break;
     case IP_LOOKUP_NEXT_MCAST:
-      /*
-       * Construct a partial rewrite from the known ethernet mcast dest MAC
-       */
-      adj_mcast_update_rewrite
-       (ai,
-        ethernet_build_rewrite (vnm,
-                                sw_if_index,
-                                adj->ia_link,
-                                ethernet_ip4_mcast_dst_addr ()));
-
-      /*
-       * 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.
-       */
-      adj->rewrite_header.dst_mcast_offset = 11;
-      adj->rewrite_header.dst_mcast_n_bytes = 3;
-
-      break;
+      {
+       /*
+        * Construct a partial rewrite from the known ethernet mcast dest MAC
+        */
+       u8 *rewrite;
+       u8 offset;
+
+       rewrite = ethernet_build_rewrite (vnm,
+                                         sw_if_index,
+                                         adj->ia_link,
+                                         ethernet_ip4_mcast_dst_addr ());
+       offset = vec_len (rewrite) - 2;
+
+       /*
+        * 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 2 bytes into the MAC desintation address. And we copy 23 bits
+        * from the address.
+        */
+       adj_mcast_update_rewrite (ai, rewrite, offset, 0x007fffff);
 
+       break;
+      }
     case IP_LOOKUP_NEXT_DROP:
     case IP_LOOKUP_NEXT_PUNT:
     case IP_LOOKUP_NEXT_LOCAL:
@@ -1016,7 +1018,6 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
          vnet_hw_interface_t *hw_if0;
          ethernet_arp_header_t *arp0;
          ethernet_header_t *eth0;
-         ip_adjacency_t *adj0;
          ip4_address_t *if_addr0, proxy_src;
          u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
          u8 is_request0, dst_is_local0, is_unnum0;
@@ -1073,6 +1074,11 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
                                          32);
          dst_flags = fib_entry_get_flags (dst_fei);
 
+         src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
+                                         &arp0->ip4_over_ethernet[0].ip4,
+                                         32);
+         src_flags = fib_entry_get_flags (src_fei);
+
          conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei);
 
          if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
@@ -1085,11 +1091,6 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
          is_unnum0 = sw_if_index0 != conn_sw_if_index0;
 
          /* Source must also be local to subnet of matching interface address. */
-         src_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
-                                         &arp0->ip4_over_ethernet[0].ip4,
-                                         32);
-         src_flags = fib_entry_get_flags (src_fei);
-
          if (!((FIB_ENTRY_FLAG_ATTACHED & src_flags) ||
                (FIB_ENTRY_FLAG_CONNECTED & src_flags)))
            {
@@ -1187,25 +1188,62 @@ arp_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
          /* get the adj from the destination's covering connected */
          if (NULL == pa)
            {
-             adj0 =
-               adj_get (fib_entry_get_adj_for_source
-                        (ip4_fib_table_lookup
-                         (ip4_fib_get (fib_index0),
-                          &arp0->ip4_over_ethernet[1].ip4, 31),
-                         FIB_SOURCE_INTERFACE));
-             if (adj0->lookup_next_index != IP_LOOKUP_NEXT_GLEAN)
-               {
-                 error0 = ETHERNET_ARP_ERROR_missing_interface_address;
-                 goto drop2;
-               }
              if (is_unnum0)
                {
                  if (!arp_unnumbered (p0, pi0, eth0, conn_sw_if_index0))
                    goto drop2;
                }
              else
-               vlib_buffer_advance (p0, -adj0->rewrite_header.data_bytes);
+               {
+                 ip_adjacency_t *adj0 = NULL;
+                 adj_index_t ai;
+
+                 if (FIB_ENTRY_FLAG_ATTACHED & src_flags)
+                   {
+                     /*
+                      * If the source is attached use the adj from that source.
+                      */
+                     ai = fib_entry_get_adj (src_fei);
+                     if (ADJ_INDEX_INVALID != ai)
+                       {
+                         adj0 = adj_get (ai);
+                       }
+                   }
+                 else
+                   {
+                     /*
+                      * Get the glean adj from the cover. This is presumably interface
+                      * sourced, and therefre needs to be a glean adj.
+                      */
+                     ai = fib_entry_get_adj_for_source
+                       (ip4_fib_table_lookup
+                        (ip4_fib_get (fib_index0),
+                         &arp0->ip4_over_ethernet[1].ip4, 31),
+                        FIB_SOURCE_INTERFACE);
+
+                     if (ADJ_INDEX_INVALID != ai)
+                       {
+                         adj0 = adj_get (ai);
+
+                         if (adj0->lookup_next_index == IP_LOOKUP_NEXT_GLEAN)
+                           {
+                             adj0 = NULL;
+                           }
+                       }
+                   }
+                 if (NULL != adj0)
+                   {
+                     vlib_buffer_advance (p0,
+                                          -adj0->rewrite_header.data_bytes);
+                   }
+                 else
+                   {
+                     error0 = ETHERNET_ARP_ERROR_missing_interface_address;
+                     goto drop2;
+                   }
+               }
            }
+
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
                                           n_left_to_next, pi0, next0);