aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFaraz Vahedi <kfv@kfv.io>2026-07-12 20:46:20 +0000
committerPouria Mousavizadeh Tehrani <pouria@FreeBSD.org>2026-07-21 20:06:35 +0000
commitc5caf856453325728155a18d3bb02a9cd651a0a0 (patch)
treea93f5d38532db84e72a9a981740232ea7de0ef42
parent5481c2d3ac1fc7682cdd184c7a797c0583e391c0 (diff)
-rw-r--r--sys/dev/virtio/network/if_vtnet.c88
-rw-r--r--sys/dev/virtio/network/if_vtnetvar.h2
2 files changed, 90 insertions, 0 deletions
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);
@@ -4057,6 +4065,86 @@ error_out:
}
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)
{
struct sglist_seg segs[3];
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 | \