-----BEGIN PGP SIGNATURE-----

iQEzBAABCAAdFiEEIV1G9IJGaJ7HfzVi7wSWWzmNYhEFAmkWo9EACgkQ7wSWWzmN
 YhHargf/Uf801PmKskryVENF9sVe6u5NxJZlT3BUJVsSTGitucBIHWZ5J7MMR1lw
 If4tfMho3BX5Wrtl5GuCEzolk9pCz3wmSN6nyOU25C5tKaoJ/uR135K25D0CwVmD
 eTOyg+gKktVfogXxJ/zwZpRHMq4XXrk/C2ZP41r/CdcLyaeuDS9GIbd/q4N7f3vv
 bEsVqECzjEwWr2JBY9SD0xlIRp3nWwEvRsgRZPzBiQzfjSTlImqGLUsxIpF5V2LV
 1BU0V/FShWyrwckBXSqCWBUh6uBUGgEl6qKnK4vH7+ed4Kd9giyp1vWAFEjHgIg+
 gZtPaT/MJQOtLyCuzfuSdUpAzz5Sfw==
 =Is8a
 -----END PGP SIGNATURE-----

Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging

# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCAAdFiEEIV1G9IJGaJ7HfzVi7wSWWzmNYhEFAmkWo9EACgkQ7wSWWzmN
# YhHargf/Uf801PmKskryVENF9sVe6u5NxJZlT3BUJVsSTGitucBIHWZ5J7MMR1lw
# If4tfMho3BX5Wrtl5GuCEzolk9pCz3wmSN6nyOU25C5tKaoJ/uR135K25D0CwVmD
# eTOyg+gKktVfogXxJ/zwZpRHMq4XXrk/C2ZP41r/CdcLyaeuDS9GIbd/q4N7f3vv
# bEsVqECzjEwWr2JBY9SD0xlIRp3nWwEvRsgRZPzBiQzfjSTlImqGLUsxIpF5V2LV
# 1BU0V/FShWyrwckBXSqCWBUh6uBUGgEl6qKnK4vH7+ed4Kd9giyp1vWAFEjHgIg+
# gZtPaT/MJQOtLyCuzfuSdUpAzz5Sfw==
# =Is8a
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 14 Nov 2025 04:36:49 AM CET
# gpg:                using RSA key 215D46F48246689EC77F3562EF04965B398D6211
# gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 215D 46F4 8246 689E C77F  3562 EF04 965B 398D 6211

* tag 'net-pull-request' of https://github.com/jasowang/qemu:
  net: pad packets to minimum length in qemu_receive_packet()
  hw/net/e1000e_core: Adjust e1000e_write_payload_frag_to_rx_buffers() assert
  hw/net/e1000e_core: Correct rx oversize packet checks
  hw/net/e1000e_core: Don't advance desc_offset for NULL buffer RX descriptors
  net/hub: make net_hub_port_cleanup idempotent

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2025-11-14 16:27:19 +01:00
commit 409be85c2f
3 changed files with 76 additions and 27 deletions

View file

@ -1392,10 +1392,13 @@ e1000e_write_payload_frag_to_rx_buffers(E1000ECore *core,
dma_addr_t data_len)
{
while (data_len > 0) {
uint32_t cur_buf_len = core->rxbuf_sizes[bastate->cur_idx];
uint32_t cur_buf_bytes_left = cur_buf_len -
bastate->written[bastate->cur_idx];
uint32_t bytes_to_write = MIN(data_len, cur_buf_bytes_left);
uint32_t cur_buf_len, cur_buf_bytes_left, bytes_to_write;
assert(bastate->cur_idx < MAX_PS_BUFFERS);
cur_buf_len = core->rxbuf_sizes[bastate->cur_idx];
cur_buf_bytes_left = cur_buf_len - bastate->written[bastate->cur_idx];
bytes_to_write = MIN(data_len, cur_buf_bytes_left);
trace_e1000e_rx_desc_buff_write(bastate->cur_idx,
ba[bastate->cur_idx],
@ -1414,8 +1417,6 @@ e1000e_write_payload_frag_to_rx_buffers(E1000ECore *core,
if (bastate->written[bastate->cur_idx] == cur_buf_len) {
bastate->cur_idx++;
}
assert(bastate->cur_idx < MAX_PS_BUFFERS);
}
}
@ -1481,7 +1482,6 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
PCIDevice *d = core->owner;
dma_addr_t base;
union e1000_rx_desc_union desc;
size_t desc_size;
size_t desc_offset = 0;
size_t iov_ofs = 0;
@ -1496,16 +1496,17 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
rxi = rxr->i;
do {
/*
* Loop processing descriptors while we have packet data to
* DMA to the guest. desc_offset tracks how much data we have
* sent to the guest in total over all descriptors, and goes
* from 0 up to total_size (the size of everything to send to
* the guest including possible trailing 4 bytes of CRC data).
*/
hwaddr ba[MAX_PS_BUFFERS];
E1000EBAState bastate = { { 0 } };
bool is_last = false;
desc_size = total_size - desc_offset;
if (desc_size > core->rx_desc_buf_size) {
desc_size = core->rx_desc_buf_size;
}
if (e1000e_ring_empty(core, rxi)) {
return;
}
@ -1519,17 +1520,27 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
e1000e_read_rx_descr(core, &desc, ba);
if (ba[0]) {
/* Total amount of data DMA'd to the guest in this iteration */
size_t desc_size = 0;
/*
* Total space available in this descriptor (we will update
* this as we use it up)
*/
size_t rx_desc_buf_size = core->rx_desc_buf_size;
if (desc_offset < size) {
static const uint32_t fcs_pad;
size_t iov_copy;
/* Amount of data to copy from the incoming packet */
size_t copy_size = size - desc_offset;
if (copy_size > core->rx_desc_buf_size) {
copy_size = core->rx_desc_buf_size;
}
/* For PS mode copy the packet header first */
if (do_ps) {
if (is_first) {
/*
* e1000e_do_ps() guarantees that buffer 0 has enough
* space for the header; otherwise we will not split
* the packet (i.e. do_ps is false).
*/
size_t ps_hdr_copied = 0;
do {
iov_copy = MIN(ps_hdr_len - ps_hdr_copied,
@ -1551,14 +1562,26 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
} while (ps_hdr_copied < ps_hdr_len);
is_first = false;
desc_size += ps_hdr_len;
} else {
/* Leave buffer 0 of each descriptor except first */
/* empty as per spec 7.1.5.1 */
e1000e_write_hdr_frag_to_rx_buffers(core, ba, &bastate,
NULL, 0);
}
rx_desc_buf_size -= core->rxbuf_sizes[0];
}
/*
* Clamp the amount of packet data we copy into what will fit
* into the remaining buffers in the descriptor.
*/
if (copy_size > rx_desc_buf_size) {
copy_size = rx_desc_buf_size;
}
desc_size += copy_size;
rx_desc_buf_size -= copy_size;
/* Copy packet payload */
while (copy_size) {
iov_copy = MIN(copy_size, iov->iov_len - iov_ofs);
@ -1575,20 +1598,30 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
iov_ofs = 0;
}
}
}
if (desc_offset + desc_size >= total_size) {
/* Simulate FCS checksum presence in the last descriptor */
e1000e_write_payload_frag_to_rx_buffers(core, ba, &bastate,
(const char *) &fcs_pad, e1000x_fcs_len(core->mac));
}
if (rx_desc_buf_size &&
desc_offset >= size && desc_offset < total_size) {
/*
* We are in the last 4 bytes corresponding to the FCS checksum.
* We only ever write zeroes here (unlike the hardware).
*/
static const uint32_t fcs_pad;
/* Amount of space for the trailing checksum */
size_t fcs_len = MIN(rx_desc_buf_size,
total_size - desc_offset);
e1000e_write_payload_frag_to_rx_buffers(core, ba, &bastate,
(const char *)&fcs_pad,
fcs_len);
desc_size += fcs_len;
}
desc_offset += desc_size;
if (desc_offset >= total_size) {
is_last = true;
}
} else { /* as per intel docs; skip descriptors with null buf addr */
trace_e1000e_rx_null_descriptor();
}
desc_offset += desc_size;
if (desc_offset >= total_size) {
is_last = true;
}
e1000e_write_rx_descr(core, &desc, is_last ? core->rx_pkt : NULL,
rss_info, do_ps ? ps_hdr_len : 0, &bastate.written);

View file

@ -34,6 +34,7 @@ typedef struct NetHubPort {
QLIST_ENTRY(NetHubPort) next;
NetHub *hub;
int id;
bool listed;
} NetHubPort;
struct NetHub {
@ -129,7 +130,10 @@ static void net_hub_port_cleanup(NetClientState *nc)
{
NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
QLIST_REMOVE(port, next);
if (port->listed) {
QLIST_REMOVE(port, next);
port->listed = false;
}
}
static NetClientInfo net_hub_port_info = {
@ -159,8 +163,10 @@ static NetHubPort *net_hub_port_new(NetHub *hub, const char *name,
port = DO_UPCAST(NetHubPort, nc, nc);
port->id = id;
port->hub = hub;
port->listed = false;
QLIST_INSERT_HEAD(&hub->ports, port, next);
port->listed = true;
return port;
}

View file

@ -775,10 +775,20 @@ ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size)
ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size)
{
uint8_t min_pkt[ETH_ZLEN];
size_t min_pktsz = sizeof(min_pkt);
if (!qemu_can_receive_packet(nc)) {
return 0;
}
if (net_peer_needs_padding(nc)) {
if (eth_pad_short_frame(min_pkt, &min_pktsz, buf, size)) {
buf = min_pkt;
size = min_pktsz;
}
}
return qemu_net_queue_receive(nc->incoming_queue, buf, size);
}