+ l->err = ETHERNET_ERROR_L3_MAC_MISMATCH;
+ next[0] = ETHERNET_INPUT_NEXT_PUNT;
+ }
+ else
+ next[0] = l->next;
+
+ vlib_buffer_advance (b, l->adv);
+ vnet_buffer (b)->l2.l2_len = l->len;
+ vnet_buffer (b)->l3_hdr_offset = vnet_buffer (b)->l2_hdr_offset + l->len;
+
+ if (l->err == ETHERNET_ERROR_NONE)
+ {
+ vnet_buffer (b)->sw_if_index[VLIB_RX] = l->sw_if_index;
+ ethernet_buffer_set_vlan_count (b, l->n_tags);
+ }
+ else
+ b->error = node->errors[l->err];
+
+ /* update counters */
+ l->n_packets += 1;
+ l->n_bytes += vlib_buffer_length_in_chain (vm, b);
+}
+
+#define DMAC_MASK clib_net_to_host_u64 (0xFFFFFFFFFFFF0000)
+#define DMAC_IGBIT clib_net_to_host_u64 (0x0100000000000000)
+
+#ifdef CLIB_HAVE_VEC256
+static_always_inline u32
+is_dmac_bad_x4 (u64 * dmacs, u64 hwaddr)
+{
+ u64x4 r0 = u64x4_load_unaligned (dmacs) & u64x4_splat (DMAC_MASK);
+ r0 = (r0 != u64x4_splat (hwaddr)) & ((r0 & u64x4_splat (DMAC_IGBIT)) == 0);
+ return u8x32_msb_mask ((u8x32) (r0));
+}
+#else
+static_always_inline u8
+is_dmac_bad (u64 dmac, u64 hwaddr)
+{
+ u64 r0 = dmac & DMAC_MASK;
+ return (r0 != hwaddr) && ((r0 & DMAC_IGBIT) == 0);
+}
+#endif
+
+static_always_inline u8
+is_sec_dmac_bad (u64 dmac, u64 hwaddr)
+{
+ return ((dmac & DMAC_MASK) != hwaddr);
+}
+
+#ifdef CLIB_HAVE_VEC256
+static_always_inline u32
+is_sec_dmac_bad_x4 (u64 * dmacs, u64 hwaddr)
+{
+ u64x4 r0 = u64x4_load_unaligned (dmacs) & u64x4_splat (DMAC_MASK);
+ r0 = (r0 != u64x4_splat (hwaddr));
+ return u8x32_msb_mask ((u8x32) (r0));
+}
+#endif
+
+static_always_inline u8
+eth_input_sec_dmac_check_x1 (u64 hwaddr, u64 * dmac, u8 * dmac_bad)
+{
+ dmac_bad[0] &= is_sec_dmac_bad (dmac[0], hwaddr);
+ return dmac_bad[0];
+}
+
+static_always_inline u32
+eth_input_sec_dmac_check_x4 (u64 hwaddr, u64 * dmac, u8 * dmac_bad)
+{
+#ifdef CLIB_HAVE_VEC256
+ *(u32 *) (dmac_bad + 0) &= is_sec_dmac_bad_x4 (dmac + 0, hwaddr);
+#else
+ dmac_bad[0] &= is_sec_dmac_bad (dmac[0], hwaddr);
+ dmac_bad[1] &= is_sec_dmac_bad (dmac[1], hwaddr);
+ dmac_bad[2] &= is_sec_dmac_bad (dmac[2], hwaddr);
+ dmac_bad[3] &= is_sec_dmac_bad (dmac[3], hwaddr);
+#endif
+ return *(u32 *) dmac_bad;
+}
+
+static_always_inline void
+eth_input_process_frame_dmac_check (vnet_hw_interface_t * hi,
+ u64 * dmacs, u8 * dmacs_bad,
+ u32 n_packets, ethernet_interface_t * ei,
+ u8 have_sec_dmac)
+{
+ u64 hwaddr = (*(u64 *) hi->hw_address) & DMAC_MASK;
+ u64 *dmac = dmacs;
+ u8 *dmac_bad = dmacs_bad;
+ u32 bad = 0;
+ i32 n_left = n_packets;
+
+#ifdef CLIB_HAVE_VEC256
+ while (n_left > 0)
+ {
+ bad |= *(u32 *) (dmac_bad + 0) = is_dmac_bad_x4 (dmac + 0, hwaddr);
+ bad |= *(u32 *) (dmac_bad + 4) = is_dmac_bad_x4 (dmac + 4, hwaddr);
+
+ /* next */
+ dmac += 8;
+ dmac_bad += 8;
+ n_left -= 8;
+ }
+#else
+ while (n_left > 0)
+ {
+ bad |= dmac_bad[0] = is_dmac_bad (dmac[0], hwaddr);
+ bad |= dmac_bad[1] = is_dmac_bad (dmac[1], hwaddr);
+ bad |= dmac_bad[2] = is_dmac_bad (dmac[2], hwaddr);
+ bad |= dmac_bad[3] = is_dmac_bad (dmac[3], hwaddr);
+
+ /* next */
+ dmac += 4;
+ dmac_bad += 4;
+ n_left -= 4;
+ }
+#endif
+
+ if (have_sec_dmac && bad)
+ {
+ mac_address_t *addr;
+
+ vec_foreach (addr, ei->secondary_addrs)
+ {
+ u64 hwaddr = ((u64 *) addr)[0] & DMAC_MASK;
+ i32 n_left = n_packets;
+ u64 *dmac = dmacs;
+ u8 *dmac_bad = dmacs_bad;
+
+ bad = 0;
+
+ while (n_left > 0)
+ {
+ int adv = 0;
+ int n_bad;
+
+ /* skip any that have already matched */
+ if (!dmac_bad[0])
+ {
+ dmac += 1;
+ dmac_bad += 1;
+ n_left -= 1;
+ continue;
+ }
+
+ n_bad = clib_min (4, n_left);
+
+ /* If >= 4 left, compare 4 together */
+ if (n_bad == 4)
+ {
+ bad |= eth_input_sec_dmac_check_x4 (hwaddr, dmac, dmac_bad);
+ adv = 4;
+ n_bad = 0;
+ }
+
+ /* handle individually */
+ while (n_bad > 0)
+ {
+ bad |= eth_input_sec_dmac_check_x1 (hwaddr, dmac + adv,
+ dmac_bad + adv);
+ adv += 1;
+ n_bad -= 1;
+ }
+
+ dmac += adv;
+ dmac_bad += adv;
+ n_left -= adv;
+ }
+
+ if (!bad) /* can stop looping if everything matched */
+ break;
+ }
+ }
+}
+
+/* process frame of buffers, store ethertype into array and update
+ buffer metadata fields depending on interface being l2 or l3 assuming that
+ packets are untagged. For tagged packets those fields are updated later.
+ Optionally store Destionation MAC address and tag data into arrays
+ for further processing */
+
+STATIC_ASSERT (VLIB_FRAME_SIZE % 8 == 0,
+ "VLIB_FRAME_SIZE must be power of 8");
+static_always_inline void
+eth_input_process_frame (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vnet_hw_interface_t * hi,
+ u32 * buffer_indices, u32 n_packets, int main_is_l3,
+ int ip4_cksum_ok, int dmac_check)
+{
+ ethernet_main_t *em = ðernet_main;
+ u16 nexts[VLIB_FRAME_SIZE], *next;
+ u16 etypes[VLIB_FRAME_SIZE], *etype = etypes;
+ u64 dmacs[VLIB_FRAME_SIZE], *dmac = dmacs;
+ u8 dmacs_bad[VLIB_FRAME_SIZE];
+ u64 tags[VLIB_FRAME_SIZE], *tag = tags;
+ u16 slowpath_indices[VLIB_FRAME_SIZE];
+ u16 n_slowpath, i;
+ u16 next_ip4, next_ip6, next_mpls, next_l2;
+ u16 et_ip4 = clib_host_to_net_u16 (ETHERNET_TYPE_IP4);
+ u16 et_ip6 = clib_host_to_net_u16 (ETHERNET_TYPE_IP6);
+ u16 et_mpls = clib_host_to_net_u16 (ETHERNET_TYPE_MPLS);
+ u16 et_vlan = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
+ u16 et_dot1ad = clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD);
+ i32 n_left = n_packets;
+ vlib_buffer_t *b[20];
+ u32 *from;
+ ethernet_interface_t *ei = ethernet_get_interface (em, hi->hw_if_index);
+
+ from = buffer_indices;
+
+ while (n_left >= 20)
+ {
+ vlib_buffer_t **ph = b + 16, **pd = b + 8;