e1000x: Share more Rx filtering logic

This saves some code and enables tracepoint for e1000's VLAN filtering.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Sriram Yagnaraman <sriram.yagnaraman@est.tech>
Signed-off-by: Jason Wang <jasowang@redhat.com>
This commit is contained in:
Akihiko Odaki 2023-05-23 11:43:06 +09:00 committed by Jason Wang
parent 0b11783014
commit e9e5b93069
6 changed files with 56 additions and 119 deletions

View File

@ -804,36 +804,11 @@ start_xmit(E1000State *s)
} }
static int static int
receive_filter(E1000State *s, const uint8_t *buf, int size) receive_filter(E1000State *s, const void *buf)
{ {
uint32_t rctl = s->mac_reg[RCTL]; return (!e1000x_is_vlan_packet(buf, s->mac_reg[VET]) ||
int isbcast = is_broadcast_ether_addr(buf); e1000x_rx_vlan_filter(s->mac_reg, PKT_GET_VLAN_HDR(buf))) &&
int ismcast = is_multicast_ether_addr(buf); e1000x_rx_group_filter(s->mac_reg, buf);
if (e1000x_is_vlan_packet(buf, le16_to_cpu(s->mac_reg[VET])) &&
e1000x_vlan_rx_filter_enabled(s->mac_reg)) {
uint16_t vid = lduw_be_p(&PKT_GET_VLAN_HDR(buf)->h_tci);
uint32_t vfta =
ldl_le_p((uint32_t *)(s->mac_reg + VFTA) +
((vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK));
if ((vfta & (1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK))) == 0) {
return 0;
}
}
if (!isbcast && !ismcast && (rctl & E1000_RCTL_UPE)) { /* promiscuous ucast */
return 1;
}
if (ismcast && (rctl & E1000_RCTL_MPE)) { /* promiscuous mcast */
return 1;
}
if (isbcast && (rctl & E1000_RCTL_BAM)) { /* broadcast enabled */
return 1;
}
return e1000x_rx_group_filter(s->mac_reg, buf);
} }
static void static void
@ -949,7 +924,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
return size; return size;
} }
if (!receive_filter(s, filter_buf, size)) { if (!receive_filter(s, filter_buf)) {
return size; return size;
} }

View File

@ -1034,48 +1034,11 @@ e1000e_rx_l4_cso_enabled(E1000ECore *core)
} }
static bool static bool
e1000e_receive_filter(E1000ECore *core, const uint8_t *buf, int size) e1000e_receive_filter(E1000ECore *core, const void *buf)
{ {
uint32_t rctl = core->mac[RCTL]; return (!e1000x_is_vlan_packet(buf, core->mac[VET]) ||
e1000x_rx_vlan_filter(core->mac, PKT_GET_VLAN_HDR(buf))) &&
if (e1000x_is_vlan_packet(buf, core->mac[VET]) && e1000x_rx_group_filter(core->mac, buf);
e1000x_vlan_rx_filter_enabled(core->mac)) {
uint16_t vid = lduw_be_p(&PKT_GET_VLAN_HDR(buf)->h_tci);
uint32_t vfta =
ldl_le_p((uint32_t *)(core->mac + VFTA) +
((vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK));
if ((vfta & (1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK))) == 0) {
trace_e1000e_rx_flt_vlan_mismatch(vid);
return false;
} else {
trace_e1000e_rx_flt_vlan_match(vid);
}
}
switch (net_rx_pkt_get_packet_type(core->rx_pkt)) {
case ETH_PKT_UCAST:
if (rctl & E1000_RCTL_UPE) {
return true; /* promiscuous ucast */
}
break;
case ETH_PKT_BCAST:
if (rctl & E1000_RCTL_BAM) {
return true; /* broadcast enabled */
}
break;
case ETH_PKT_MCAST:
if (rctl & E1000_RCTL_MPE) {
return true; /* promiscuous mcast */
}
break;
default:
g_assert_not_reached();
}
return e1000x_rx_group_filter(core->mac, buf);
} }
static inline void static inline void
@ -1736,7 +1699,7 @@ e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt,
net_rx_pkt_set_packet_type(core->rx_pkt, net_rx_pkt_set_packet_type(core->rx_pkt,
get_eth_packet_type(PKT_GET_ETH_HDR(buf))); get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
if (!e1000e_receive_filter(core, buf, size)) { if (!e1000e_receive_filter(core, buf)) {
trace_e1000e_rx_flt_dropped(); trace_e1000e_rx_flt_dropped();
return orig_size; return orig_size;
} }

View File

@ -58,32 +58,64 @@ bool e1000x_is_vlan_packet(const void *buf, uint16_t vet)
return res; return res;
} }
bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf) bool e1000x_rx_vlan_filter(uint32_t *mac, const struct vlan_header *vhdr)
{
if (e1000x_vlan_rx_filter_enabled(mac)) {
uint16_t vid = lduw_be_p(&vhdr->h_tci);
uint32_t vfta =
ldl_le_p((uint32_t *)(mac + VFTA) +
((vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK));
if ((vfta & (1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK))) == 0) {
trace_e1000x_rx_flt_vlan_mismatch(vid);
return false;
}
trace_e1000x_rx_flt_vlan_match(vid);
}
return true;
}
bool e1000x_rx_group_filter(uint32_t *mac, const struct eth_header *ehdr)
{ {
static const int mta_shift[] = { 4, 3, 2, 0 }; static const int mta_shift[] = { 4, 3, 2, 0 };
uint32_t f, ra[2], *rp, rctl = mac[RCTL]; uint32_t f, ra[2], *rp, rctl = mac[RCTL];
if (is_broadcast_ether_addr(ehdr->h_dest)) {
if (rctl & E1000_RCTL_BAM) {
return true;
}
} else if (is_multicast_ether_addr(ehdr->h_dest)) {
if (rctl & E1000_RCTL_MPE) {
return true;
}
} else {
if (rctl & E1000_RCTL_UPE) {
return true;
}
}
for (rp = mac + RA; rp < mac + RA + 32; rp += 2) { for (rp = mac + RA; rp < mac + RA + 32; rp += 2) {
if (!(rp[1] & E1000_RAH_AV)) { if (!(rp[1] & E1000_RAH_AV)) {
continue; continue;
} }
ra[0] = cpu_to_le32(rp[0]); ra[0] = cpu_to_le32(rp[0]);
ra[1] = cpu_to_le32(rp[1]); ra[1] = cpu_to_le32(rp[1]);
if (!memcmp(buf, (uint8_t *)ra, ETH_ALEN)) { if (!memcmp(ehdr->h_dest, (uint8_t *)ra, ETH_ALEN)) {
trace_e1000x_rx_flt_ucast_match((int)(rp - mac - RA) / 2, trace_e1000x_rx_flt_ucast_match((int)(rp - mac - RA) / 2,
MAC_ARG(buf)); MAC_ARG(ehdr->h_dest));
return true; return true;
} }
} }
trace_e1000x_rx_flt_ucast_mismatch(MAC_ARG(buf)); trace_e1000x_rx_flt_ucast_mismatch(MAC_ARG(ehdr->h_dest));
f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3]; f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff; f = (((ehdr->h_dest[5] << 8) | ehdr->h_dest[4]) >> f) & 0xfff;
if (mac[MTA + (f >> 5)] & (1 << (f & 0x1f))) { if (mac[MTA + (f >> 5)] & (1 << (f & 0x1f))) {
return true; return true;
} }
trace_e1000x_rx_flt_inexact_mismatch(MAC_ARG(buf), trace_e1000x_rx_flt_inexact_mismatch(MAC_ARG(ehdr->h_dest),
(rctl >> E1000_RCTL_MO_SHIFT) & 3, (rctl >> E1000_RCTL_MO_SHIFT) & 3,
f >> 5, f >> 5,
mac[MTA + (f >> 5)]); mac[MTA + (f >> 5)]);

View File

@ -107,7 +107,9 @@ bool e1000x_rx_ready(PCIDevice *d, uint32_t *mac);
bool e1000x_is_vlan_packet(const void *buf, uint16_t vet); bool e1000x_is_vlan_packet(const void *buf, uint16_t vet);
bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf); bool e1000x_rx_vlan_filter(uint32_t *mac, const struct vlan_header *vhdr);
bool e1000x_rx_group_filter(uint32_t *mac, const struct eth_header *ehdr);
bool e1000x_hw_rx_enabled(uint32_t *mac); bool e1000x_hw_rx_enabled(uint32_t *mac);

View File

@ -976,7 +976,6 @@ static uint16_t igb_receive_assign(IGBCore *core, const L2Header *l2_header,
uint16_t queues = 0; uint16_t queues = 0;
uint16_t oversized = 0; uint16_t oversized = 0;
uint16_t vid = be16_to_cpu(l2_header->vlan.h_tci) & VLAN_VID_MASK; uint16_t vid = be16_to_cpu(l2_header->vlan.h_tci) & VLAN_VID_MASK;
bool accepted = false;
int i; int i;
memset(rss_info, 0, sizeof(E1000E_RSSInfo)); memset(rss_info, 0, sizeof(E1000E_RSSInfo));
@ -986,16 +985,8 @@ static uint16_t igb_receive_assign(IGBCore *core, const L2Header *l2_header,
} }
if (e1000x_is_vlan_packet(ehdr, core->mac[VET] & 0xffff) && if (e1000x_is_vlan_packet(ehdr, core->mac[VET] & 0xffff) &&
e1000x_vlan_rx_filter_enabled(core->mac)) { !e1000x_rx_vlan_filter(core->mac, PKT_GET_VLAN_HDR(ehdr))) {
uint32_t vfta = return queues;
ldl_le_p((uint32_t *)(core->mac + VFTA) +
((vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK));
if ((vfta & (1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK))) == 0) {
trace_e1000e_rx_flt_vlan_mismatch(vid);
return queues;
} else {
trace_e1000e_rx_flt_vlan_match(vid);
}
} }
if (core->mac[MRQC] & 1) { if (core->mac[MRQC] & 1) {
@ -1103,33 +1094,7 @@ static uint16_t igb_receive_assign(IGBCore *core, const L2Header *l2_header,
} }
} }
} else { } else {
switch (net_rx_pkt_get_packet_type(core->rx_pkt)) { bool accepted = e1000x_rx_group_filter(core->mac, ehdr);
case ETH_PKT_UCAST:
if (rctl & E1000_RCTL_UPE) {
accepted = true; /* promiscuous ucast */
}
break;
case ETH_PKT_BCAST:
if (rctl & E1000_RCTL_BAM) {
accepted = true; /* broadcast enabled */
}
break;
case ETH_PKT_MCAST:
if (rctl & E1000_RCTL_MPE) {
accepted = true; /* promiscuous mcast */
}
break;
default:
g_assert_not_reached();
}
if (!accepted) {
accepted = e1000x_rx_group_filter(core->mac, ehdr->h_dest);
}
if (!accepted) { if (!accepted) {
for (macp = core->mac + RA2; macp < core->mac + RA2 + 16; macp += 2) { for (macp = core->mac + RA2; macp < core->mac + RA2 + 16; macp += 2) {
if (!(macp[1] & E1000_RAH_AV)) { if (!(macp[1] & E1000_RAH_AV)) {

View File

@ -106,6 +106,8 @@ e1000_receiver_overrun(size_t s, uint32_t rdh, uint32_t rdt) "Receiver overrun:
# e1000x_common.c # e1000x_common.c
e1000x_rx_can_recv_disabled(bool link_up, bool rx_enabled, bool pci_master) "link_up: %d, rx_enabled %d, pci_master %d" e1000x_rx_can_recv_disabled(bool link_up, bool rx_enabled, bool pci_master) "link_up: %d, rx_enabled %d, pci_master %d"
e1000x_vlan_is_vlan_pkt(bool is_vlan_pkt, uint16_t eth_proto, uint16_t vet) "Is VLAN packet: %d, ETH proto: 0x%X, VET: 0x%X" e1000x_vlan_is_vlan_pkt(bool is_vlan_pkt, uint16_t eth_proto, uint16_t vet) "Is VLAN packet: %d, ETH proto: 0x%X, VET: 0x%X"
e1000x_rx_flt_vlan_mismatch(uint16_t vid) "VID mismatch: 0x%X"
e1000x_rx_flt_vlan_match(uint16_t vid) "VID match: 0x%X"
e1000x_rx_flt_ucast_match(uint32_t idx, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x" e1000x_rx_flt_ucast_match(uint32_t idx, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x"
e1000x_rx_flt_ucast_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x" e1000x_rx_flt_ucast_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x"
e1000x_rx_flt_inexact_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint32_t mo, uint32_t mta, uint32_t mta_val) "inexact mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] 0x%x" e1000x_rx_flt_inexact_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint32_t mo, uint32_t mta, uint32_t mta_val) "inexact mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] 0x%x"
@ -154,8 +156,6 @@ e1000e_rx_can_recv_rings_full(void) "Cannot receive: all rings are full"
e1000e_rx_can_recv(void) "Can receive" e1000e_rx_can_recv(void) "Can receive"
e1000e_rx_has_buffers(int ridx, uint32_t free_desc, size_t total_size, uint32_t desc_buf_size) "ring #%d: free descr: %u, packet size %zu, descr buffer size %u" e1000e_rx_has_buffers(int ridx, uint32_t free_desc, size_t total_size, uint32_t desc_buf_size) "ring #%d: free descr: %u, packet size %zu, descr buffer size %u"
e1000e_rx_null_descriptor(void) "Null RX descriptor!!" e1000e_rx_null_descriptor(void) "Null RX descriptor!!"
e1000e_rx_flt_vlan_mismatch(uint16_t vid) "VID mismatch: 0x%X"
e1000e_rx_flt_vlan_match(uint16_t vid) "VID match: 0x%X"
e1000e_rx_desc_ps_read(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) "buffers: [0x%"PRIx64", 0x%"PRIx64", 0x%"PRIx64", 0x%"PRIx64"]" e1000e_rx_desc_ps_read(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) "buffers: [0x%"PRIx64", 0x%"PRIx64", 0x%"PRIx64", 0x%"PRIx64"]"
e1000e_rx_desc_ps_write(uint16_t a0, uint16_t a1, uint16_t a2, uint16_t a3) "bytes written: [%u, %u, %u, %u]" e1000e_rx_desc_ps_write(uint16_t a0, uint16_t a1, uint16_t a2, uint16_t a3) "bytes written: [%u, %u, %u, %u]"
e1000e_rx_desc_buff_sizes(uint32_t b0, uint32_t b1, uint32_t b2, uint32_t b3) "buffer sizes: [%u, %u, %u, %u]" e1000e_rx_desc_buff_sizes(uint32_t b0, uint32_t b1, uint32_t b2, uint32_t b3) "buffer sizes: [%u, %u, %u, %u]"