summaryrefslogtreecommitdiff
path: root/usr/src/uts/common
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2020-04-08 11:41:12 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2020-04-08 11:41:12 +0000
commit6b564a7014af2d4d9f000ed39a4fed77fd5245e0 (patch)
tree3805c7d1cab7ee8faf746ed3a1f0d1a448d4a8da /usr/src/uts/common
parent4fc8237742a380d4833394892fb148e1a34acb28 (diff)
parent62366fbbe8edca853fee6c14327d822239ba914f (diff)
downloadillumos-joyent-release-20200409.tar.gz
[illumos-gate merge]release-20200409
commit 62366fbbe8edca853fee6c14327d822239ba914f 12466 Enable IPv6 TSO Support for vioif commit d240edaf609c558d5a1f981b09a577823b54fae2 12465 vioif needs length for tso checksum commit 425251fd07ab465313fb50dea0f1ac795be10e05 9059 Simplify SMAP relocations with krtld commit 28e0ac9c914344194ef919b0271895d33f83d396 12433 efcode: NULL pointer errors commit 31aa620247ae407b2bee2dccd71693d1938f54d6 12452 Want support for AMD Zen 2 CPC Events Conflicts: usr/src/uts/i86pc/os/machdep.c usr/src/uts/common/io/dld/dld_proto.c usr/src/uts/common/inet/ip/ip_if.c
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r--usr/src/uts/common/inet/ip.h3
-rw-r--r--usr/src/uts/common/inet/ip/ip_if.c8
-rw-r--r--usr/src/uts/common/inet/ip/ip_output.c3
-rw-r--r--usr/src/uts/common/inet/tcp/tcp.c6
-rw-r--r--usr/src/uts/common/io/dld/dld_proto.c24
-rw-r--r--usr/src/uts/common/io/i40e/i40e_transceiver.c180
-rw-r--r--usr/src/uts/common/io/mac/mac_provider.c156
-rw-r--r--usr/src/uts/common/io/vioif/vioif.c81
-rw-r--r--usr/src/uts/common/io/vioif/vioif.h2
-rw-r--r--usr/src/uts/common/mapfiles/mac.mapfile1
-rw-r--r--usr/src/uts/common/sys/dld.h3
-rw-r--r--usr/src/uts/common/sys/mac_provider.h33
12 files changed, 303 insertions, 197 deletions
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index 89574da71f..81801b3dad 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -1596,7 +1596,8 @@ struct ill_zerocopy_capab_s {
struct ill_lso_capab_s {
uint_t ill_lso_flags; /* capabilities */
- uint_t ill_lso_max; /* maximum size of payload */
+ uint_t ill_lso_max_tcpv4; /* maximum size of payload */
+ uint_t ill_lso_max_tcpv6; /* maximum size of payload */
};
/*
diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c
index a2ddcb3547..638a5e4b21 100644
--- a/usr/src/uts/common/inet/ip/ip_if.c
+++ b/usr/src/uts/common/inet/ip/ip_if.c
@@ -2112,7 +2112,7 @@ ill_capability_lso_enable(ill_t *ill)
dld_capab_lso_t lso;
int rc;
- ASSERT(!ill->ill_isv6 && IAM_WRITER_ILL(ill));
+ ASSERT(IAM_WRITER_ILL(ill));
if (ill->ill_lso_capab == NULL) {
ill->ill_lso_capab = kmem_zalloc(sizeof (ill_lso_capab_t),
@@ -2129,7 +2129,8 @@ ill_capability_lso_enable(ill_t *ill)
if ((rc = idc->idc_capab_df(idc->idc_capab_dh, DLD_CAPAB_LSO, &lso,
DLD_ENABLE)) == 0) {
ill->ill_lso_capab->ill_lso_flags = lso.lso_flags;
- ill->ill_lso_capab->ill_lso_max = lso.lso_max;
+ ill->ill_lso_capab->ill_lso_max_tcpv4 = lso.lso_max_tcpv4;
+ ill->ill_lso_capab->ill_lso_max_tcpv6 = lso.lso_max_tcpv6;
ill->ill_capabilities |= ILL_CAPAB_LSO;
ip1dbg(("ill_capability_lso_enable: interface %s "
"has enabled LSO\n ", ill->ill_name));
@@ -2194,11 +2195,10 @@ ill_capability_dld_enable(ill_t *ill)
if (!ill->ill_isv6) {
ill_capability_direct_enable(ill);
ill_capability_poll_enable(ill);
- ill_capability_lso_enable(ill);
}
ill_capability_ipcheck_enable(ill);
-
+ ill_capability_lso_enable(ill);
ill->ill_capabilities |= ILL_CAPAB_DLD;
ill_mac_perim_exit(ill, mph);
}
diff --git a/usr/src/uts/common/inet/ip/ip_output.c b/usr/src/uts/common/inet/ip/ip_output.c
index a6ca2aabd5..a0157d3c48 100644
--- a/usr/src/uts/common/inet/ip/ip_output.c
+++ b/usr/src/uts/common/inet/ip/ip_output.c
@@ -673,7 +673,8 @@ ip_verify_lso(ill_t *ill, ip_xmit_attr_t *ixa)
/*
* Capability has changed, refresh the copy in ixa.
*/
- if (lsoc->ill_lso_max != new_lsoc->ill_lso_max) {
+ if (lsoc->ill_lso_max_tcpv4 != new_lsoc->ill_lso_max_tcpv4 ||
+ lsoc->ill_lso_max_tcpv6 != new_lsoc->ill_lso_max_tcpv6) {
*lsoc = *new_lsoc;
return (B_FALSE);
diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c
index ef4c96db1c..554fe8b78f 100644
--- a/usr/src/uts/common/inet/tcp/tcp.c
+++ b/usr/src/uts/common/inet/tcp/tcp.c
@@ -3332,9 +3332,11 @@ tcp_update_lso(tcp_t *tcp, ip_xmit_attr_t *ixa)
*/
if (ixa->ixa_flags & IXAF_LSO_CAPAB) {
ill_lso_capab_t *lsoc = &ixa->ixa_lso_capab;
+ uint_t lso_max = (ixa->ixa_flags & IXAF_IS_IPV4) ?
+ lsoc->ill_lso_max_tcpv4 : lsoc->ill_lso_max_tcpv6;
- ASSERT(lsoc->ill_lso_max > 0);
- tcp->tcp_lso_max = MIN(TCP_MAX_LSO_LENGTH, lsoc->ill_lso_max);
+ ASSERT3U(lso_max, >, 0);
+ tcp->tcp_lso_max = MIN(TCP_MAX_LSO_LENGTH, lso_max);
DTRACE_PROBE3(tcp_update_lso, boolean_t, tcp->tcp_lso,
boolean_t, B_TRUE, uint32_t, tcp->tcp_lso_max);
diff --git a/usr/src/uts/common/io/dld/dld_proto.c b/usr/src/uts/common/io/dld/dld_proto.c
index 1371fa47c0..596147f4e9 100644
--- a/usr/src/uts/common/io/dld/dld_proto.c
+++ b/usr/src/uts/common/io/dld/dld_proto.c
@@ -1537,13 +1537,23 @@ dld_capab_lso(dld_str_t *dsp, void *data, uint_t flags)
* accordingly.
*/
if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_LSO, &mac_lso)) {
- lso->lso_max = mac_lso.lso_basic_tcp_ipv4.lso_max;
+ lso->lso_max_tcpv4 = mac_lso.lso_basic_tcp_ipv4.lso_max;
+ lso->lso_max_tcpv6 = mac_lso.lso_basic_tcp_ipv6.lso_max;
lso->lso_flags = 0;
/* translate the flag for mac clients */
if ((mac_lso.lso_flags & LSO_TX_BASIC_TCP_IPV4) != 0)
lso->lso_flags |= DLD_LSO_BASIC_TCP_IPV4;
- dsp->ds_lso = B_TRUE;
- dsp->ds_lso_max = lso->lso_max;
+ if ((mac_lso.lso_flags & LSO_TX_BASIC_TCP_IPV6) != 0)
+ lso->lso_flags |= DLD_LSO_BASIC_TCP_IPV6;
+ dsp->ds_lso = lso->lso_flags != 0;
+ /*
+ * DLS uses this to try and make sure that a raw ioctl
+ * doesn't send too much data, but doesn't currently
+ * check the actual SAP that is sending this (or that
+ * it's TCP). So for now, just use the max value here.
+ */
+ dsp->ds_lso_max = MAX(lso->lso_max_tcpv4,
+ lso->lso_max_tcpv6);
} else {
dsp->ds_lso = B_FALSE;
dsp->ds_lso_max = 0;
@@ -1581,10 +1591,18 @@ dld_capab(dld_str_t *dsp, uint_t type, void *data, uint_t flags)
switch (type) {
case DLD_CAPAB_DIRECT:
+ if (dsp->ds_sap == ETHERTYPE_IPV6) {
+ err = ENOTSUP;
+ break;
+ }
err = dld_capab_direct(dsp, data, flags);
break;
case DLD_CAPAB_POLL:
+ if (dsp->ds_sap == ETHERTYPE_IPV6) {
+ err = ENOTSUP;
+ break;
+ }
err = dld_capab_poll(dsp, data, flags);
break;
diff --git a/usr/src/uts/common/io/i40e/i40e_transceiver.c b/usr/src/uts/common/io/i40e/i40e_transceiver.c
index caafa3e102..9662cb58f5 100644
--- a/usr/src/uts/common/io/i40e/i40e_transceiver.c
+++ b/usr/src/uts/common/io/i40e/i40e_transceiver.c
@@ -1663,186 +1663,6 @@ i40e_ring_rx_poll(void *arg, int poll_bytes)
}
/*
- * This is a structure I wish someone would fill out for me for dorking with the
- * checksums. When we get some more experience with this, we should go ahead and
- * consider adding this to MAC.
- */
-typedef enum mac_ether_offload_flags {
- MEOI_L2INFO_SET = 0x01,
- MEOI_VLAN_TAGGED = 0x02,
- MEOI_L3INFO_SET = 0x04,
- MEOI_L3CKSUM_SET = 0x08,
- MEOI_L4INFO_SET = 0x10,
- MEOI_L4CKSUM_SET = 0x20
-} mac_ether_offload_flags_t;
-
-typedef struct mac_ether_offload_info {
- mac_ether_offload_flags_t meoi_flags;
- uint8_t meoi_l2hlen; /* How long is the Ethernet header? */
- uint16_t meoi_l3proto; /* What's the Ethertype */
- uint8_t meoi_l3hlen; /* How long is the header? */
- uint8_t meoi_l4proto; /* What is the payload type? */
- uint8_t meoi_l4hlen; /* How long is the L4 header */
- mblk_t *meoi_l3ckmp; /* Which mblk has the l3 checksum */
- off_t meoi_l3ckoff; /* What's the offset to it */
- mblk_t *meoi_l4ckmp; /* Which mblk has the L4 checksum */
- off_t meoi_l4off; /* What is the offset to it? */
-} mac_ether_offload_info_t;
-
-/*
- * This is something that we'd like to make a general MAC function. Before we do
- * that, we should add support for TSO.
- *
- * We should really keep track of our offset and not walk everything every
- * time. I can't imagine that this will be kind to us at high packet rates;
- * however, for the moment, let's leave that.
- *
- * This walks a message block chain without pulling up to fill in the context
- * information. Note that the data we care about could be hidden across more
- * than one mblk_t.
- */
-static int
-i40e_meoi_get_uint8(mblk_t *mp, off_t off, uint8_t *out)
-{
- size_t mpsize;
- uint8_t *bp;
-
- mpsize = msgsize(mp);
- /* Check for overflow */
- if (off + sizeof (uint16_t) > mpsize)
- return (-1);
-
- mpsize = MBLKL(mp);
- while (off >= mpsize) {
- mp = mp->b_cont;
- off -= mpsize;
- mpsize = MBLKL(mp);
- }
-
- bp = mp->b_rptr + off;
- *out = *bp;
- return (0);
-
-}
-
-static int
-i40e_meoi_get_uint16(mblk_t *mp, off_t off, uint16_t *out)
-{
- size_t mpsize;
- uint8_t *bp;
-
- mpsize = msgsize(mp);
- /* Check for overflow */
- if (off + sizeof (uint16_t) > mpsize)
- return (-1);
-
- mpsize = MBLKL(mp);
- while (off >= mpsize) {
- mp = mp->b_cont;
- off -= mpsize;
- mpsize = MBLKL(mp);
- }
-
- /*
- * Data is in network order. Note the second byte of data might be in
- * the next mp.
- */
- bp = mp->b_rptr + off;
- *out = *bp << 8;
- if (off + 1 == mpsize) {
- mp = mp->b_cont;
- bp = mp->b_rptr;
- } else {
- bp++;
- }
-
- *out |= *bp;
- return (0);
-
-}
-
-static int
-mac_ether_offload_info(mblk_t *mp, mac_ether_offload_info_t *meoi)
-{
- size_t off;
- uint16_t ether;
- uint8_t ipproto, iplen, l4len, maclen;
-
- bzero(meoi, sizeof (mac_ether_offload_info_t));
-
- off = offsetof(struct ether_header, ether_type);
- if (i40e_meoi_get_uint16(mp, off, &ether) != 0)
- return (-1);
-
- if (ether == ETHERTYPE_VLAN) {
- off = offsetof(struct ether_vlan_header, ether_type);
- if (i40e_meoi_get_uint16(mp, off, &ether) != 0)
- return (-1);
- meoi->meoi_flags |= MEOI_VLAN_TAGGED;
- maclen = sizeof (struct ether_vlan_header);
- } else {
- maclen = sizeof (struct ether_header);
- }
- meoi->meoi_flags |= MEOI_L2INFO_SET;
- meoi->meoi_l2hlen = maclen;
- meoi->meoi_l3proto = ether;
-
- switch (ether) {
- case ETHERTYPE_IP:
- /*
- * For IPv4 we need to get the length of the header, as it can
- * be variable.
- */
- off = offsetof(ipha_t, ipha_version_and_hdr_length) + maclen;
- if (i40e_meoi_get_uint8(mp, off, &iplen) != 0)
- return (-1);
- iplen &= 0x0f;
- if (iplen < 5 || iplen > 0x0f)
- return (-1);
- iplen *= 4;
- off = offsetof(ipha_t, ipha_protocol) + maclen;
- if (i40e_meoi_get_uint8(mp, off, &ipproto) == -1)
- return (-1);
- break;
- case ETHERTYPE_IPV6:
- iplen = 40;
- off = offsetof(ip6_t, ip6_nxt) + maclen;
- if (i40e_meoi_get_uint8(mp, off, &ipproto) == -1)
- return (-1);
- break;
- default:
- return (0);
- }
- meoi->meoi_l3hlen = iplen;
- meoi->meoi_l4proto = ipproto;
- meoi->meoi_flags |= MEOI_L3INFO_SET;
-
- switch (ipproto) {
- case IPPROTO_TCP:
- off = offsetof(tcph_t, th_offset_and_rsrvd) + maclen + iplen;
- if (i40e_meoi_get_uint8(mp, off, &l4len) == -1)
- return (-1);
- l4len = (l4len & 0xf0) >> 4;
- if (l4len < 5 || l4len > 0xf)
- return (-1);
- l4len *= 4;
- break;
- case IPPROTO_UDP:
- l4len = sizeof (struct udphdr);
- break;
- case IPPROTO_SCTP:
- l4len = sizeof (sctp_hdr_t);
- break;
- default:
- return (0);
- }
-
- meoi->meoi_l4hlen = l4len;
- meoi->meoi_flags |= MEOI_L4INFO_SET;
- return (0);
-}
-
-/*
* Attempt to put togther the information we'll need to feed into a descriptor
* to properly program the hardware for checksum offload as well as the
* generally required flags.
diff --git a/usr/src/uts/common/io/mac/mac_provider.c b/usr/src/uts/common/io/mac/mac_provider.c
index 0f917cd8ca..7f193f68eb 100644
--- a/usr/src/uts/common/io/mac/mac_provider.c
+++ b/usr/src/uts/common/io/mac/mac_provider.c
@@ -58,6 +58,10 @@
#include <sys/pattr.h>
#include <sys/strsun.h>
#include <sys/vlan.h>
+#include <inet/ip.h>
+#include <inet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/sctp.h>
/*
* MAC Provider Interface.
@@ -1653,3 +1657,155 @@ mac_transceiver_info_set_usable(mac_transceiver_info_t *infop,
{
infop->mti_usable = usable;
}
+
+/*
+ * We should really keep track of our offset and not walk everything every
+ * time. I can't imagine that this will be kind to us at high packet rates;
+ * however, for the moment, let's leave that.
+ *
+ * This walks a message block chain without pulling up to fill in the context
+ * information. Note that the data we care about could be hidden across more
+ * than one mblk_t.
+ */
+static int
+mac_meoi_get_uint8(mblk_t *mp, off_t off, uint8_t *out)
+{
+ size_t mpsize;
+ uint8_t *bp;
+
+ mpsize = msgsize(mp);
+ /* Check for overflow */
+ if (off + sizeof (uint16_t) > mpsize)
+ return (-1);
+
+ mpsize = MBLKL(mp);
+ while (off >= mpsize) {
+ mp = mp->b_cont;
+ off -= mpsize;
+ mpsize = MBLKL(mp);
+ }
+
+ bp = mp->b_rptr + off;
+ *out = *bp;
+ return (0);
+
+}
+
+static int
+mac_meoi_get_uint16(mblk_t *mp, off_t off, uint16_t *out)
+{
+ size_t mpsize;
+ uint8_t *bp;
+
+ mpsize = msgsize(mp);
+ /* Check for overflow */
+ if (off + sizeof (uint16_t) > mpsize)
+ return (-1);
+
+ mpsize = MBLKL(mp);
+ while (off >= mpsize) {
+ mp = mp->b_cont;
+ off -= mpsize;
+ mpsize = MBLKL(mp);
+ }
+
+ /*
+ * Data is in network order. Note the second byte of data might be in
+ * the next mp.
+ */
+ bp = mp->b_rptr + off;
+ *out = *bp << 8;
+ if (off + 1 == mpsize) {
+ mp = mp->b_cont;
+ bp = mp->b_rptr;
+ } else {
+ bp++;
+ }
+
+ *out |= *bp;
+ return (0);
+
+}
+
+
+int
+mac_ether_offload_info(mblk_t *mp, mac_ether_offload_info_t *meoi)
+{
+ size_t off;
+ uint16_t ether;
+ uint8_t ipproto, iplen, l4len, maclen;
+
+ bzero(meoi, sizeof (mac_ether_offload_info_t));
+
+ meoi->meoi_len = msgsize(mp);
+ off = offsetof(struct ether_header, ether_type);
+ if (mac_meoi_get_uint16(mp, off, &ether) != 0)
+ return (-1);
+
+ if (ether == ETHERTYPE_VLAN) {
+ off = offsetof(struct ether_vlan_header, ether_type);
+ if (mac_meoi_get_uint16(mp, off, &ether) != 0)
+ return (-1);
+ meoi->meoi_flags |= MEOI_VLAN_TAGGED;
+ maclen = sizeof (struct ether_vlan_header);
+ } else {
+ maclen = sizeof (struct ether_header);
+ }
+ meoi->meoi_flags |= MEOI_L2INFO_SET;
+ meoi->meoi_l2hlen = maclen;
+ meoi->meoi_l3proto = ether;
+
+ switch (ether) {
+ case ETHERTYPE_IP:
+ /*
+ * For IPv4 we need to get the length of the header, as it can
+ * be variable.
+ */
+ off = offsetof(ipha_t, ipha_version_and_hdr_length) + maclen;
+ if (mac_meoi_get_uint8(mp, off, &iplen) != 0)
+ return (-1);
+ iplen &= 0x0f;
+ if (iplen < 5 || iplen > 0x0f)
+ return (-1);
+ iplen *= 4;
+ off = offsetof(ipha_t, ipha_protocol) + maclen;
+ if (mac_meoi_get_uint8(mp, off, &ipproto) == -1)
+ return (-1);
+ break;
+ case ETHERTYPE_IPV6:
+ iplen = 40;
+ off = offsetof(ip6_t, ip6_nxt) + maclen;
+ if (mac_meoi_get_uint8(mp, off, &ipproto) == -1)
+ return (-1);
+ break;
+ default:
+ return (0);
+ }
+ meoi->meoi_l3hlen = iplen;
+ meoi->meoi_l4proto = ipproto;
+ meoi->meoi_flags |= MEOI_L3INFO_SET;
+
+ switch (ipproto) {
+ case IPPROTO_TCP:
+ off = offsetof(tcph_t, th_offset_and_rsrvd) + maclen + iplen;
+ if (mac_meoi_get_uint8(mp, off, &l4len) == -1)
+ return (-1);
+ l4len = (l4len & 0xf0) >> 4;
+ if (l4len < 5 || l4len > 0xf)
+ return (-1);
+ l4len *= 4;
+ break;
+ case IPPROTO_UDP:
+ l4len = sizeof (struct udphdr);
+ break;
+ case IPPROTO_SCTP:
+ l4len = sizeof (sctp_hdr_t);
+ break;
+ default:
+ return (0);
+ }
+
+ meoi->meoi_l4hlen = l4len;
+ meoi->meoi_flags |= MEOI_L4INFO_SET;
+ return (0);
+}
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
diff --git a/usr/src/uts/common/mapfiles/mac.mapfile b/usr/src/uts/common/mapfiles/mac.mapfile
index d40c09b311..d5ba3ae2e5 100644
--- a/usr/src/uts/common/mapfiles/mac.mapfile
+++ b/usr/src/uts/common/mapfiles/mac.mapfile
@@ -32,6 +32,7 @@ $mapfile_version 2
SYMBOL_SCOPE {
global:
mac_alloc { FLAGS = EXTERN };
+ mac_ether_offload_info { FLAGS = EXTERN };
mac_fini_ops { FLAGS = EXTERN };
mac_free { FLAGS = EXTERN };
mac_hcksum_get { FLAGS = EXTERN };
diff --git a/usr/src/uts/common/sys/dld.h b/usr/src/uts/common/sys/dld.h
index 5be223ce93..6921960160 100644
--- a/usr/src/uts/common/sys/dld.h
+++ b/usr/src/uts/common/sys/dld.h
@@ -446,7 +446,8 @@ typedef struct dld_capab_poll_s {
typedef struct dld_capab_lso_s {
uint_t lso_flags; /* capability flags */
- uint_t lso_max; /* maximum payload */
+ uint_t lso_max_tcpv4; /* maximum TCPv4 payload */
+ uint_t lso_max_tcpv6; /* maximum TCPv6 payload */
} dld_capab_lso_t;
int dld_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
diff --git a/usr/src/uts/common/sys/mac_provider.h b/usr/src/uts/common/sys/mac_provider.h
index fc3b3892bd..04c20d6aac 100644
--- a/usr/src/uts/common/sys/mac_provider.h
+++ b/usr/src/uts/common/sys/mac_provider.h
@@ -120,10 +120,15 @@ typedef struct lso_basic_tcp_ipv4_s {
t_uscalar_t lso_max; /* maximum payload */
} lso_basic_tcp_ipv4_t;
+typedef struct lso_basic_tcp_ipv6_s {
+ t_uscalar_t lso_max; /* maximum payload */
+} lso_basic_tcp_ipv6_t;
+
/*
* Currently supported flags for LSO.
*/
-#define LSO_TX_BASIC_TCP_IPV4 0x01 /* TCP LSO capability */
+#define LSO_TX_BASIC_TCP_IPV4 0x01 /* TCPv4 LSO capability */
+#define LSO_TX_BASIC_TCP_IPV6 0x02 /* TCPv6 LSO capability */
/*
* Future LSO capabilities can be added at the end of the mac_capab_lso_t.
@@ -136,6 +141,7 @@ typedef struct lso_basic_tcp_ipv4_s {
typedef struct mac_capab_lso_s {
t_uscalar_t lso_flags;
lso_basic_tcp_ipv4_t lso_basic_tcp_ipv4;
+ lso_basic_tcp_ipv6_t lso_basic_tcp_ipv6;
/* Add future lso capabilities here */
} mac_capab_lso_t;
@@ -647,6 +653,31 @@ extern void mac_transceiver_info_set_usable(
mac_transceiver_info_t *,
boolean_t);
+/*
+ * This represents a provisional set of currently illumos-private APIs to get
+ * information about a mblk_t chain's type. This is an evolving interface.
+ */
+typedef enum mac_ether_offload_flags {
+ MEOI_L2INFO_SET = 1 << 0,
+ MEOI_VLAN_TAGGED = 1 << 1,
+ MEOI_L3INFO_SET = 1 << 2,
+ MEOI_L4INFO_SET = 1 << 3
+} mac_ether_offload_flags_t;
+
+typedef struct mac_ether_offload_info {
+ mac_ether_offload_flags_t meoi_flags; /* What's valid? */
+ size_t meoi_len; /* Total message length */
+ uint8_t meoi_l2hlen; /* How long is the Ethernet header? */
+ uint16_t meoi_l3proto; /* What's the Ethertype */
+ uint8_t meoi_l3hlen; /* How long is the header? */
+ uint8_t meoi_l4proto; /* What is the payload type? */
+ uint8_t meoi_l4hlen; /* How long is the L4 header */
+} mac_ether_offload_info_t;
+
+extern int mac_ether_offload_info(mblk_t *,
+ mac_ether_offload_info_t *);
+
+
#endif /* _KERNEL */
#ifdef __cplusplus