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

iQEzBAABCAAdFiEEIV1G9IJGaJ7HfzVi7wSWWzmNYhEFAmfO1zkACgkQ7wSWWzmN
 YhET+wf+PkaGeFTNUrOtWpl35fSMKlmOVbb1fkPfuhVBmeY2Vh1EIN3OjqnzdV0F
 wxpuk+wwmFiuV1n6RNuMHQ0nz1mhgsSlZh93N5rArC/PUr3iViaT0cb82RjwxhaI
 RODBhhy7V9WxEhT9hR8sCP2ky2mrKgcYbjiIEw+IvFZOVQa58rMr2h/cbAb/iH4l
 7T9Wba03JBqOS6qgzSFZOMxvqnYdVjhqXN8M6W9ngRJOjPEAkTB6Evwep6anRjcM
 mCUOgkf2sgQwKve8pYAeTMkzXFctvTc/qCU4ZbN8XcoKVVxe2jllGQqdOpMskPEf
 slOuINeW5M0K5gyjsb/huqcOTfDI2A==
 =/Y0+
 -----END PGP SIGNATURE-----

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

# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCAAdFiEEIV1G9IJGaJ7HfzVi7wSWWzmNYhEFAmfO1zkACgkQ7wSWWzmN
# YhET+wf+PkaGeFTNUrOtWpl35fSMKlmOVbb1fkPfuhVBmeY2Vh1EIN3OjqnzdV0F
# wxpuk+wwmFiuV1n6RNuMHQ0nz1mhgsSlZh93N5rArC/PUr3iViaT0cb82RjwxhaI
# RODBhhy7V9WxEhT9hR8sCP2ky2mrKgcYbjiIEw+IvFZOVQa58rMr2h/cbAb/iH4l
# 7T9Wba03JBqOS6qgzSFZOMxvqnYdVjhqXN8M6W9ngRJOjPEAkTB6Evwep6anRjcM
# mCUOgkf2sgQwKve8pYAeTMkzXFctvTc/qCU4ZbN8XcoKVVxe2jllGQqdOpMskPEf
# slOuINeW5M0K5gyjsb/huqcOTfDI2A==
# =/Y0+
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 10 Mar 2025 20:12:41 HKT
# gpg:                using RSA key 215D46F48246689EC77F3562EF04965B398D6211
# gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [full]
# Primary key fingerprint: 215D 46F4 8246 689E C77F  3562 EF04 965B 398D 6211

* tag 'net-pull-request' of https://github.com/jasowang/qemu:
  tap-linux: Open ipvtap and macvtap
  Revert "hw/net/net_tx_pkt: Fix overrun in update_sctp_checksum()"
  util/iov: Do not assert offset is in iov
  net: move backend cleanup to NIC cleanup
  net: parameterize the removing client from nc list

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2025-03-11 09:26:40 +08:00
commit 920aa48824
6 changed files with 51 additions and 32 deletions

View File

@ -141,10 +141,6 @@ bool net_tx_pkt_update_sctp_checksum(struct NetTxPkt *pkt)
uint32_t csum = 0; uint32_t csum = 0;
struct iovec *pl_start_frag = pkt->vec + NET_TX_PKT_PL_START_FRAG; struct iovec *pl_start_frag = pkt->vec + NET_TX_PKT_PL_START_FRAG;
if (iov_size(pl_start_frag, pkt->payload_frags) < 8 + sizeof(csum)) {
return false;
}
if (iov_from_buf(pl_start_frag, pkt->payload_frags, 8, &csum, sizeof(csum)) < sizeof(csum)) { if (iov_from_buf(pl_start_frag, pkt->payload_frags, 8, &csum, sizeof(csum)) < sizeof(csum)) {
return false; return false;
} }

View File

@ -31,7 +31,7 @@ size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
* only part of data will be copied, up to the end of the iovec. * only part of data will be copied, up to the end of the iovec.
* Number of bytes actually copied will be returned, which is * Number of bytes actually copied will be returned, which is
* min(bytes, iov_size(iov)-offset) * min(bytes, iov_size(iov)-offset)
* `Offset' must point to the inside of iovec. * Returns 0 when `offset' points to the outside of iovec.
*/ */
size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt, size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt,
size_t offset, const void *buf, size_t bytes); size_t offset, const void *buf, size_t bytes);
@ -67,11 +67,12 @@ iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
/** /**
* Set data bytes pointed out by iovec `iov' of size `iov_cnt' elements, * Set data bytes pointed out by iovec `iov' of size `iov_cnt' elements,
* starting at byte offset `start', to value `fillc', repeating it * starting at byte offset `start', to value `fillc', repeating it
* `bytes' number of times. `Offset' must point to the inside of iovec. * `bytes' number of times.
* If `bytes' is large enough, only last bytes portion of iovec, * If `bytes' is large enough, only last bytes portion of iovec,
* up to the end of it, will be filled with the specified value. * up to the end of it, will be filled with the specified value.
* Function return actual number of bytes processed, which is * Function return actual number of bytes processed, which is
* min(size, iov_size(iov) - offset). * min(size, iov_size(iov) - offset).
* Returns 0 when `offset' points to the outside of iovec.
*/ */
size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt, size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
size_t offset, int fillc, size_t bytes); size_t offset, int fillc, size_t bytes);

View File

@ -381,9 +381,12 @@ NetClientState *qemu_get_peer(NetClientState *nc, int queue_index)
return ncs->peer; return ncs->peer;
} }
static void qemu_cleanup_net_client(NetClientState *nc) static void qemu_cleanup_net_client(NetClientState *nc,
bool remove_from_net_clients)
{ {
if (remove_from_net_clients) {
QTAILQ_REMOVE(&net_clients, nc, next); QTAILQ_REMOVE(&net_clients, nc, next);
}
if (nc->info->cleanup) { if (nc->info->cleanup) {
nc->info->cleanup(nc); nc->info->cleanup(nc);
@ -425,7 +428,13 @@ void qemu_del_net_client(NetClientState *nc)
object_unparent(OBJECT(nf)); object_unparent(OBJECT(nf));
} }
/* If there is a peer NIC, delete and cleanup client, but do not free. */ /*
* If there is a peer NIC, transfer ownership to it. Delete the client
* from net_client list but do not cleanup nor free. This way NIC can
* still access to members of the backend.
*
* The cleanup and free will be done when the NIC is free.
*/
if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) {
NICState *nic = qemu_get_nic(nc->peer); NICState *nic = qemu_get_nic(nc->peer);
if (nic->peer_deleted) { if (nic->peer_deleted) {
@ -435,21 +444,18 @@ void qemu_del_net_client(NetClientState *nc)
for (i = 0; i < queues; i++) { for (i = 0; i < queues; i++) {
ncs[i]->peer->link_down = true; ncs[i]->peer->link_down = true;
QTAILQ_REMOVE(&net_clients, ncs[i], next);
} }
if (nc->peer->info->link_status_changed) { if (nc->peer->info->link_status_changed) {
nc->peer->info->link_status_changed(nc->peer); nc->peer->info->link_status_changed(nc->peer);
} }
for (i = 0; i < queues; i++) {
qemu_cleanup_net_client(ncs[i]);
}
return; return;
} }
for (i = 0; i < queues; i++) { for (i = 0; i < queues; i++) {
qemu_cleanup_net_client(ncs[i]); qemu_cleanup_net_client(ncs[i], true);
qemu_free_net_client(ncs[i]); qemu_free_net_client(ncs[i]);
} }
} }
@ -462,8 +468,12 @@ void qemu_del_nic(NICState *nic)
for (i = 0; i < queues; i++) { for (i = 0; i < queues; i++) {
NetClientState *nc = qemu_get_subqueue(nic, i); NetClientState *nc = qemu_get_subqueue(nic, i);
/* If this is a peer NIC and peer has already been deleted, free it now. */ /*
* If this is a peer NIC and peer has already been deleted, clean it up
* and free it now.
*/
if (nic->peer_deleted) { if (nic->peer_deleted) {
qemu_cleanup_net_client(nc->peer, false);
qemu_free_net_client(nc->peer); qemu_free_net_client(nc->peer);
} else if (nc->peer) { } else if (nc->peer) {
/* if there are RX packets pending, complete them */ /* if there are RX packets pending, complete them */
@ -474,7 +484,7 @@ void qemu_del_nic(NICState *nic)
for (i = queues - 1; i >= 0; i--) { for (i = queues - 1; i >= 0; i--) {
NetClientState *nc = qemu_get_subqueue(nic, i); NetClientState *nc = qemu_get_subqueue(nic, i);
qemu_cleanup_net_client(nc); qemu_cleanup_net_client(nc, true);
qemu_free_net_client(nc); qemu_free_net_client(nc);
} }
@ -1678,6 +1688,9 @@ void net_cleanup(void)
* of the latest NET_CLIENT_DRIVER_NIC, and operate on *p as we walk * of the latest NET_CLIENT_DRIVER_NIC, and operate on *p as we walk
* the list. * the list.
* *
* However, the NIC may have peers that trust to be clean beyond this
* point. For example, if they have been removed with device_del.
*
* The 'nc' variable isn't part of the list traversal; it's purely * The 'nc' variable isn't part of the list traversal; it's purely
* for convenience as too much '(*p)->' has a tendency to make the * for convenience as too much '(*p)->' has a tendency to make the
* readers' eyes bleed. * readers' eyes bleed.
@ -1685,6 +1698,17 @@ void net_cleanup(void)
while (*p) { while (*p) {
nc = *p; nc = *p;
if (nc->info->type == NET_CLIENT_DRIVER_NIC) { if (nc->info->type == NET_CLIENT_DRIVER_NIC) {
NICState *nic = qemu_get_nic(nc);
if (nic->peer_deleted) {
int queues = MAX(nic->conf->peers.queues, 1);
for (int i = 0; i < queues; i++) {
nc = qemu_get_subqueue(nic, i);
qemu_cleanup_net_client(nc->peer, false);
}
}
/* Skip NET_CLIENT_DRIVER_NIC entries */ /* Skip NET_CLIENT_DRIVER_NIC entries */
p = &QTAILQ_NEXT(nc, next); p = &QTAILQ_NEXT(nc, next);
} else { } else {

View File

@ -45,11 +45,22 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
int len = sizeof(struct virtio_net_hdr); int len = sizeof(struct virtio_net_hdr);
unsigned int features; unsigned int features;
ret = if_nametoindex(ifname);
if (ret) {
g_autofree char *file = g_strdup_printf("/dev/tap%d", ret);
fd = open(file, O_RDWR);
} else {
fd = -1;
}
if (fd < 0) {
fd = RETRY_ON_EINTR(open(PATH_NET_TUN, O_RDWR)); fd = RETRY_ON_EINTR(open(PATH_NET_TUN, O_RDWR));
if (fd < 0) { if (fd < 0) {
error_setg_errno(errp, errno, "could not open %s", PATH_NET_TUN); error_setg_errno(errp, errno, "could not open %s", PATH_NET_TUN);
return -1; return -1;
} }
}
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI; ifr.ifr_flags = IFF_TAP | IFF_NO_PI;

View File

@ -224,14 +224,6 @@ static void vhost_vdpa_cleanup(NetClientState *nc)
{ {
VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
/*
* If a peer NIC is attached, do not cleanup anything.
* Cleanup will happen as a part of qemu_cleanup() -> net_cleanup()
* when the guest is shutting down.
*/
if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) {
return;
}
munmap(s->cvq_cmd_out_buffer, vhost_vdpa_net_cvq_cmd_page_len()); munmap(s->cvq_cmd_out_buffer, vhost_vdpa_net_cvq_cmd_page_len());
munmap(s->status, vhost_vdpa_net_cvq_cmd_page_len()); munmap(s->status, vhost_vdpa_net_cvq_cmd_page_len());
if (s->vhost_net) { if (s->vhost_net) {

View File

@ -37,7 +37,6 @@ size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt,
offset -= iov[i].iov_len; offset -= iov[i].iov_len;
} }
} }
assert(offset == 0);
return done; return done;
} }
@ -56,7 +55,6 @@ size_t iov_to_buf_full(const struct iovec *iov, const unsigned int iov_cnt,
offset -= iov[i].iov_len; offset -= iov[i].iov_len;
} }
} }
assert(offset == 0);
return done; return done;
} }
@ -75,7 +73,6 @@ size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
offset -= iov[i].iov_len; offset -= iov[i].iov_len;
} }
} }
assert(offset == 0);
return done; return done;
} }
@ -277,7 +274,6 @@ unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt,
bytes -= len; bytes -= len;
offset = 0; offset = 0;
} }
assert(offset == 0);
return j; return j;
} }
@ -348,7 +344,6 @@ size_t qemu_iovec_concat_iov(QEMUIOVector *dst,
soffset -= src_iov[i].iov_len; soffset -= src_iov[i].iov_len;
} }
} }
assert(soffset == 0); /* offset beyond end of src */
return done; return done;
} }