Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F132531644
D27904.id81527.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
48 KB
Referenced Files
None
Subscribers
None
D27904.id81527.diff
View Options
Index: sys/dev/virtio/network/if_vtnet.c
===================================================================
--- sys/dev/virtio/network/if_vtnet.c
+++ sys/dev/virtio/network/if_vtnet.c
@@ -190,7 +190,7 @@
struct sglist *, int, int);
static int vtnet_ctrl_mac_cmd(struct vtnet_softc *, uint8_t *);
static int vtnet_ctrl_mq_cmd(struct vtnet_softc *, uint16_t);
-static int vtnet_ctrl_rx_cmd(struct vtnet_softc *, int, int);
+static int vtnet_ctrl_rx_cmd(struct vtnet_softc *, uint8_t, int);
static int vtnet_set_promisc(struct vtnet_softc *, int);
static int vtnet_set_allmulti(struct vtnet_softc *, int);
static void vtnet_attach_disable_promisc(struct vtnet_softc *);
@@ -234,6 +234,13 @@
DEBUGNET_DEFINE(vtnet);
+#define vtnet_htog16(_sc, _val) virtio_htog16(vtnet_modern(_sc), _val)
+#define vtnet_htog32(_sc, _val) virtio_htog32(vtnet_modern(_sc), _val)
+#define vtnet_htog64(_sc, _val) virtio_htog64(vtnet_modern(_sc), _val)
+#define vtnet_gtoh16(_sc, _val) virtio_gtoh16(vtnet_modern(_sc), _val)
+#define vtnet_gtoh32(_sc, _val) virtio_gtoh32(vtnet_modern(_sc), _val)
+#define vtnet_gtoh64(_sc, _val) virtio_gtoh64(vtnet_modern(_sc), _val)
+
/* Tunables. */
static SYSCTL_NODE(_hw, OID_AUTO, vtnet, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
"VNET driver parameters");
@@ -266,27 +273,30 @@
static uma_zone_t vtnet_tx_header_zone;
static struct virtio_feature_desc vtnet_feature_desc[] = {
- { VIRTIO_NET_F_CSUM, "TxChecksum" },
- { VIRTIO_NET_F_GUEST_CSUM, "RxChecksum" },
- { VIRTIO_NET_F_MAC, "MacAddress" },
- { VIRTIO_NET_F_GSO, "TxAllGSO" },
- { VIRTIO_NET_F_GUEST_TSO4, "RxTSOv4" },
- { VIRTIO_NET_F_GUEST_TSO6, "RxTSOv6" },
- { VIRTIO_NET_F_GUEST_ECN, "RxECN" },
- { VIRTIO_NET_F_GUEST_UFO, "RxUFO" },
- { VIRTIO_NET_F_HOST_TSO4, "TxTSOv4" },
- { VIRTIO_NET_F_HOST_TSO6, "TxTSOv6" },
- { VIRTIO_NET_F_HOST_ECN, "TxTSOECN" },
- { VIRTIO_NET_F_HOST_UFO, "TxUFO" },
- { VIRTIO_NET_F_MRG_RXBUF, "MrgRxBuf" },
- { VIRTIO_NET_F_STATUS, "Status" },
- { VIRTIO_NET_F_CTRL_VQ, "ControlVq" },
- { VIRTIO_NET_F_CTRL_RX, "RxMode" },
- { VIRTIO_NET_F_CTRL_VLAN, "VLanFilter" },
- { VIRTIO_NET_F_CTRL_RX_EXTRA, "RxModeExtra" },
- { VIRTIO_NET_F_GUEST_ANNOUNCE, "GuestAnnounce" },
- { VIRTIO_NET_F_MQ, "Multiqueue" },
- { VIRTIO_NET_F_CTRL_MAC_ADDR, "SetMacAddress" },
+ { VIRTIO_NET_F_CSUM, "TxChecksum" },
+ { VIRTIO_NET_F_GUEST_CSUM, "RxChecksum" },
+ { VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, "CtrlRxOffloads" },
+ { VIRTIO_NET_F_MAC, "MAC" },
+ { VIRTIO_NET_F_GSO, "TxGSO" },
+ { VIRTIO_NET_F_GUEST_TSO4, "RxLROv4" },
+ { VIRTIO_NET_F_GUEST_TSO6, "RxLROv6" },
+ { VIRTIO_NET_F_GUEST_ECN, "RxLROECN" },
+ { VIRTIO_NET_F_GUEST_UFO, "RxUFO" },
+ { VIRTIO_NET_F_HOST_TSO4, "TxTSOv4" },
+ { VIRTIO_NET_F_HOST_TSO6, "TxTSOv6" },
+ { VIRTIO_NET_F_HOST_ECN, "TxTSOECN" },
+ { VIRTIO_NET_F_HOST_UFO, "TxUFO" },
+ { VIRTIO_NET_F_MRG_RXBUF, "MrgRxBuf" },
+ { VIRTIO_NET_F_STATUS, "Status" },
+ { VIRTIO_NET_F_CTRL_VQ, "CtrlVq" },
+ { VIRTIO_NET_F_CTRL_RX, "CtrlRxMode" },
+ { VIRTIO_NET_F_CTRL_VLAN, "CtrlVLANFilter" },
+ { VIRTIO_NET_F_CTRL_RX_EXTRA, "CtrlRxModeExtra" },
+ { VIRTIO_NET_F_GUEST_ANNOUNCE, "GuestAnnounce" },
+ { VIRTIO_NET_F_MQ, "Multiqueue" },
+ { VIRTIO_NET_F_CTRL_MAC_ADDR, "CtrlMacAddr" },
+ { VIRTIO_NET_F_SPEED_DUPLEX, "SpeedDuplex" },
+
{ 0, NULL }
};
@@ -308,12 +318,12 @@
#ifdef DEV_NETMAP
#include <dev/netmap/if_vtnet_netmap.h>
-#endif /* DEV_NETMAP */
+#endif
static driver_t vtnet_driver = {
- "vtnet",
- vtnet_methods,
- sizeof(struct vtnet_softc)
+ .name = "vtnet",
+ .methods = vtnet_methods,
+ .size = sizeof(struct vtnet_softc)
};
static devclass_t vtnet_devclass;
@@ -325,7 +335,7 @@
MODULE_DEPEND(vtnet, virtio, 1, 1, 1);
#ifdef DEV_NETMAP
MODULE_DEPEND(vtnet, netmap, 1, 1, 1);
-#endif /* DEV_NETMAP */
+#endif
VIRTIO_SIMPLE_PNPTABLE(vtnet, VIRTIO_ID_NETWORK, "VirtIO Networking Adapter");
VIRTIO_SIMPLE_PNPINFO(virtio_mmio, vtnet);
@@ -390,7 +400,6 @@
sc = device_get_softc(dev);
sc->vtnet_dev = dev;
- /* Register our feature descriptions. */
virtio_set_feature_desc(dev, vtnet_feature_desc);
VTNET_CORE_LOCK_INIT(sc);
@@ -425,16 +434,14 @@
error = virtio_setup_intr(dev, INTR_TYPE_NET);
if (error) {
- device_printf(dev, "cannot setup virtqueue interrupts\n");
- /* BMV: This will crash if during boot! */
+ device_printf(dev, "cannot setup interrupts\n");
ether_ifdetach(sc->vtnet_ifp);
goto fail;
}
#ifdef DEV_NETMAP
vtnet_netmap_attach(sc);
-#endif /* DEV_NETMAP */
-
+#endif
vtnet_start_taskqueues(sc);
fail:
@@ -466,7 +473,7 @@
#ifdef DEV_NETMAP
netmap_detach(ifp);
-#endif /* DEV_NETMAP */
+#endif
vtnet_free_taskqueues(sc);
@@ -533,7 +540,6 @@
static int
vtnet_shutdown(device_t dev)
{
-
/*
* Suspend already does all of what we need to
* do here; we just never expect to be resumed.
@@ -570,31 +576,32 @@
vtnet_negotiate_features(struct vtnet_softc *sc)
{
device_t dev;
- uint64_t mask, features;
+ uint64_t features;
+ int no_csum;
dev = sc->vtnet_dev;
- mask = 0;
+ features = virtio_bus_is_modern(dev) ? VTNET_MODERN_FEATURES :
+ VTNET_LEGACY_FEATURES;
/*
* TSO and LRO are only available when their corresponding checksum
* offload feature is also negotiated.
*/
- if (vtnet_tunable_int(sc, "csum_disable", vtnet_csum_disable)) {
- mask |= VIRTIO_NET_F_CSUM | VIRTIO_NET_F_GUEST_CSUM;
- mask |= VTNET_TSO_FEATURES | VTNET_LRO_FEATURES;
- }
- if (vtnet_tunable_int(sc, "tso_disable", vtnet_tso_disable))
- mask |= VTNET_TSO_FEATURES;
- if (vtnet_tunable_int(sc, "lro_disable", vtnet_lro_disable))
- mask |= VTNET_LRO_FEATURES;
+ no_csum = vtnet_tunable_int(sc, "csum_disable", vtnet_csum_disable);
+ if (no_csum)
+ features &= ~(VIRTIO_NET_F_CSUM | VIRTIO_NET_F_GUEST_CSUM);
+ if (no_csum || vtnet_tunable_int(sc, "tso_disable", vtnet_tso_disable))
+ features &= ~VTNET_TSO_FEATURES;
+ if (no_csum || vtnet_tunable_int(sc, "lro_disable", vtnet_lro_disable))
+ features &= ~VTNET_LRO_FEATURES;
+
#ifndef VTNET_LEGACY_TX
if (vtnet_tunable_int(sc, "mq_disable", vtnet_mq_disable))
- mask |= VIRTIO_NET_F_MQ;
+ features &= ~VIRTIO_NET_F_MQ;
#else
- mask |= VIRTIO_NET_F_MQ;
+ features &= ~VIRTIO_NET_F_MQ;
#endif
- features = VTNET_FEATURES & ~mask;
sc->vtnet_features = virtio_negotiate_features(dev, features);
if (virtio_with_feature(dev, VTNET_LRO_FEATURES) &&
@@ -619,6 +626,8 @@
} else
sc->vtnet_flags |= VTNET_FLAG_LRO_NOMRG;
}
+
+ virtio_finalize_features(dev);
}
static void
@@ -630,6 +639,8 @@
vtnet_negotiate_features(sc);
+ if (virtio_with_feature(dev, VIRTIO_F_VERSION_1))
+ sc->vtnet_flags |= VTNET_FLAG_MODERN;
if (virtio_with_feature(dev, VIRTIO_RING_F_INDIRECT_DESC))
sc->vtnet_flags |= VTNET_FLAG_INDIRECT;
if (virtio_with_feature(dev, VIRTIO_RING_F_EVENT_IDX))
@@ -643,11 +654,21 @@
if (virtio_with_feature(dev, VIRTIO_NET_F_MRG_RXBUF)) {
sc->vtnet_flags |= VTNET_FLAG_MRG_RXBUFS;
sc->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ } else if (vtnet_modern(sc)) {
+ /*
+ * The V1 header is the same size and layout as the mergeable
+ * buffer header, but num_buffers will always be one. Depending
+ * on the context, the driver uses the mergeable header for
+ * either case.
+ */
+ sc->vtnet_hdr_size = sizeof(struct virtio_net_hdr_v1);
} else
sc->vtnet_hdr_size = sizeof(struct virtio_net_hdr);
if (sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS)
sc->vtnet_rx_nsegs = VTNET_MRG_RX_SEGS;
+ else if (vtnet_modern(sc)) /* TODO: And ANY_LAYOUT when supported */
+ sc->vtnet_rx_nsegs = VTNET_MODERN_RX_SEGS;
else if (sc->vtnet_flags & VTNET_FLAG_LRO_NOMRG)
sc->vtnet_rx_nsegs = VTNET_MAX_RX_SEGS;
else
@@ -660,6 +681,8 @@
else
sc->vtnet_tx_nsegs = VTNET_MIN_TX_SEGS;
+ sc->vtnet_max_vq_pairs = 1;
+
if (virtio_with_feature(dev, VIRTIO_NET_F_CTRL_VQ)) {
sc->vtnet_flags |= VTNET_FLAG_CTRL_VQ;
@@ -669,23 +692,22 @@
sc->vtnet_flags |= VTNET_FLAG_VLAN_FILTER;
if (virtio_with_feature(dev, VIRTIO_NET_F_CTRL_MAC_ADDR))
sc->vtnet_flags |= VTNET_FLAG_CTRL_MAC;
- }
- if (virtio_with_feature(dev, VIRTIO_NET_F_MQ) &&
- sc->vtnet_flags & VTNET_FLAG_CTRL_VQ) {
- sc->vtnet_max_vq_pairs = virtio_read_dev_config_2(dev,
- offsetof(struct virtio_net_config, max_virtqueue_pairs));
- } else
- sc->vtnet_max_vq_pairs = 1;
+ if (virtio_with_feature(dev, VIRTIO_NET_F_MQ)) {
+ sc->vtnet_max_vq_pairs = virtio_read_dev_config_2(dev,
+ offsetof(struct virtio_net_config,
+ max_virtqueue_pairs));
+ }
+ }
if (sc->vtnet_max_vq_pairs > 1) {
+ int max;
+
/*
* Limit the maximum number of queue pairs to the lower of
- * the number of CPUs and the configured maximum.
- * The actual number of queues that get used may be less.
+ * the number of CPUs and the configured maximum. The actual
+ * number of queues that get used may be less.
*/
- int max;
-
max = vtnet_tunable_int(sc, "mq_max_pairs", vtnet_mq_max_pairs);
if (max > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN) {
if (max > mp_ncpus)
@@ -694,7 +716,7 @@
max = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX;
if (max > 1) {
sc->vtnet_requested_vq_pairs = max;
- sc->vtnet_flags |= VTNET_FLAG_MULTIQ;
+ sc->vtnet_flags |= VTNET_FLAG_MQ;
}
}
}
@@ -903,7 +925,7 @@
if (info == NULL)
return (ENOMEM);
- for (i = 0, idx = 0; i < sc->vtnet_max_vq_pairs; i++, idx+=2) {
+ for (i = 0, idx = 0; i < sc->vtnet_max_vq_pairs; i++, idx += 2) {
rxq = &sc->vtnet_rxqs[i];
VQ_ALLOC_INFO_INIT(&info[idx], sc->vtnet_rx_nsegs,
vtnet_rx_vq_intr, rxq, &rxq->vtnrx_vq,
@@ -921,10 +943,10 @@
}
/*
- * Enable interrupt binding if this is multiqueue. This only matters
- * when per-vq MSIX is available.
+ * TODO: Enable interrupt binding if this is multiqueue. This will
+ * only matter when per-vq MSIX is available.
*/
- if (sc->vtnet_flags & VTNET_FLAG_MULTIQ)
+ if (sc->vtnet_flags & VTNET_FLAG_MQ)
flags |= 0;
error = virtio_alloc_virtqueues(dev, flags, nvqs, info);
@@ -972,9 +994,7 @@
ifmedia_add(&sc->vtnet_media, VTNET_MEDIATYPE, 0, NULL);
ifmedia_set(&sc->vtnet_media, VTNET_MEDIATYPE);
- /* Read (or generate) the MAC address for the adapter. */
vtnet_get_hwaddr(sc);
-
ether_ifattach(ifp, sc->vtnet_hwaddr);
if (virtio_with_feature(dev, VIRTIO_NET_F_STATUS))
@@ -985,21 +1005,19 @@
ifp->if_capabilities |= IFCAP_JUMBO_MTU | IFCAP_VLAN_MTU;
if (virtio_with_feature(dev, VIRTIO_NET_F_CSUM)) {
+ int gso;
+
ifp->if_capabilities |= IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6;
- if (virtio_with_feature(dev, VIRTIO_NET_F_GSO)) {
- ifp->if_capabilities |= IFCAP_TSO4 | IFCAP_TSO6;
+ gso = virtio_with_feature(dev, VIRTIO_NET_F_GSO);
+ if (gso || virtio_with_feature(dev, VIRTIO_NET_F_HOST_TSO4))
+ ifp->if_capabilities |= IFCAP_TSO4;
+ if (gso || virtio_with_feature(dev, VIRTIO_NET_F_HOST_TSO6))
+ ifp->if_capabilities |= IFCAP_TSO6;
+ if (gso || virtio_with_feature(dev, VIRTIO_NET_F_HOST_ECN))
sc->vtnet_flags |= VTNET_FLAG_TSO_ECN;
- } else {
- if (virtio_with_feature(dev, VIRTIO_NET_F_HOST_TSO4))
- ifp->if_capabilities |= IFCAP_TSO4;
- if (virtio_with_feature(dev, VIRTIO_NET_F_HOST_TSO6))
- ifp->if_capabilities |= IFCAP_TSO6;
- if (virtio_with_feature(dev, VIRTIO_NET_F_HOST_ECN))
- sc->vtnet_flags |= VTNET_FLAG_TSO_ECN;
- }
- if (ifp->if_capabilities & IFCAP_TSO)
+ if (ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6))
ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
}
@@ -1007,7 +1025,8 @@
ifp->if_capabilities |= IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6;
if (virtio_with_feature(dev, VIRTIO_NET_F_GUEST_TSO4) ||
- virtio_with_feature(dev, VIRTIO_NET_F_GUEST_TSO6))
+ virtio_with_feature(dev, VIRTIO_NET_F_GUEST_TSO6) ||
+ virtio_with_feature(dev, VIRTIO_NET_F_GUEST_ECN))
ifp->if_capabilities |= IFCAP_LRO;
}
@@ -1027,7 +1046,6 @@
/*
* Capabilities after here are not enabled by default.
*/
-
if (sc->vtnet_flags & VTNET_FLAG_VLAN_FILTER) {
ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
@@ -1051,36 +1069,40 @@
return (0);
}
+/* BMV: This needs rethinking. */
static int
vtnet_change_mtu(struct vtnet_softc *sc, int new_mtu)
{
struct ifnet *ifp;
- int frame_size, clsize;
+ int frame_size, clustersz;
ifp = sc->vtnet_ifp;
if (new_mtu < ETHERMIN || new_mtu > VTNET_MAX_MTU)
return (EINVAL);
- frame_size = sc->vtnet_hdr_size + sizeof(struct ether_vlan_header) +
- new_mtu;
+ frame_size = sc->vtnet_hdr_size;
+ frame_size += sizeof(struct ether_vlan_header) + new_mtu;
/*
- * Based on the new MTU (and hence frame size) determine which
- * cluster size is most appropriate for the receive queues.
+ * Based on the new MTU, determine which cluster size is appropriate
+ * for the receive queues.
+ *
+ * BMV: This likely needs rethinking wrt LRO enabled/disabled and
+ * the size of the virtqueue.
*/
- if (frame_size <= MCLBYTES) {
- clsize = MCLBYTES;
- } else if ((sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS) == 0) {
- /* Avoid going past 9K jumbos. */
+ if (frame_size <= MCLBYTES)
+ clustersz = MCLBYTES;
+ else if (sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS)
+ clustersz = MJUMPAGESIZE;
+ else {
if (frame_size > MJUM9BYTES)
return (EINVAL);
- clsize = MJUM9BYTES;
- } else
- clsize = MJUMPAGESIZE;
+ clustersz = MJUM9BYTES;
+ }
ifp->if_mtu = new_mtu;
- sc->vtnet_rx_new_clsize = clsize;
+ sc->vtnet_rx_new_clustersz = clustersz;
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
@@ -1137,10 +1159,9 @@
case SIOCADDMULTI:
case SIOCDELMULTI:
- if ((sc->vtnet_flags & VTNET_FLAG_CTRL_RX) == 0)
- break;
VTNET_CORE_LOCK(sc);
- if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ if (sc->vtnet_flags & VTNET_FLAG_CTRL_RX &&
+ ifp->if_drv_flags & IFF_DRV_RUNNING)
vtnet_rx_filter_mac(sc);
VTNET_CORE_UNLOCK(sc);
break;
@@ -1268,27 +1289,27 @@
vtnet_rx_alloc_buf(struct vtnet_softc *sc, int nbufs, struct mbuf **m_tailp)
{
struct mbuf *m_head, *m_tail, *m;
- int i, clsize;
+ int i, clustersz;
- clsize = sc->vtnet_rx_clsize;
+ clustersz = sc->vtnet_rx_clustersz;
KASSERT(nbufs == 1 || sc->vtnet_flags & VTNET_FLAG_LRO_NOMRG,
("%s: chained mbuf %d request without LRO_NOMRG", __func__, nbufs));
- m_head = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, clsize);
+ m_head = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, clustersz);
if (m_head == NULL)
goto fail;
- m_head->m_len = clsize;
+ m_head->m_len = clustersz;
m_tail = m_head;
/* Allocate the rest of the chain. */
for (i = 1; i < nbufs; i++) {
- m = m_getjcl(M_NOWAIT, MT_DATA, 0, clsize);
+ m = m_getjcl(M_NOWAIT, MT_DATA, 0, clustersz);
if (m == NULL)
goto fail;
- m->m_len = clsize;
+ m->m_len = clustersz;
m_tail->m_next = m;
m_tail = m;
}
@@ -1315,10 +1336,10 @@
struct vtnet_softc *sc;
struct mbuf *m, *m_prev;
struct mbuf *m_new, *m_tail;
- int len, clsize, nreplace, error;
+ int len, clustersz, nreplace, error;
sc = rxq->vtnrx_sc;
- clsize = sc->vtnet_rx_clsize;
+ clustersz = sc->vtnet_rx_clustersz;
m_prev = NULL;
m_tail = NULL;
@@ -1344,9 +1365,9 @@
}
/* We always allocate the same cluster size. */
- KASSERT(m->m_len == clsize,
+ KASSERT(m->m_len == clustersz,
("%s: mbuf size %d is not the cluster size %d",
- __func__, m->m_len, clsize));
+ __func__, m->m_len, clustersz));
m->m_len = MIN(m->m_len, len);
len -= m->m_len;
@@ -1362,7 +1383,7 @@
m_new = vtnet_rx_alloc_buf(sc, nreplace, &m_tail);
if (m_new == NULL) {
- m_prev->m_len = clsize;
+ m_prev->m_len = clustersz;
return (ENOBUFS);
}
@@ -1392,7 +1413,7 @@
m_tail->m_next = NULL;
}
- m_prev->m_len = clsize;
+ m_prev->m_len = clustersz;
m_freem(m_new);
}
@@ -1442,39 +1463,40 @@
{
struct vtnet_softc *sc;
struct sglist *sg;
- struct vtnet_rx_header *rxhdr;
- uint8_t *mdata;
- int offset, error;
+ int error;
sc = rxq->vtnrx_sc;
sg = rxq->vtnrx_sg;
- mdata = mtod(m, uint8_t *);
+ KASSERT(m->m_next == NULL || sc->vtnet_flags & VTNET_FLAG_LRO_NOMRG,
+ ("%s: mbuf chain without LRO_NOMRG", __func__));
+ KASSERT(m->m_len == sc->vtnet_rx_clustersz, ("%s: unexpected mbuf "
+ "length %d %d", __func__, m->m_len, sc->vtnet_rx_clustersz));
VTNET_RXQ_LOCK_ASSERT(rxq);
- KASSERT(sc->vtnet_flags & VTNET_FLAG_LRO_NOMRG || m->m_next == NULL,
- ("%s: chained mbuf without LRO_NOMRG", __func__));
- KASSERT(m->m_len == sc->vtnet_rx_clsize,
- ("%s: unexpected cluster size %d/%d", __func__, m->m_len,
- sc->vtnet_rx_clsize));
sglist_reset(sg);
- if ((sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS) == 0) {
+ if (vtnet_modern(sc) || sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS) {
+ error = sglist_append_mbuf(sg, m);
+ } else {
+ struct vtnet_rx_header *rxhdr;
+
+ rxhdr = mtod(m, struct vtnet_rx_header *);
MPASS(sc->vtnet_hdr_size == sizeof(struct virtio_net_hdr));
- rxhdr = (struct vtnet_rx_header *) mdata;
- sglist_append(sg, &rxhdr->vrh_hdr, sc->vtnet_hdr_size);
- offset = sizeof(struct vtnet_rx_header);
- } else
- offset = 0;
- sglist_append(sg, mdata + offset, m->m_len - offset);
- if (m->m_next != NULL) {
- error = sglist_append_mbuf(sg, m->m_next);
- MPASS(error == 0);
+ /* Append inlined header and then rest of the mbuf chain. */
+ error = sglist_append(sg, &rxhdr->vrh_hdr, sc->vtnet_hdr_size);
+ if (error == 0) {
+ error = sglist_append(sg, &rxhdr[1],
+ m->m_len - sizeof(struct vtnet_rx_header));
+ }
+ if (error == 0 && m->m_next != NULL)
+ error = sglist_append_mbuf(sg, m->m_next);
}
- error = virtqueue_enqueue(rxq->vtnrx_vq, m, sg, 0, sg->sg_nseg);
+ if (error)
+ return (error);
- return (error);
+ return (virtqueue_enqueue(rxq->vtnrx_vq, m, sg, 0, sg->sg_nseg));
}
static int
@@ -1783,16 +1805,12 @@
struct vtnet_softc *sc;
struct ifnet *ifp;
struct virtqueue *vq;
- struct mbuf *m, *mr;
- struct virtio_net_hdr_mrg_rxbuf *mhdr;
+ struct mbuf *m;
int len, deq, nbufs, adjsz, count;
- pfil_return_t pfil;
- bool pfil_done;
sc = rxq->vtnrx_sc;
vq = rxq->vtnrx_vq;
ifp = sc->vtnet_ifp;
- hdr = &lhdr;
deq = 0;
count = sc->vtnet_rx_process_limit;
@@ -1810,49 +1828,23 @@
continue;
}
- if ((sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS) == 0) {
- nbufs = 1;
- adjsz = sizeof(struct vtnet_rx_header);
+ if (vtnet_modern(sc) ||
+ sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS) {
/*
- * Account for our pad inserted between the header
- * and the actual start of the frame.
+ * For our purposes here, the V1 header is the same as
+ * the mergeable buffers header.
*/
- len += VTNET_RX_HEADER_PAD;
- } else {
- mhdr = mtod(m, struct virtio_net_hdr_mrg_rxbuf *);
- nbufs = mhdr->num_buffers;
+ struct virtio_net_hdr_mrg_rxbuf *mhdr =
+ mtod(m, struct virtio_net_hdr_mrg_rxbuf *);
+ nbufs = vtnet_htog16(sc, mhdr->num_buffers);
adjsz = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ } else {
+ nbufs = 1;
+ adjsz = sizeof(struct vtnet_rx_header);
+ /* Our pad between the header and start of the frame. */
+ len += VTNET_RX_HEADER_PAD;
}
- /*
- * If we have enough data in first mbuf, run it through
- * pfil as a memory buffer before dequeueing the rest.
- */
- if (PFIL_HOOKED_IN(sc->vtnet_pfil) &&
- len - adjsz >= ETHER_HDR_LEN + max_protohdr) {
- pfil = pfil_run_hooks(sc->vtnet_pfil,
- m->m_data + adjsz, ifp,
- (len - adjsz) | PFIL_MEMPTR | PFIL_IN, NULL);
- switch (pfil) {
- case PFIL_REALLOCED:
- mr = pfil_mem2mbuf(m->m_data + adjsz);
- vtnet_rxq_input(rxq, mr, hdr);
- /* FALLTHROUGH */
- case PFIL_DROPPED:
- case PFIL_CONSUMED:
- vtnet_rxq_discard_buf(rxq, m);
- if (nbufs > 1)
- vtnet_rxq_discard_merged_bufs(rxq,
- nbufs);
- continue;
- default:
- KASSERT(pfil == PFIL_PASS,
- ("Filter returned %d!\n", pfil));
- };
- pfil_done = true;
- } else
- pfil_done = false;
-
if (vtnet_rxq_replace_buf(rxq, m, len) != 0) {
rxq->vtnrx_stats.vrxs_iqdrops++;
vtnet_rxq_discard_buf(rxq, m);
@@ -1872,31 +1864,39 @@
}
/*
- * Save copy of header before we strip it. For both mergeable
- * and non-mergeable, the header is at the beginning of the
- * mbuf data. We no longer need num_buffers, so always use a
- * regular header.
- *
- * BMV: Is this memcpy() expensive? We know the mbuf data is
- * still valid even after the m_adj().
+ * Save an endian swapped version of the header prior to it
+ * being stripped. For both mergeable and non-mergeable, the
+ * header is at the start of the mbuf data. num_buffers was
+ * already saved (and longer need it) so use a regular header.
*/
- memcpy(hdr, mtod(m, void *), sizeof(struct virtio_net_hdr));
+ hdr = mtod(m, struct virtio_net_hdr *);
+ lhdr.flags = hdr->flags;
+ lhdr.gso_type = hdr->gso_type;
+ lhdr.hdr_len = vtnet_htog16(sc, hdr->hdr_len);
+ lhdr.gso_size = vtnet_htog16(sc, hdr->gso_size);
+ lhdr.csum_start = vtnet_htog16(sc, hdr->csum_start);
+ lhdr.csum_offset = vtnet_htog16(sc, hdr->csum_offset);
m_adj(m, adjsz);
- if (PFIL_HOOKED_IN(sc->vtnet_pfil) && pfil_done == false) {
+ if (PFIL_HOOKED_IN(sc->vtnet_pfil)) {
+ pfil_return_t pfil;
+
pfil = pfil_run_hooks(sc->vtnet_pfil, &m, ifp, PFIL_IN,
NULL);
switch (pfil) {
+ case PFIL_REALLOCED:
+ m = pfil_mem2mbuf(m->m_data);
+ break;
case PFIL_DROPPED:
case PFIL_CONSUMED:
continue;
default:
KASSERT(pfil == PFIL_PASS,
- ("Filter returned %d!\n", pfil));
+ ("Filter returned %d!", pfil));
}
}
- vtnet_rxq_input(rxq, m, hdr);
+ vtnet_rxq_input(rxq, m, &lhdr);
/* Must recheck after dropping the Rx lock. */
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
@@ -2062,12 +2062,11 @@
}
/*
- * BMV: Much of this can go away once we finally have offsets in
- * the mbuf packet header. Bug andre@.
+ * BMV: This can go away once we finally have offsets in the mbuf header.
*/
static int
-vtnet_txq_offload_ctx(struct vtnet_txq *txq, struct mbuf *m,
- int *etype, int *proto, int *start)
+vtnet_txq_offload_ctx(struct vtnet_txq *txq, struct mbuf *m, int *etype,
+ int *proto, int *start)
{
struct vtnet_softc *sc;
struct ether_vlan_header *evh;
@@ -2135,8 +2134,8 @@
} else
tcp = (struct tcphdr *)(m->m_data + offset);
- hdr->hdr_len = offset + (tcp->th_off << 2);
- hdr->gso_size = m->m_pkthdr.tso_segsz;
+ hdr->hdr_len = vtnet_gtoh16(sc, offset + (tcp->th_off << 2));
+ hdr->gso_size = vtnet_gtoh16(sc, m->m_pkthdr.tso_segsz);
hdr->gso_type = eth_type == ETHERTYPE_IP ? VIRTIO_NET_HDR_GSO_TCPV4 :
VIRTIO_NET_HDR_GSO_TCPV6;
@@ -2181,8 +2180,8 @@
* but that really should not be necessary.
*/
hdr->flags |= VIRTIO_NET_HDR_F_NEEDS_CSUM;
- hdr->csum_start = csum_start;
- hdr->csum_offset = m->m_pkthdr.csum_data;
+ hdr->csum_start = vtnet_gtoh16(sc, csum_start);
+ hdr->csum_offset = vtnet_gtoh16(sc, m->m_pkthdr.csum_data);
txq->vtntx_stats.vtxs_csum++;
}
@@ -2226,8 +2225,11 @@
sglist_reset(sg);
error = sglist_append(sg, &txhdr->vth_uhdr, sc->vtnet_hdr_size);
- KASSERT(error == 0 && sg->sg_nseg == 1,
- ("%s: error %d adding header to sglist", __func__, error));
+ if (error != 0 || sg->sg_nseg != 1) {
+ KASSERT(0, ("%s: cannot add header to sglist error %d nseg %d",
+ __func__, error, sg->sg_nseg));
+ goto fail;
+ }
error = sglist_append_mbuf(sg, m);
if (error) {
@@ -2275,9 +2277,9 @@
}
/*
- * Always use the non-mergeable header, regardless if the feature
- * was negotiated. For transmit, num_buffers is always zero. The
- * vtnet_hdr_size is used to enqueue the correct header size.
+ * Always use the non-mergeable header, regardless if mergable headers
+ * were negotiated, because for transmit num_buffers is always zero.
+ * The vtnet_hdr_size is used to enqueue the right header size segment.
*/
hdr = &txhdr->vth_uhdr.hdr;
@@ -2299,11 +2301,9 @@
}
error = vtnet_txq_enqueue_buf(txq, m_head, txhdr);
- if (error == 0)
- return (0);
-
fail:
- uma_zfree(vtnet_tx_header_zone, txhdr);
+ if (error)
+ uma_zfree(vtnet_tx_header_zone, txhdr);
return (error);
}
@@ -2452,7 +2452,6 @@
sc = ifp->if_softc;
npairs = sc->vtnet_act_vq_pairs;
- /* check if flowid is set */
if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
i = m->m_pkthdr.flowid % npairs;
else
@@ -2983,7 +2982,7 @@
{
device_t dev;
struct vtnet_rxq *rxq;
- int i, clsize, error;
+ int i, clustersz, error;
dev = sc->vtnet_dev;
@@ -2994,14 +2993,14 @@
* BMV: It might make sense to use page sized clusters as
* the default (depending on the features negotiated).
*/
- if (sc->vtnet_rx_new_clsize != 0) {
- clsize = sc->vtnet_rx_new_clsize;
- sc->vtnet_rx_new_clsize = 0;
+ if (sc->vtnet_rx_new_clustersz != 0) {
+ clustersz = sc->vtnet_rx_new_clustersz;
+ sc->vtnet_rx_new_clustersz = 0;
} else
- clsize = MCLBYTES;
+ clustersz = MCLBYTES;
- sc->vtnet_rx_clsize = clsize;
- sc->vtnet_rx_nmbufs = VTNET_NEEDED_RX_MBUFS(sc, clsize);
+ sc->vtnet_rx_clustersz = clustersz;
+ sc->vtnet_rx_nmbufs = VTNET_NEEDED_RX_MBUFS(sc, clustersz);
KASSERT(sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS ||
sc->vtnet_rx_nmbufs < sc->vtnet_rx_nsegs,
@@ -3067,7 +3066,7 @@
dev = sc->vtnet_dev;
- if ((sc->vtnet_flags & VTNET_FLAG_MULTIQ) == 0) {
+ if ((sc->vtnet_flags & VTNET_FLAG_MQ) == 0) {
sc->vtnet_act_vq_pairs = 1;
return;
}
@@ -3181,16 +3180,13 @@
static void
vtnet_free_ctrl_vq(struct vtnet_softc *sc)
{
- struct virtqueue *vq;
-
- vq = sc->vtnet_ctrl_vq;
/*
* The control virtqueue is only polled and therefore it should
* already be empty.
*/
- KASSERT(virtqueue_empty(vq),
- ("%s: ctrl vq %p not empty", __func__, vq));
+ KASSERT(virtqueue_empty(sc->vtnet_ctrl_vq),
+ ("%s: ctrl vq %p not empty", __func__, sc->vtnet_ctrl_vq));
}
static void
@@ -3202,46 +3198,53 @@
vq = sc->vtnet_ctrl_vq;
VTNET_CORE_LOCK_ASSERT(sc);
- KASSERT(sc->vtnet_flags & VTNET_FLAG_CTRL_VQ,
- ("%s: CTRL_VQ feature not negotiated", __func__));
+ MPASS(sc->vtnet_flags & VTNET_FLAG_CTRL_VQ);
if (!virtqueue_empty(vq))
return;
- if (virtqueue_enqueue(vq, cookie, sg, readable, writable) != 0)
- return;
/*
- * Poll for the response, but the command is likely already
- * done when we return from the notify.
+ * Poll for the response, but the command is likely completed before
+ * returning from the notify.
*/
- virtqueue_notify(vq);
- virtqueue_poll(vq, NULL);
+ if (virtqueue_enqueue(vq, cookie, sg, readable, writable) == 0) {
+ virtqueue_notify(vq);
+ virtqueue_poll(vq, NULL);
+ }
}
static int
vtnet_ctrl_mac_cmd(struct vtnet_softc *sc, uint8_t *hwaddr)
{
- struct virtio_net_ctrl_hdr hdr __aligned(2);
struct sglist_seg segs[3];
struct sglist sg;
- uint8_t ack;
+ struct {
+ struct virtio_net_ctrl_hdr hdr __aligned(2);
+ uint8_t pad1;
+ uint8_t addr[ETHER_ADDR_LEN] __aligned(8);
+ uint8_t pad2;
+ uint8_t ack;
+ } s;
int error;
- hdr.class = VIRTIO_NET_CTRL_MAC;
- hdr.cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET;
- ack = VIRTIO_NET_ERR;
-
- sglist_init(&sg, 3, segs);
error = 0;
- error |= sglist_append(&sg, &hdr, sizeof(struct virtio_net_ctrl_hdr));
- error |= sglist_append(&sg, hwaddr, ETHER_ADDR_LEN);
- error |= sglist_append(&sg, &ack, sizeof(uint8_t));
- KASSERT(error == 0 && sg.sg_nseg == 3,
- ("%s: error %d adding set MAC msg to sglist", __func__, error));
+ MPASS(sc->vtnet_flags & VTNET_FLAG_CTRL_MAC);
+
+ s.hdr.class = VIRTIO_NET_CTRL_MAC;
+ s.hdr.cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET;
+ bcopy(hwaddr, &s.addr[0], ETHER_ADDR_LEN);
+ s.ack = VIRTIO_NET_ERR;
+
+ sglist_init(&sg, nitems(segs), segs);
+ error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr));
+ error |= sglist_append(&sg, &s.addr[0], ETHER_ADDR_LEN);
+ error |= sglist_append(&sg, &s.ack, sizeof(uint8_t));
+ MPASS(error == 0 && sg.sg_nseg == nitems(segs));
- vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg - 1, 1);
+ if (error == 0)
+ vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
- return (ack == VIRTIO_NET_OK ? 0 : EIO);
+ return (s.ack == VIRTIO_NET_OK ? 0 : EIO);
}
static int
@@ -3250,63 +3253,64 @@
struct sglist_seg segs[3];
struct sglist sg;
struct {
- struct virtio_net_ctrl_hdr hdr;
+ struct virtio_net_ctrl_hdr hdr __aligned(2);
uint8_t pad1;
- struct virtio_net_ctrl_mq mq;
+ struct virtio_net_ctrl_mq mq __aligned(2);
uint8_t pad2;
uint8_t ack;
- } s __aligned(2);
+ } s;
int error;
+ error = 0;
+ MPASS(sc->vtnet_flags & VTNET_FLAG_MQ);
+
s.hdr.class = VIRTIO_NET_CTRL_MQ;
s.hdr.cmd = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET;
- s.mq.virtqueue_pairs = npairs;
+ s.mq.virtqueue_pairs = vtnet_gtoh16(sc, npairs);
s.ack = VIRTIO_NET_ERR;
- sglist_init(&sg, 3, segs);
- error = 0;
+ sglist_init(&sg, nitems(segs), segs);
error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr));
error |= sglist_append(&sg, &s.mq, sizeof(struct virtio_net_ctrl_mq));
error |= sglist_append(&sg, &s.ack, sizeof(uint8_t));
- KASSERT(error == 0 && sg.sg_nseg == 3,
- ("%s: error %d adding MQ message to sglist", __func__, error));
+ MPASS(error == 0 && sg.sg_nseg == nitems(segs));
- vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
+ if (error == 0)
+ vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
return (s.ack == VIRTIO_NET_OK ? 0 : EIO);
}
static int
-vtnet_ctrl_rx_cmd(struct vtnet_softc *sc, int cmd, int on)
+vtnet_ctrl_rx_cmd(struct vtnet_softc *sc, uint8_t cmd, int on)
{
struct sglist_seg segs[3];
struct sglist sg;
struct {
- struct virtio_net_ctrl_hdr hdr;
+ struct virtio_net_ctrl_hdr hdr __aligned(2);
uint8_t pad1;
uint8_t onoff;
uint8_t pad2;
uint8_t ack;
- } s __aligned(2);
+ } s;
int error;
- KASSERT(sc->vtnet_flags & VTNET_FLAG_CTRL_RX,
- ("%s: CTRL_RX feature not negotiated", __func__));
+ error = 0;
+ MPASS(sc->vtnet_flags & VTNET_FLAG_CTRL_RX);
s.hdr.class = VIRTIO_NET_CTRL_RX;
s.hdr.cmd = cmd;
s.onoff = !!on;
s.ack = VIRTIO_NET_ERR;
- sglist_init(&sg, 3, segs);
- error = 0;
+ sglist_init(&sg, nitems(segs), segs);
error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr));
error |= sglist_append(&sg, &s.onoff, sizeof(uint8_t));
error |= sglist_append(&sg, &s.ack, sizeof(uint8_t));
- KASSERT(error == 0 && sg.sg_nseg == 3,
- ("%s: error %d adding Rx message to sglist", __func__, error));
+ MPASS(error == 0 && sg.sg_nseg == nitems(segs));
- vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
+ if (error == 0)
+ vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
return (s.ack == VIRTIO_NET_OK ? 0 : EIO);
}
@@ -3314,14 +3318,12 @@
static int
vtnet_set_promisc(struct vtnet_softc *sc, int on)
{
-
return (vtnet_ctrl_rx_cmd(sc, VIRTIO_NET_CTRL_RX_PROMISC, on));
}
static int
vtnet_set_allmulti(struct vtnet_softc *sc, int on)
{
-
return (vtnet_ctrl_rx_cmd(sc, VIRTIO_NET_CTRL_RX_ALLMULTI, on));
}
@@ -3358,13 +3360,15 @@
VTNET_CORE_LOCK_ASSERT(sc);
- if (vtnet_set_promisc(sc, ifp->if_flags & IFF_PROMISC) != 0)
+ if (vtnet_set_promisc(sc, ifp->if_flags & IFF_PROMISC) != 0) {
device_printf(dev, "cannot %s promiscuous mode\n",
ifp->if_flags & IFF_PROMISC ? "enable" : "disable");
+ }
- if (vtnet_set_allmulti(sc, ifp->if_flags & IFF_ALLMULTI) != 0)
+ if (vtnet_set_allmulti(sc, ifp->if_flags & IFF_ALLMULTI) != 0) {
device_printf(dev, "cannot %s all-multicast mode\n",
ifp->if_flags & IFF_ALLMULTI ? "enable" : "disable");
+ }
}
static u_int
@@ -3410,55 +3414,54 @@
ifp = sc->vtnet_ifp;
filter = sc->vtnet_mac_filter;
+ error = 0;
+ MPASS(sc->vtnet_flags & VTNET_FLAG_CTRL_RX);
VTNET_CORE_LOCK_ASSERT(sc);
- KASSERT(sc->vtnet_flags & VTNET_FLAG_CTRL_RX,
- ("%s: CTRL_RX feature not negotiated", __func__));
/* Unicast MAC addresses: */
ucnt = if_foreach_lladdr(ifp, vtnet_copy_ifaddr, sc);
promisc = (ucnt > VTNET_MAX_MAC_ENTRIES);
if (promisc) {
- filter->vmf_unicast.nentries = 0;
+ ucnt = 0;
if_printf(ifp, "more than %d MAC addresses assigned, "
"falling back to promiscuous mode\n",
VTNET_MAX_MAC_ENTRIES);
- } else
- filter->vmf_unicast.nentries = ucnt;
+ }
/* Multicast MAC addresses: */
mcnt = if_foreach_llmaddr(ifp, vtnet_copy_maddr, filter);
allmulti = (mcnt > VTNET_MAX_MAC_ENTRIES);
if (allmulti) {
- filter->vmf_multicast.nentries = 0;
+ mcnt = 0;
if_printf(ifp, "more than %d multicast MAC addresses "
"assigned, falling back to all-multicast mode\n",
VTNET_MAX_MAC_ENTRIES);
- } else
- filter->vmf_multicast.nentries = mcnt;
+ }
if (promisc && allmulti)
goto out;
+ filter->vmf_unicast.nentries = vtnet_gtoh32(sc, ucnt);
+ filter->vmf_multicast.nentries = vtnet_gtoh32(sc, mcnt);
+
hdr.class = VIRTIO_NET_CTRL_MAC;
hdr.cmd = VIRTIO_NET_CTRL_MAC_TABLE_SET;
ack = VIRTIO_NET_ERR;
- sglist_init(&sg, 4, segs);
- error = 0;
+ sglist_init(&sg, nitems(segs), segs);
error |= sglist_append(&sg, &hdr, sizeof(struct virtio_net_ctrl_hdr));
error |= sglist_append(&sg, &filter->vmf_unicast,
- sizeof(uint32_t) + filter->vmf_unicast.nentries * ETHER_ADDR_LEN);
+ sizeof(uint32_t) + ucnt * ETHER_ADDR_LEN);
error |= sglist_append(&sg, &filter->vmf_multicast,
- sizeof(uint32_t) + filter->vmf_multicast.nentries * ETHER_ADDR_LEN);
+ sizeof(uint32_t) + mcnt * ETHER_ADDR_LEN);
error |= sglist_append(&sg, &ack, sizeof(uint8_t));
- KASSERT(error == 0 && sg.sg_nseg == 4,
- ("%s: error %d adding MAC filter msg to sglist", __func__, error));
-
- vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg - 1, 1);
+ MPASS(error == 0 && sg.sg_nseg == nitems(segs));
+ if (error == 0)
+ vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg - 1, 1);
if (ack != VIRTIO_NET_OK)
if_printf(ifp, "error setting host MAC filter table\n");
@@ -3475,28 +3478,30 @@
struct sglist_seg segs[3];
struct sglist sg;
struct {
- struct virtio_net_ctrl_hdr hdr;
+ struct virtio_net_ctrl_hdr hdr __aligned(2);
uint8_t pad1;
- uint16_t tag;
+ uint16_t tag __aligned(2);
uint8_t pad2;
uint8_t ack;
- } s __aligned(2);
+ } s;
int error;
+ error = 0;
+ MPASS(sc->vtnet_flags & VTNET_FLAG_VLAN_FILTER);
+
s.hdr.class = VIRTIO_NET_CTRL_VLAN;
s.hdr.cmd = add ? VIRTIO_NET_CTRL_VLAN_ADD : VIRTIO_NET_CTRL_VLAN_DEL;
- s.tag = tag;
+ s.tag = vtnet_gtoh16(sc, tag);
s.ack = VIRTIO_NET_ERR;
- sglist_init(&sg, 3, segs);
- error = 0;
+ sglist_init(&sg, nitems(segs), segs);
error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr));
error |= sglist_append(&sg, &s.tag, sizeof(uint16_t));
error |= sglist_append(&sg, &s.ack, sizeof(uint8_t));
- KASSERT(error == 0 && sg.sg_nseg == 3,
- ("%s: error %d adding VLAN message to sglist", __func__, error));
+ MPASS(error == 0 && sg.sg_nseg == nitems(segs));
- vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
+ if (error == 0)
+ vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1);
return (s.ack == VIRTIO_NET_OK ? 0 : EIO);
}
@@ -3504,13 +3509,12 @@
static void
vtnet_rx_filter_vlan(struct vtnet_softc *sc)
{
+ int i, bit;
uint32_t w;
uint16_t tag;
- int i, bit;
+ MPASS(sc->vtnet_flags & VTNET_FLAG_VLAN_FILTER);
VTNET_CORE_LOCK_ASSERT(sc);
- KASSERT(sc->vtnet_flags & VTNET_FLAG_VLAN_FILTER,
- ("%s: VLAN_FILTER feature not negotiated", __func__));
/* Enable the filter for each configured VLAN. */
for (i = 0; i < VTNET_VLAN_FILTER_NWORDS; i++) {
@@ -3657,15 +3661,18 @@
vtnet_set_hwaddr(struct vtnet_softc *sc)
{
device_t dev;
- int i;
dev = sc->vtnet_dev;
if (sc->vtnet_flags & VTNET_FLAG_CTRL_MAC) {
if (vtnet_ctrl_mac_cmd(sc, sc->vtnet_hwaddr) != 0)
device_printf(dev, "unable to set MAC address\n");
- } else if (sc->vtnet_flags & VTNET_FLAG_MAC) {
- for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ return;
+ }
+
+ /* In modern VirtIO the MAC config is read-only. */
+ if (!vtnet_modern(sc) && sc->vtnet_flags & VTNET_FLAG_MAC) {
+ for (int i = 0; i < ETHER_ADDR_LEN; i++) {
virtio_write_dev_config_1(dev,
offsetof(struct virtio_net_config, mac) + i,
sc->vtnet_hwaddr[i]);
@@ -3676,28 +3683,17 @@
static void
vtnet_get_hwaddr(struct vtnet_softc *sc)
{
- device_t dev;
- int i;
- dev = sc->vtnet_dev;
-
- if ((sc->vtnet_flags & VTNET_FLAG_MAC) == 0) {
- /*
- * Generate a random locally administered unicast address.
- *
- * It would be nice to generate the same MAC address across
- * reboots, but it seems all the hosts currently available
- * support the MAC feature, so this isn't too important.
- */
+ if (sc->vtnet_flags & VTNET_FLAG_MAC) {
+ virtio_read_device_config_array(sc->vtnet_dev,
+ offsetof(struct virtio_net_config, mac),
+ &sc->vtnet_hwaddr[0], sizeof(uint8_t), ETHER_ADDR_LEN);
+ } else {
+ /* Generate a random locally administered unicast address. */
sc->vtnet_hwaddr[0] = 0xB2;
arc4rand(&sc->vtnet_hwaddr[1], ETHER_ADDR_LEN - 1, 0);
+ /* BMV: FIXME Cannot do before DRIVER_OK! See 3.1.2 */
vtnet_set_hwaddr(sc);
- return;
- }
-
- for (i = 0; i < ETHER_ADDR_LEN; i++) {
- sc->vtnet_hwaddr[i] = virtio_read_dev_config_1(dev,
- offsetof(struct virtio_net_config, mac) + i);
}
}
@@ -3938,10 +3934,10 @@
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "max_vq_pairs",
CTLFLAG_RD, &sc->vtnet_max_vq_pairs, 0,
- "Maximum number of supported virtqueue pairs");
+ "Number of maximum supported virtqueue pairs");
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "requested_vq_pairs",
CTLFLAG_RD, &sc->vtnet_requested_vq_pairs, 0,
- "Requested number of virtqueue pairs");
+ "Number of requested virtqueue pairs");
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "act_vq_pairs",
CTLFLAG_RD, &sc->vtnet_act_vq_pairs, 0,
"Number of active virtqueue pairs");
@@ -4061,8 +4057,7 @@
VTNET_CORE_LOCK(sc);
*nrxr = sc->vtnet_max_vq_pairs;
- *ncl = DEBUGNET_MAX_IN_FLIGHT;
- *clsize = sc->vtnet_rx_clsize;
+ *clsize = sc->vtnet_rx_clustersz;
VTNET_CORE_UNLOCK(sc);
}
Index: sys/dev/virtio/network/if_vtnetvar.h
===================================================================
--- sys/dev/virtio/network/if_vtnetvar.h
+++ sys/dev/virtio/network/if_vtnetvar.h
@@ -140,7 +140,7 @@
pfil_head_t vtnet_pfil;
uint32_t vtnet_flags;
-#define VTNET_FLAG_SUSPENDED 0x0001
+#define VTNET_FLAG_MODERN 0x0001
#define VTNET_FLAG_MAC 0x0002
#define VTNET_FLAG_CTRL_VQ 0x0004
#define VTNET_FLAG_CTRL_RX 0x0008
@@ -149,17 +149,18 @@
#define VTNET_FLAG_TSO_ECN 0x0040
#define VTNET_FLAG_MRG_RXBUFS 0x0080
#define VTNET_FLAG_LRO_NOMRG 0x0100
-#define VTNET_FLAG_MULTIQ 0x0200
+#define VTNET_FLAG_MQ 0x0200
#define VTNET_FLAG_INDIRECT 0x0400
#define VTNET_FLAG_EVENT_IDX 0x0800
+#define VTNET_FLAG_SUSPENDED 0x1000
int vtnet_link_active;
int vtnet_hdr_size;
int vtnet_rx_process_limit;
int vtnet_rx_nsegs;
int vtnet_rx_nmbufs;
- int vtnet_rx_clsize;
- int vtnet_rx_new_clsize;
+ int vtnet_rx_clustersz;
+ int vtnet_rx_new_clustersz;
int vtnet_tx_intr_thresh;
int vtnet_tx_nsegs;
int vtnet_if_flags;
@@ -183,6 +184,12 @@
char vtnet_hwaddr[ETHER_ADDR_LEN];
};
+static bool
+vtnet_modern(struct vtnet_softc *sc)
+{
+ return ((sc->vtnet_flags & VTNET_FLAG_MODERN) != 0);
+}
+
/*
* Maximum number of queue pairs we will autoconfigure to.
*/
@@ -215,14 +222,19 @@
*/
#define VTNET_VLAN_FILTER_NWORDS (4096 / 32)
+/* We depend on these being the same size (and same layout). */
+CTASSERT(sizeof(struct virtio_net_hdr_mrg_rxbuf) ==
+ sizeof(struct virtio_net_hdr_v1));
+
/*
- * When mergeable buffers are not negotiated, the vtnet_rx_header structure
- * below is placed at the beginning of the mbuf data. Use 4 bytes of pad to
- * both keep the VirtIO header and the data non-contiguous and to keep the
- * frame's payload 4 byte aligned.
+ * In legacy VirtIO when mergeable buffers are not negotiated, this structure
+ * is placed at the beginning of the mbuf data. Use 4 bytes of pad to keep
+ * both the VirtIO header and the data non-contiguous and the frame's payload
+ * 4 byte aligned. Note this padding would not be necessary if the
+ * VIRTIO_F_ANY_LAYOUT feature was negotiated (but we don't support that yet).
*
- * When mergeable buffers are negotiated, the host puts the VirtIO header in
- * the beginning of the first mbuf's data.
+ * In modern VirtIO or when mergeable buffers are negotiated, the host puts
+ * the VirtIO header in the beginning of the first mbuf's data.
*/
#define VTNET_RX_HEADER_PAD 4
struct vtnet_rx_header {
@@ -238,6 +250,7 @@
union {
struct virtio_net_hdr hdr;
struct virtio_net_hdr_mrg_rxbuf mhdr;
+ struct virtio_net_hdr_v1 v1hdr;
} vth_uhdr;
struct mbuf *vth_mbuf;
@@ -252,6 +265,11 @@
*/
#define VTNET_MAX_MAC_ENTRIES 128
+/*
+ * The driver version of struct virtio_net_ctrl_mac but with our predefined
+ * number of MAC addresses allocated. This structure is shared with the host,
+ * so nentries field is in the correct VirtIO endianness.
+ */
struct vtnet_mac_table {
uint32_t nentries;
uint8_t macs[VTNET_MAX_MAC_ENTRIES][ETHER_ADDR_LEN];
@@ -276,8 +294,7 @@
#define VTNET_CSUM_ALL_OFFLOAD \
(VTNET_CSUM_OFFLOAD | VTNET_CSUM_OFFLOAD_IPV6 | CSUM_TSO)
-/* Features desired/implemented by this driver. */
-#define VTNET_FEATURES \
+#define VTNET_COMMON_FEATURES \
(VIRTIO_NET_F_MAC | \
VIRTIO_NET_F_STATUS | \
VIRTIO_NET_F_CTRL_VQ | \
@@ -285,7 +302,6 @@
VIRTIO_NET_F_CTRL_MAC_ADDR | \
VIRTIO_NET_F_CTRL_VLAN | \
VIRTIO_NET_F_CSUM | \
- VIRTIO_NET_F_GSO | \
VIRTIO_NET_F_HOST_TSO4 | \
VIRTIO_NET_F_HOST_TSO6 | \
VIRTIO_NET_F_HOST_ECN | \
@@ -298,6 +314,9 @@
VIRTIO_RING_F_EVENT_IDX | \
VIRTIO_RING_F_INDIRECT_DESC)
+#define VTNET_MODERN_FEATURES (VTNET_COMMON_FEATURES)
+#define VTNET_LEGACY_FEATURES (VTNET_COMMON_FEATURES | VIRTIO_NET_F_GSO)
+
/*
* The VIRTIO_NET_F_HOST_TSO[46] features permit us to send the host
* frames larger than 1514 bytes.
@@ -317,11 +336,12 @@
#define VTNET_MAX_RX_SIZE 65550
/*
- * Used to preallocate the Vq indirect descriptors. The first segment
- * is reserved for the header, except for mergeable buffers since the
- * header is placed inline with the data.
+ * Used to preallocate the Vq indirect descriptors. The first segment is
+ * reserved for the header, except for mergeable buffers or modern since
+ * the header is placed inline with the data.
*/
#define VTNET_MRG_RX_SEGS 1
+#define VTNET_MODERN_RX_SEGS 1
#define VTNET_MIN_RX_SEGS 2
#define VTNET_MAX_RX_SEGS 34
#define VTNET_MIN_TX_SEGS 32
@@ -345,10 +365,10 @@
* mergeable buffers, we must allocate an mbuf chain large enough to
* hold both the vtnet_rx_header and the maximum receivable data.
*/
-#define VTNET_NEEDED_RX_MBUFS(_sc, _clsize) \
+#define VTNET_NEEDED_RX_MBUFS(_sc, _clustersz) \
((_sc)->vtnet_flags & VTNET_FLAG_LRO_NOMRG) == 0 ? 1 : \
howmany(sizeof(struct vtnet_rx_header) + VTNET_MAX_RX_SIZE, \
- (_clsize))
+ (_clustersz))
#define VTNET_CORE_MTX(_sc) &(_sc)->vtnet_mtx
#define VTNET_CORE_LOCK(_sc) mtx_lock(VTNET_CORE_MTX((_sc)))
Index: sys/dev/virtio/network/virtio_net.h
===================================================================
--- sys/dev/virtio/network/virtio_net.h
+++ sys/dev/virtio/network/virtio_net.h
@@ -34,29 +34,33 @@
#define _VIRTIO_NET_H
/* The feature bitmap for virtio net */
-#define VIRTIO_NET_F_CSUM 0x00001 /* Host handles pkts w/ partial csum */
-#define VIRTIO_NET_F_GUEST_CSUM 0x00002 /* Guest handles pkts w/ partial csum*/
-#define VIRTIO_NET_F_MAC 0x00020 /* Host has given MAC address. */
-#define VIRTIO_NET_F_GSO 0x00040 /* Host handles pkts w/ any GSO type */
-#define VIRTIO_NET_F_GUEST_TSO4 0x00080 /* Guest can handle TSOv4 in. */
-#define VIRTIO_NET_F_GUEST_TSO6 0x00100 /* Guest can handle TSOv6 in. */
-#define VIRTIO_NET_F_GUEST_ECN 0x00200 /* Guest can handle TSO[6] w/ ECN in.*/
-#define VIRTIO_NET_F_GUEST_UFO 0x00400 /* Guest can handle UFO in. */
-#define VIRTIO_NET_F_HOST_TSO4 0x00800 /* Host can handle TSOv4 in. */
-#define VIRTIO_NET_F_HOST_TSO6 0x01000 /* Host can handle TSOv6 in. */
-#define VIRTIO_NET_F_HOST_ECN 0x02000 /* Host can handle TSO[6] w/ ECN in. */
-#define VIRTIO_NET_F_HOST_UFO 0x04000 /* Host can handle UFO in. */
-#define VIRTIO_NET_F_MRG_RXBUF 0x08000 /* Host can merge receive buffers. */
-#define VIRTIO_NET_F_STATUS 0x10000 /* virtio_net_config.status available*/
-#define VIRTIO_NET_F_CTRL_VQ 0x20000 /* Control channel available */
-#define VIRTIO_NET_F_CTRL_RX 0x40000 /* Control channel RX mode support */
-#define VIRTIO_NET_F_CTRL_VLAN 0x80000 /* Control channel VLAN filtering */
-#define VIRTIO_NET_F_CTRL_RX_EXTRA 0x100000 /* Extra RX mode control support */
-#define VIRTIO_NET_F_GUEST_ANNOUNCE 0x200000 /* Announce device on network */
-#define VIRTIO_NET_F_MQ 0x400000 /* Device supports RFS */
-#define VIRTIO_NET_F_CTRL_MAC_ADDR 0x800000 /* Set MAC address */
+#define VIRTIO_NET_F_CSUM 0x000001 /* Host handles pkts w/ partial csum */
+#define VIRTIO_NET_F_GUEST_CSUM 0x000002 /* Guest handles pkts w/ partial csum*/
+#define VIRTIO_NET_F_CTRL_GUEST_OFFLOADS 0x000004 /* Dynamic offload configuration. */
+#define VIRTIO_NET_F_MTU 0x000008 /* Initial MTU advice */
+#define VIRTIO_NET_F_MAC 0x000020 /* Host has given MAC address. */
+#define VIRTIO_NET_F_GSO 0x000040 /* Host handles pkts w/ any GSO type */
+#define VIRTIO_NET_F_GUEST_TSO4 0x000080 /* Guest can handle TSOv4 in. */
+#define VIRTIO_NET_F_GUEST_TSO6 0x000100 /* Guest can handle TSOv6 in. */
+#define VIRTIO_NET_F_GUEST_ECN 0x000200 /* Guest can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_GUEST_UFO 0x000400 /* Guest can handle UFO in. */
+#define VIRTIO_NET_F_HOST_TSO4 0x000800 /* Host can handle TSOv4 in. */
+#define VIRTIO_NET_F_HOST_TSO6 0x001000 /* Host can handle TSOv6 in. */
+#define VIRTIO_NET_F_HOST_ECN 0x002000 /* Host can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_HOST_UFO 0x004000 /* Host can handle UFO in. */
+#define VIRTIO_NET_F_MRG_RXBUF 0x008000 /* Host can merge receive buffers. */
+#define VIRTIO_NET_F_STATUS 0x010000 /* virtio_net_config.status available*/
+#define VIRTIO_NET_F_CTRL_VQ 0x020000 /* Control channel available */
+#define VIRTIO_NET_F_CTRL_RX 0x040000 /* Control channel RX mode support */
+#define VIRTIO_NET_F_CTRL_VLAN 0x080000 /* Control channel VLAN filtering */
+#define VIRTIO_NET_F_CTRL_RX_EXTRA 0x100000 /* Extra RX mode control support */
+#define VIRTIO_NET_F_GUEST_ANNOUNCE 0x200000 /* Announce device on network */
+#define VIRTIO_NET_F_MQ 0x400000 /* Device supports Receive Flow Steering */
+#define VIRTIO_NET_F_CTRL_MAC_ADDR 0x800000 /* Set MAC address */
+#define VIRTIO_NET_F_SPEED_DUPLEX (1ULL << 63) /* Device set linkspeed and duplex */
#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */
+#define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */
struct virtio_net_config {
/* The config defining mac address (if VIRTIO_NET_F_MAC) */
@@ -68,16 +72,32 @@
* Legal values are between 1 and 0x8000.
*/
uint16_t max_virtqueue_pairs;
+ /* Default maximum transmit unit advice */
+ uint16_t mtu;
+ /*
+ * speed, in units of 1Mb. All values 0 to INT_MAX are legal.
+ * Any other value stands for unknown.
+ */
+ uint32_t speed;
+ /*
+ * 0x00 - half duplex
+ * 0x01 - full duplex
+ * Any other value stands for unknown.
+ */
+ uint8_t duplex;
} __packed;
/*
- * This is the first element of the scatter-gather list. If you don't
+ * This header comes first in the scatter-gather list. If you don't
* specify GSO or CSUM features, you can simply ignore the header.
+ *
+ * This is bitwise-equivalent to the legacy struct virtio_net_hdr_mrg_rxbuf,
+ * only flattened.
*/
-struct virtio_net_hdr {
-#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start,csum_offset*/
+struct virtio_net_hdr_v1 {
+#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start, csum_offset */
#define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */
- uint8_t flags;
+ uint8_t flags;
#define VIRTIO_NET_HDR_GSO_NONE 0 /* Not a GSO frame */
#define VIRTIO_NET_HDR_GSO_TCPV4 1 /* GSO frame, IPv4 TCP (TSO) */
#define VIRTIO_NET_HDR_GSO_UDP 3 /* GSO frame, IPv4 UDP (UFO) */
@@ -88,6 +108,24 @@
uint16_t gso_size; /* Bytes to append to hdr_len per frame */
uint16_t csum_start; /* Position to start checksumming from */
uint16_t csum_offset; /* Offset after that to place checksum */
+ uint16_t num_buffers; /* Number of merged rx buffers */
+};
+
+/*
+ * This header comes first in the scatter-gather list.
+ * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must
+ * be the first element of the scatter-gather list. If you don't
+ * specify GSO or CSUM features, you can simply ignore the header.
+ */
+struct virtio_net_hdr {
+ /* See VIRTIO_NET_HDR_F_* */
+ uint8_t flags;
+ /* See VIRTIO_NET_HDR_GSO_* */
+ uint8_t gso_type;
+ uint16_t hdr_len; /* Ethernet + IP + tcp/udp hdrs */
+ uint16_t gso_size; /* Bytes to append to hdr_len per frame */
+ uint16_t csum_start; /* Position to start checksumming from */
+ uint16_t csum_offset; /* Offset after that to place checksum */
};
/*
@@ -201,6 +239,21 @@
#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN 1
#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX 0x8000
+/*
+ * Control network offloads
+ *
+ * Reconfigures the network offloads that Guest can handle.
+ *
+ * Available with the VIRTIO_NET_F_CTRL_GUEST_OFFLOADS feature bit.
+ *
+ * Command data format matches the feature bit mask exactly.
+ *
+ * See VIRTIO_NET_F_GUEST_* for the list of offloads
+ * that can be enabled/disabled.
+ */
+#define VIRTIO_NET_CTRL_GUEST_OFFLOADS 5
+#define VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET 0
+
/*
* Use the checksum offset in the VirtIO header to set the
* correct CSUM_* flags.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Oct 18, 5:53 PM (4 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23888204
Default Alt Text
D27904.id81527.diff (48 KB)
Attached To
Mode
D27904: if_vtnet: Add initial modern (V1) support
Attached
Detach File
Event Timeline
Log In to Comment