aboutsummaryrefslogtreecommitdiff
path: root/hw/net
diff options
context:
space:
mode:
authorAkihiko Odaki <akihiko.odaki@daynix.com>2023-05-23 11:43:00 +0900
committerJason Wang <jasowang@redhat.com>2023-05-23 15:20:15 +0800
commitdc9ef1bf454811646b3ee6387f1b96f63f538a18 (patch)
tree5df52629d49e9128248344186090c8e34b803bec /hw/net
parent310a128eae12339f97f6c940a7ddf92f40d283e4 (diff)
downloadqemu-dc9ef1bf454811646b3ee6387f1b96f63f538a18.zip
qemu-dc9ef1bf454811646b3ee6387f1b96f63f538a18.tar.gz
qemu-dc9ef1bf454811646b3ee6387f1b96f63f538a18.tar.bz2
igb: Always copy ethernet header
igb_receive_internal() used to check the iov length to determine copy the iovs to a contiguous buffer, but the check is flawed in two ways: - It does not ensure that iovcnt > 0. - It does not take virtio-net header into consideration. The size of this copy is just 22 octets, which can be even less than the code size required for checks. This (wrong) optimization is probably not worth so just remove it. Removing this also allows igb to assume aligned accesses for the ethernet header. Fixes: 3a977deebe ("Intrdocue igb device emulation") 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>
Diffstat (limited to 'hw/net')
-rw-r--r--hw/net/igb_core.c43
1 files changed, 23 insertions, 20 deletions
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
index 21a8d9a..1123df9 100644
--- a/hw/net/igb_core.c
+++ b/hw/net/igb_core.c
@@ -67,6 +67,11 @@ typedef struct IGBTxPktVmdqCallbackContext {
NetClientState *nc;
} IGBTxPktVmdqCallbackContext;
+typedef struct L2Header {
+ struct eth_header eth;
+ struct vlan_header vlan;
+} L2Header;
+
static ssize_t
igb_receive_internal(IGBCore *core, const struct iovec *iov, int iovcnt,
bool has_vnet, bool *external_tx);
@@ -961,15 +966,16 @@ igb_rx_is_oversized(IGBCore *core, uint16_t qn, size_t size)
return size > (lpe ? max_ethernet_lpe_size : max_ethernet_vlan_size);
}
-static uint16_t igb_receive_assign(IGBCore *core, const struct eth_header *ehdr,
+static uint16_t igb_receive_assign(IGBCore *core, const L2Header *l2_header,
size_t size, E1000E_RSSInfo *rss_info,
bool *external_tx)
{
static const int ta_shift[] = { 4, 3, 2, 0 };
+ const struct eth_header *ehdr = &l2_header->eth;
uint32_t f, ra[2], *macp, rctl = core->mac[RCTL];
uint16_t queues = 0;
uint16_t oversized = 0;
- uint16_t vid = lduw_be_p(&PKT_GET_VLAN_HDR(ehdr)->h_tci) & VLAN_VID_MASK;
+ uint16_t vid = be16_to_cpu(l2_header->vlan.h_tci) & VLAN_VID_MASK;
bool accepted = false;
int i;
@@ -1590,14 +1596,13 @@ static ssize_t
igb_receive_internal(IGBCore *core, const struct iovec *iov, int iovcnt,
bool has_vnet, bool *external_tx)
{
- static const int maximum_ethernet_hdr_len = (ETH_HLEN + 4);
-
uint16_t queues = 0;
uint32_t n = 0;
- uint8_t min_buf[ETH_ZLEN];
+ union {
+ L2Header l2_header;
+ uint8_t octets[ETH_ZLEN];
+ } buf;
struct iovec min_iov;
- struct eth_header *ehdr;
- uint8_t *filter_buf;
size_t size, orig_size;
size_t iov_ofs = 0;
E1000E_RxRing rxr;
@@ -1623,24 +1628,21 @@ igb_receive_internal(IGBCore *core, const struct iovec *iov, int iovcnt,
net_rx_pkt_unset_vhdr(core->rx_pkt);
}
- filter_buf = iov->iov_base + iov_ofs;
orig_size = iov_size(iov, iovcnt);
size = orig_size - iov_ofs;
/* Pad to minimum Ethernet frame length */
- if (size < sizeof(min_buf)) {
- iov_to_buf(iov, iovcnt, iov_ofs, min_buf, size);
- memset(&min_buf[size], 0, sizeof(min_buf) - size);
+ if (size < sizeof(buf)) {
+ iov_to_buf(iov, iovcnt, iov_ofs, &buf, size);
+ memset(&buf.octets[size], 0, sizeof(buf) - size);
e1000x_inc_reg_if_not_full(core->mac, RUC);
- min_iov.iov_base = filter_buf = min_buf;
- min_iov.iov_len = size = sizeof(min_buf);
+ min_iov.iov_base = &buf;
+ min_iov.iov_len = size = sizeof(buf);
iovcnt = 1;
iov = &min_iov;
iov_ofs = 0;
- } else if (iov->iov_len < maximum_ethernet_hdr_len) {
- /* This is very unlikely, but may happen. */
- iov_to_buf(iov, iovcnt, iov_ofs, min_buf, maximum_ethernet_hdr_len);
- filter_buf = min_buf;
+ } else {
+ iov_to_buf(iov, iovcnt, iov_ofs, &buf, sizeof(buf.l2_header));
}
/* Discard oversized packets if !LPE and !SBP. */
@@ -1648,11 +1650,12 @@ igb_receive_internal(IGBCore *core, const struct iovec *iov, int iovcnt,
return orig_size;
}
- ehdr = PKT_GET_ETH_HDR(filter_buf);
- net_rx_pkt_set_packet_type(core->rx_pkt, get_eth_packet_type(ehdr));
+ net_rx_pkt_set_packet_type(core->rx_pkt,
+ get_eth_packet_type(&buf.l2_header.eth));
net_rx_pkt_set_protocols(core->rx_pkt, iov, iovcnt, iov_ofs);
- queues = igb_receive_assign(core, ehdr, size, &rss_info, external_tx);
+ queues = igb_receive_assign(core, &buf.l2_header, size,
+ &rss_info, external_tx);
if (!queues) {
trace_e1000e_rx_flt_dropped();
return orig_size;