Date: Tue, 21 Jul 2026 20:07:41 +0000 From: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Faraz Vahedi <kfv@kfv.io> Subject: git: c5caf8564533 - main - vtnet: Implement VIRTIO_NET_F_GUEST_ANNOUNCE Message-ID: <6a5fd18d.22243.7937b2fa@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by pouria: URL: https://cgit.FreeBSD.org/src/commit/?id=c5caf856453325728155a18d3bb02a9cd651a0a0 commit c5caf856453325728155a18d3bb02a9cd651a0a0 Author: Faraz Vahedi <kfv@kfv.io> AuthorDate: 2026-07-12 20:46:20 +0000 Commit: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org> CommitDate: 2026-07-21 20:06:35 +0000 vtnet: Implement VIRTIO_NET_F_GUEST_ANNOUNCE When the device sets VIRTIO_NET_S_ANNOUNCE in the config status field, for example after a VM migrates to a new host, announce the interface's presence on the network so peers and switches learn the new attachment point, then acknowledge the request with the VIRTIO_NET_CTRL_ANNOUNCE_ACK control command, as per VirtIO v1.3, 5.1.6.5.4. The announcement raises iflladdr_event: the stack sends gratuitous ARPs and unsolicited neighbor advertisements for the interface's addresses, and stacked interfaces such as vlan(4) propagate the event and announce theirs as well. The event handlers may sleep, so the work is deferred from the config change interrupt to a task on taskqueue_thread; that context also allows the acknowledgement to be skipped safely if the interface was stopped in the meantime, in which case the device keeps the bit set and the request is re-delivered with the next config change interrupt. Signed-off-by: Faraz Vahedi <kfv@kfv.io> Reviewed by: adrian Pull Request: https://github.com/freebsd/freebsd-src/pull/2322 --- sys/dev/virtio/network/if_vtnet.c | 88 ++++++++++++++++++++++++++++++++++++ sys/dev/virtio/network/if_vtnetvar.h | 2 + 2 files changed, 90 insertions(+) diff --git a/sys/dev/virtio/network/if_vtnet.c b/sys/dev/virtio/network/if_vtnet.c index ac5c08f60a0e..e9683698decb 100644 --- a/sys/dev/virtio/network/if_vtnet.c +++ b/sys/dev/virtio/network/if_vtnet.c @@ -224,6 +224,9 @@ static int vtnet_exec_ctrl_cmd(struct vtnet_softc *, uint8_t *, static int vtnet_ctrl_mac_cmd(struct vtnet_softc *, uint8_t *); static int vtnet_ctrl_guest_offloads(struct vtnet_softc *, uint64_t); static int vtnet_ctrl_mq_cmd(struct vtnet_softc *, uint16_t); +static int vtnet_ctrl_announce_ack_cmd(struct vtnet_softc *); +static bool vtnet_announce_pending(struct vtnet_softc *); +static void vtnet_announce(void *, int); static int vtnet_ctrl_rx_cmd(struct vtnet_softc *, uint8_t, bool); static int vtnet_set_promisc(struct vtnet_softc *, bool); static int vtnet_set_allmulti(struct vtnet_softc *, bool); @@ -468,6 +471,7 @@ vtnet_attach(device_t dev) VTNET_CORE_LOCK_INIT(sc); callout_init_mtx(&sc->vtnet_tick_ch, VTNET_CORE_MTX(sc), 0); + TASK_INIT(&sc->vtnet_announce_task, 0, vtnet_announce, sc); vtnet_load_tunables(sc); vtnet_alloc_interface(sc); @@ -642,6 +646,8 @@ vtnet_detach(device_t dev) ether_ifdetach(ifp); } + taskqueue_drain(taskqueue_thread, &sc->vtnet_announce_task); + #ifdef DEV_NETMAP netmap_detach(ifp); #endif @@ -746,6 +752,8 @@ vtnet_config_change(device_t dev) VTNET_CORE_LOCK(sc); vtnet_update_link_status(sc); + if (vtnet_announce_pending(sc)) + taskqueue_enqueue(taskqueue_thread, &sc->vtnet_announce_task); if (sc->vtnet_link_active != 0) vtnet_tx_start_all(sc); VTNET_CORE_UNLOCK(sc); @@ -4056,6 +4064,86 @@ error_out: return (error); } +static int +vtnet_ctrl_announce_ack_cmd(struct vtnet_softc *sc) +{ + struct sglist_seg segs[2]; + bus_dmamap_t hdr_dmap; + bus_addr_t hdr_paddr; + struct sglist sg; + struct virtio_net_ctrl_hdr hdr __aligned(2); + uint8_t ack; + int error; + + error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap); + if (error != 0) + goto error_out; + + error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &hdr, + sizeof(hdr), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT); + if (error != 0) + goto error_destroy_hdr; + + hdr.class = VIRTIO_NET_CTRL_ANNOUNCE; + hdr.cmd = VIRTIO_NET_CTRL_ANNOUNCE_ACK; + ack = VIRTIO_NET_ERR; + bus_dmamap_sync(sc->vtnet_hdr_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE); + + sglist_init(&sg, nitems(segs), segs); + error = sglist_append_phys(&sg, hdr_paddr, sizeof(hdr)); + MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1); + + if (error == 0) + error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1); + if (error == 0) + error = (ack == VIRTIO_NET_OK ? 0 : EIO); + + bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap); +error_destroy_hdr: + bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap); +error_out: + return (error); +} + +static bool +vtnet_announce_pending(struct vtnet_softc *sc) +{ + uint16_t status; + + if ((sc->vtnet_features & VIRTIO_NET_F_GUEST_ANNOUNCE) == 0 || + (sc->vtnet_features & VIRTIO_NET_F_CTRL_VQ) == 0 || + (sc->vtnet_features & VIRTIO_NET_F_STATUS) == 0) + return (false); + + status = virtio_read_dev_config_2(sc->vtnet_dev, + offsetof(struct virtio_net_config, status)); + + return ((status & VIRTIO_NET_S_ANNOUNCE) != 0); +} + +static void +vtnet_announce(void *xsc, int pending __unused) +{ + struct vtnet_softc *sc; + if_t ifp; + + sc = xsc; + ifp = sc->vtnet_ifp; + + if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) + return; + + CURVNET_SET(if_getvnet(ifp)); + EVENTHANDLER_INVOKE(iflladdr_event, ifp); + CURVNET_RESTORE(); + + VTNET_CORE_LOCK(sc); + if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0 && + vtnet_ctrl_announce_ack_cmd(sc) != 0) + device_printf(sc->vtnet_dev, "cannot ack announcement\n"); + VTNET_CORE_UNLOCK(sc); +} + static int vtnet_ctrl_rx_cmd(struct vtnet_softc *sc, uint8_t cmd, bool on) { diff --git a/sys/dev/virtio/network/if_vtnetvar.h b/sys/dev/virtio/network/if_vtnetvar.h index 77a7680e5b43..904050c7864a 100644 --- a/sys/dev/virtio/network/if_vtnetvar.h +++ b/sys/dev/virtio/network/if_vtnetvar.h @@ -183,6 +183,7 @@ struct vtnet_softc { uint64_t vtnet_negotiated_features; struct vtnet_statistics vtnet_stats; struct callout vtnet_tick_ch; + struct task vtnet_announce_task; struct ifmedia vtnet_media; eventhandler_tag vtnet_vlan_attach; eventhandler_tag vtnet_vlan_detach; @@ -338,6 +339,7 @@ CTASSERT(sizeof(struct vtnet_mac_filter) <= PAGE_SIZE); VIRTIO_NET_F_CTRL_RX | \ VIRTIO_NET_F_CTRL_MAC_ADDR | \ VIRTIO_NET_F_CTRL_VLAN | \ + VIRTIO_NET_F_GUEST_ANNOUNCE | \ VIRTIO_NET_F_CSUM | \ VIRTIO_NET_F_HOST_TSO4 | \ VIRTIO_NET_F_HOST_TSO6 | \home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a5fd18d.22243.7937b2fa>
