The branch main has been updated by pouria:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=c5caf856453325728155a18d3bb02a9cd651a0a0

commit c5caf856453325728155a18d3bb02a9cd651a0a0
Author:     Faraz Vahedi <[email protected]>
AuthorDate: 2026-07-12 20:46:20 +0000
Commit:     Pouria Mousavizadeh Tehrani <[email protected]>
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 <[email protected]>
    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            | \

Reply via email to