ethernet: all dmac checks include secondary addrs
Type: feature In ethernet_input_inline(), when verifying that the destination mac address on a received packet matches the mac address of the interface where the packet was received, check the secondary addresses on the interface if the primary address does not match. This was done previously for eth_input_single_int(). Change-Id: I45716184dd789d83852271f9c79cedf5f6cbf75b Signed-off-by: Matthew Smith <mgsmith@netgate.com>
This commit is contained in:

committed by
Damjan Marion

parent
9db6ada779
commit
42bde459b6
@ -194,6 +194,12 @@ parse_header (ethernet_input_variant_t variant,
|
||||
ethernet_buffer_set_vlan_count (b0, vlan_count);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Determine the subinterface for this packet, given the result of the
|
||||
// vlan table lookups and vlan header parsing. Check the most specific
|
||||
// matches first.
|
||||
@ -213,22 +219,31 @@ identify_subint (vnet_hw_interface_t * hi,
|
||||
|
||||
if (matched)
|
||||
{
|
||||
|
||||
// Perform L3 my-mac filter
|
||||
// A unicast packet arriving on an L3 interface must have a dmac matching the interface mac.
|
||||
// This is required for promiscuous mode, else we will forward packets we aren't supposed to.
|
||||
if (!(*is_l2))
|
||||
{
|
||||
u64 dmacs[2];
|
||||
u8 dmacs_bad[2];
|
||||
ethernet_header_t *e0;
|
||||
e0 = (void *) (b0->data + vnet_buffer (b0)->l2_hdr_offset);
|
||||
ethernet_interface_t *ei0;
|
||||
|
||||
if (!(ethernet_address_cast (e0->dst_address)))
|
||||
{
|
||||
if (!ethernet_mac_address_equal ((u8 *) e0, hi->hw_address))
|
||||
{
|
||||
*error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
|
||||
}
|
||||
}
|
||||
e0 = (void *) (b0->data + vnet_buffer (b0)->l2_hdr_offset);
|
||||
dmacs[0] = *(u64 *) e0;
|
||||
ei0 = ethernet_get_interface (ðernet_main, hi->hw_if_index);
|
||||
|
||||
if (ei0 && vec_len (ei0->secondary_addrs))
|
||||
ethernet_input_inline_dmac_check (hi, dmacs, dmacs_bad,
|
||||
1 /* n_packets */ , ei0,
|
||||
1 /* have_sec_dmac */ );
|
||||
else
|
||||
ethernet_input_inline_dmac_check (hi, dmacs, dmacs_bad,
|
||||
1 /* n_packets */ , ei0,
|
||||
0 /* have_sec_dmac */ );
|
||||
|
||||
if (dmacs_bad[0])
|
||||
*error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
|
||||
}
|
||||
|
||||
// Check for down subinterface
|
||||
@ -619,14 +634,14 @@ is_dmac_bad_x4 (u64 * dmacs, u64 hwaddr)
|
||||
r0 = (r0 != u64x4_splat (hwaddr)) & ((r0 & u64x4_splat (DMAC_IGBIT)) == 0);
|
||||
return u8x32_msb_mask ((u8x32) (r0));
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
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)
|
||||
@ -665,6 +680,44 @@ eth_input_sec_dmac_check_x4 (u64 hwaddr, u64 * dmac, u8 * dmac_bad)
|
||||
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,
|
||||
@ -1157,6 +1210,7 @@ ethernet_input_inline (vlib_main_t * vm,
|
||||
u32 cached_sw_if_index = ~0;
|
||||
u32 cached_is_l2 = 0; /* shut up gcc */
|
||||
vnet_hw_interface_t *hi = NULL; /* used for main interface only */
|
||||
ethernet_interface_t *ei = NULL;
|
||||
vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
|
||||
vlib_buffer_t **b = bufs;
|
||||
|
||||
@ -1194,6 +1248,8 @@ ethernet_input_inline (vlib_main_t * vm,
|
||||
qinq_intf_t *qinq_intf0, *qinq_intf1;
|
||||
u32 is_l20, is_l21;
|
||||
ethernet_header_t *e0, *e1;
|
||||
u64 dmacs[2];
|
||||
u8 dmacs_bad[2];
|
||||
|
||||
/* Prefetch next iteration. */
|
||||
{
|
||||
@ -1251,6 +1307,7 @@ ethernet_input_inline (vlib_main_t * vm,
|
||||
{
|
||||
cached_sw_if_index = sw_if_index0;
|
||||
hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
|
||||
ei = ethernet_get_interface (em, hi->hw_if_index);
|
||||
intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
|
||||
subint0 = &intf0->untagged_subint;
|
||||
cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
|
||||
@ -1273,14 +1330,27 @@ ethernet_input_inline (vlib_main_t * vm,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ethernet_address_cast (e0->dst_address) &&
|
||||
(hi->hw_address != 0) &&
|
||||
!ethernet_mac_address_equal ((u8 *) e0, hi->hw_address))
|
||||
dmacs[0] = *(u64 *) e0;
|
||||
dmacs[1] = *(u64 *) e1;
|
||||
|
||||
if (ei && vec_len (ei->secondary_addrs))
|
||||
ethernet_input_inline_dmac_check (hi, dmacs,
|
||||
dmacs_bad,
|
||||
2 /* n_packets */ ,
|
||||
ei,
|
||||
1 /* have_sec_dmac */ );
|
||||
else
|
||||
ethernet_input_inline_dmac_check (hi, dmacs,
|
||||
dmacs_bad,
|
||||
2 /* n_packets */ ,
|
||||
ei,
|
||||
0 /* have_sec_dmac */ );
|
||||
|
||||
if (dmacs_bad[0])
|
||||
error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
|
||||
if (!ethernet_address_cast (e1->dst_address) &&
|
||||
(hi->hw_address != 0) &&
|
||||
!ethernet_mac_address_equal ((u8 *) e1, hi->hw_address))
|
||||
if (dmacs_bad[1])
|
||||
error1 = ETHERNET_ERROR_L3_MAC_MISMATCH;
|
||||
|
||||
vlib_buffer_advance (b0, sizeof (ethernet_header_t));
|
||||
determine_next_node (em, variant, 0, type0, b0,
|
||||
&error0, &next0);
|
||||
@ -1437,6 +1507,8 @@ ethernet_input_inline (vlib_main_t * vm,
|
||||
qinq_intf_t *qinq_intf0;
|
||||
ethernet_header_t *e0;
|
||||
u32 is_l20;
|
||||
u64 dmacs[2];
|
||||
u8 dmacs_bad[2];
|
||||
|
||||
// Prefetch next iteration
|
||||
if (n_left_from > 1)
|
||||
@ -1478,6 +1550,7 @@ ethernet_input_inline (vlib_main_t * vm,
|
||||
{
|
||||
cached_sw_if_index = sw_if_index0;
|
||||
hi = vnet_get_sup_hw_interface (vnm, sw_if_index0);
|
||||
ei = ethernet_get_interface (em, hi->hw_if_index);
|
||||
intf0 = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
|
||||
subint0 = &intf0->untagged_subint;
|
||||
cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2;
|
||||
@ -1495,10 +1568,24 @@ ethernet_input_inline (vlib_main_t * vm,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ethernet_address_cast (e0->dst_address) &&
|
||||
(hi->hw_address != 0) &&
|
||||
!ethernet_mac_address_equal ((u8 *) e0, hi->hw_address))
|
||||
dmacs[0] = *(u64 *) e0;
|
||||
|
||||
if (ei && vec_len (ei->secondary_addrs))
|
||||
ethernet_input_inline_dmac_check (hi, dmacs,
|
||||
dmacs_bad,
|
||||
1 /* n_packets */ ,
|
||||
ei,
|
||||
1 /* have_sec_dmac */ );
|
||||
else
|
||||
ethernet_input_inline_dmac_check (hi, dmacs,
|
||||
dmacs_bad,
|
||||
1 /* n_packets */ ,
|
||||
ei,
|
||||
0 /* have_sec_dmac */ );
|
||||
|
||||
if (dmacs_bad[0])
|
||||
error0 = ETHERNET_ERROR_L3_MAC_MISMATCH;
|
||||
|
||||
vlib_buffer_advance (b0, sizeof (ethernet_header_t));
|
||||
determine_next_node (em, variant, 0, type0, b0,
|
||||
&error0, &next0);
|
||||
|
Reference in New Issue
Block a user