summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/vioif
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/io/vioif')
-rw-r--r--usr/src/uts/common/io/vioif/vioif.c81
-rw-r--r--usr/src/uts/common/io/vioif/vioif.h2
2 files changed, 79 insertions, 4 deletions
diff --git a/usr/src/uts/common/io/vioif/vioif.c b/usr/src/uts/common/io/vioif/vioif.c
index e1535182b3..cac90d3073 100644
--- a/usr/src/uts/common/io/vioif/vioif.c
+++ b/usr/src/uts/common/io/vioif/vioif.c
@@ -74,6 +74,7 @@
#include <sys/random.h>
#include <sys/containerof.h>
#include <sys/stream.h>
+#include <inet/tcp.h>
#include <sys/mac.h>
#include <sys/mac_provider.h>
@@ -1018,7 +1019,7 @@ vioif_send(vioif_t *vif, mblk_t *mp)
for (nmp = mp; nmp; nmp = nmp->b_cont)
msg_size += MBLKL(nmp);
- if (vif->vif_tx_tso4) {
+ if (vif->vif_tx_tso4 || vif->vif_tx_tso6) {
mac_lso_get(mp, &lso_mss, &lso_flags);
lso_required = (lso_flags & HW_LSO) != 0;
}
@@ -1084,8 +1085,70 @@ vioif_send(vioif_t *vif, mblk_t *mp)
* Setup LSO fields if required.
*/
if (lso_required) {
- vnh->vnh_gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+ mac_ether_offload_flags_t needed;
+ mac_ether_offload_info_t meo;
+ uint32_t cksum;
+ size_t len;
+ mblk_t *pullmp = NULL;
+ tcpha_t *tcpha;
+
+ if (mac_ether_offload_info(mp, &meo) != 0) {
+ goto fail;
+ }
+
+ needed = MEOI_L2INFO_SET | MEOI_L3INFO_SET | MEOI_L4INFO_SET;
+ if ((meo.meoi_flags & needed) != needed) {
+ goto fail;
+ }
+
+ if (meo.meoi_l4proto != IPPROTO_TCP) {
+ goto fail;
+ }
+
+ if (meo.meoi_l3proto == ETHERTYPE_IP && vif->vif_tx_tso4) {
+ vnh->vnh_gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+ } else if (meo.meoi_l3proto == ETHERTYPE_IPV6 &&
+ vif->vif_tx_tso6) {
+ vnh->vnh_gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ } else {
+ goto fail;
+ }
+
+ /*
+ * The TCP stack does not include the length in the TCP
+ * pseudo-header when it is performing LSO since hardware
+ * generally asks for it to be removed (as it'll change).
+ * Unfortunately, for virtio, we actually need it. This means we
+ * need to go through and calculate the actual length and fix
+ * things up. Because the virtio spec cares about the ECN flag
+ * and indicating that, at least this means we'll have that
+ * available as well.
+ */
+ if (MBLKL(mp) < vnh->vnh_hdr_len) {
+ pullmp = msgpullup(mp, vnh->vnh_hdr_len);
+ if (pullmp == NULL)
+ goto fail;
+ tcpha = (tcpha_t *)(pullmp->b_rptr + meo.meoi_l2hlen +
+ meo.meoi_l3hlen);
+ } else {
+ tcpha = (tcpha_t *)(mp->b_rptr + meo.meoi_l2hlen +
+ meo.meoi_l3hlen);
+ }
+
+ len = meo.meoi_len - meo.meoi_l2hlen - meo.meoi_l3hlen;
+ cksum = ntohs(tcpha->tha_sum) + len;
+ cksum = (cksum >> 16) + (cksum & 0xffff);
+ cksum = (cksum >> 16) + (cksum & 0xffff);
+ tcpha->tha_sum = htons(cksum);
+
+ if (tcpha->tha_flags & TH_CWR) {
+ vnh->vnh_gso_type |= VIRTIO_NET_HDR_GSO_ECN;
+ }
vnh->vnh_gso_size = (uint16_t)lso_mss;
+ vnh->vnh_hdr_len = meo.meoi_l2hlen + meo.meoi_l3hlen +
+ meo.meoi_l4hlen;
+
+ freemsg(pullmp);
}
/*
@@ -1453,8 +1516,9 @@ vioif_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
}
mac_capab_lso_t *lso = cap_data;
- lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
+ lso->lso_flags = LSO_TX_BASIC_TCP_IPV4 | LSO_TX_BASIC_TCP_IPV6;
lso->lso_basic_tcp_ipv4.lso_max = VIOIF_RX_DATA_SIZE;
+ lso->lso_basic_tcp_ipv6.lso_max = VIOIF_RX_DATA_SIZE;
return (B_TRUE);
}
@@ -1556,6 +1620,7 @@ vioif_check_features(vioif_t *vif)
vif->vif_tx_csum = 0;
vif->vif_tx_tso4 = 0;
+ vif->vif_tx_tso6 = 0;
if (vioif_has_feature(vif, VIRTIO_NET_F_CSUM)) {
/*
@@ -1569,6 +1634,7 @@ vioif_check_features(vioif_t *vif)
*/
boolean_t gso = vioif_has_feature(vif, VIRTIO_NET_F_GSO);
boolean_t tso4 = vioif_has_feature(vif, VIRTIO_NET_F_HOST_TSO4);
+ boolean_t tso6 = vioif_has_feature(vif, VIRTIO_NET_F_HOST_TSO6);
boolean_t ecn = vioif_has_feature(vif, VIRTIO_NET_F_HOST_ECN);
/*
@@ -1578,8 +1644,15 @@ vioif_check_features(vioif_t *vif)
* we require the device to support the combination of
* segmentation offload and ECN support.
*/
- if (gso || (tso4 && ecn)) {
+ if (gso) {
vif->vif_tx_tso4 = 1;
+ vif->vif_tx_tso6 = 1;
+ }
+ if (tso4 && ecn) {
+ vif->vif_tx_tso4 = 1;
+ }
+ if (tso6 && ecn) {
+ vif->vif_tx_tso6 = 1;
}
}
}
diff --git a/usr/src/uts/common/io/vioif/vioif.h b/usr/src/uts/common/io/vioif/vioif.h
index 19d8965bd4..9f750c9b8a 100644
--- a/usr/src/uts/common/io/vioif/vioif.h
+++ b/usr/src/uts/common/io/vioif/vioif.h
@@ -164,6 +164,7 @@ extern "C" {
#define VIRTIO_NET_WANTED_FEATURES (VIRTIO_NET_F_CSUM | \
VIRTIO_NET_F_GSO | \
VIRTIO_NET_F_HOST_TSO4 | \
+ VIRTIO_NET_F_HOST_TSO6 | \
VIRTIO_NET_F_HOST_ECN | \
VIRTIO_NET_F_MAC | \
VIRTIO_NET_F_MTU)
@@ -356,6 +357,7 @@ struct vioif {
*/
unsigned int vif_tx_csum:1;
unsigned int vif_tx_tso4:1;
+ unsigned int vif_tx_tso6:1;
/*
* For debugging, it is useful to know whether the MAC address we