Skip site navigation (1)Skip section navigation (2)
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>