diff options
Diffstat (limited to 'usr/src/uts/common/io/vioif')
-rw-r--r-- | usr/src/uts/common/io/vioif/vioif.c | 81 | ||||
-rw-r--r-- | usr/src/uts/common/io/vioif/vioif.h | 2 |
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 |