+#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));
+}
+#endif
+
+static_always_inline u8
+is_dmac_bad (u64 dmac, u64 hwaddr)
+{
+ u64 r0 = dmac & DMAC_MASK;
+ return (r0 != hwaddr) && ((r0 & DMAC_IGBIT) == 0);
+}
+
+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;
+}
+
+/*
+ * DMAC check for ethernet_input_inline()
+ *
+ * dmacs and dmacs_bad are arrays that are 2 elements long
+ * n_packets should be 1 or 2 for ethernet_input_inline()
+ */
+static_always_inline void
+ethernet_input_inline_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;
+ u8 bad = 0;
+
+ dmacs_bad[0] = is_dmac_bad (dmacs[0], hwaddr);
+ dmacs_bad[1] = ((n_packets > 1) & is_dmac_bad (dmacs[1], hwaddr));
+
+ bad = dmacs_bad[0] | dmacs_bad[1];
+
+ if (PREDICT_FALSE (bad && have_sec_dmac))
+ {
+ mac_address_t *sec_addr;
+
+ vec_foreach (sec_addr, ei->secondary_addrs)
+ {
+ hwaddr = (*(u64 *) sec_addr) & DMAC_MASK;
+
+ bad = (eth_input_sec_dmac_check_x1 (hwaddr, dmacs, dmacs_bad) |
+ eth_input_sec_dmac_check_x1 (hwaddr, dmacs + 1,
+ dmacs_bad + 1));
+
+ if (!bad)
+ return;
+ }
+ }
+}
+
+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;
+ }
+ }
+}
+