mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-08 02:03:56 -06:00
e1000e: Perform software segmentation for loopback
e1000e didn't perform software segmentation for loopback if virtio-net header is enabled, which is wrong. To fix the problem, introduce net_tx_pkt_send_custom(), which allows the caller to specify whether offloading should be assumed or not. net_tx_pkt_send_custom() also allows the caller to provide a custom sending function. Packets with virtio-net headers and ones without virtio-net headers will be provided at the same time so the function can choose the preferred version. In case of e1000e loopback, it prefers to have virtio-net headers as they allows to skip the checksum verification if VIRTIO_NET_HDR_F_DATA_VALID is set. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Signed-off-by: Jason Wang <jasowang@redhat.com>
This commit is contained in:
parent
aac8f89dba
commit
ffbd2dbd8e
5 changed files with 88 additions and 51 deletions
|
@ -61,6 +61,10 @@ union e1000_rx_desc_union {
|
|||
union e1000_rx_desc_packet_split packet_split;
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt,
|
||||
bool has_vnet);
|
||||
|
||||
static inline void
|
||||
e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val);
|
||||
|
||||
|
@ -655,6 +659,15 @@ e1000e_setup_tx_offloads(E1000ECore *core, struct e1000e_tx *tx)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void e1000e_tx_pkt_callback(void *core,
|
||||
const struct iovec *iov,
|
||||
int iovcnt,
|
||||
const struct iovec *virt_iov,
|
||||
int virt_iovcnt)
|
||||
{
|
||||
e1000e_receive_internal(core, virt_iov, virt_iovcnt, true);
|
||||
}
|
||||
|
||||
static bool
|
||||
e1000e_tx_pkt_send(E1000ECore *core, struct e1000e_tx *tx, int queue_index)
|
||||
{
|
||||
|
@ -669,7 +682,8 @@ e1000e_tx_pkt_send(E1000ECore *core, struct e1000e_tx *tx, int queue_index)
|
|||
|
||||
if ((core->phy[0][MII_BMCR] & MII_BMCR_LOOPBACK) ||
|
||||
((core->mac[RCTL] & E1000_RCTL_LBM_MAC) == E1000_RCTL_LBM_MAC)) {
|
||||
return net_tx_pkt_send_loopback(tx->tx_pkt, queue);
|
||||
return net_tx_pkt_send_custom(tx->tx_pkt, false,
|
||||
e1000e_tx_pkt_callback, core);
|
||||
} else {
|
||||
return net_tx_pkt_send(tx->tx_pkt, queue);
|
||||
}
|
||||
|
@ -1674,6 +1688,13 @@ e1000e_rx_fix_l4_csum(E1000ECore *core, struct NetRxPkt *pkt)
|
|||
|
||||
ssize_t
|
||||
e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
return e1000e_receive_internal(core, iov, iovcnt, core->has_vnet);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt,
|
||||
bool has_vnet)
|
||||
{
|
||||
static const int maximum_ethernet_hdr_len = (ETH_HLEN + 4);
|
||||
|
||||
|
@ -1696,9 +1717,11 @@ e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt)
|
|||
}
|
||||
|
||||
/* Pull virtio header in */
|
||||
if (core->has_vnet) {
|
||||
if (has_vnet) {
|
||||
net_rx_pkt_set_vhdr_iovec(core->rx_pkt, iov, iovcnt);
|
||||
iov_ofs = sizeof(struct virtio_net_hdr);
|
||||
} else {
|
||||
net_rx_pkt_unset_vhdr(core->rx_pkt);
|
||||
}
|
||||
|
||||
filter_buf = iov->iov_base + iov_ofs;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue