summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2018-04-04 17:37:14 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2018-04-04 17:37:14 +0000
commit84636c8082b9aee9413dca55149c8d17a373523e (patch)
tree9c3ebe73bdec96177e962591eae4a4ee10c42c2c
parent4ac08e240a8b70d239bb2fed6f0d1a09f8da3038 (diff)
downloadillumos-joyent-84636c8082b9aee9413dca55149c8d17a373523e.tar.gz
OS-6812 implement RFD 118 interpretation of HCKSUM_INET_FULL_V4/6
-rw-r--r--usr/src/man/man9e/mac.9e26
-rw-r--r--usr/src/uts/common/inet/ip/ip6_output.c13
-rw-r--r--usr/src/uts/common/inet/ip/ip_output.c8
-rw-r--r--usr/src/uts/common/io/qede/qede_gld.c11
-rw-r--r--usr/src/uts/common/sys/dlpi.h7
-rw-r--r--usr/src/uts/i86pc/io/viona/viona.c43
6 files changed, 84 insertions, 24 deletions
diff --git a/usr/src/man/man9e/mac.9e b/usr/src/man/man9e/mac.9e
index 52984f9791..c22becc131 100644
--- a/usr/src/man/man9e/mac.9e
+++ b/usr/src/man/man9e/mac.9e
@@ -9,9 +9,9 @@
.\" http://www.illumos.org/license/CDDL.
.\"
.\"
-.\" Copyright 2016 Joyent, Inc.
+.\" Copyright 2018 Joyent, Inc.
.\"
-.Dd March 26, 2017
+.Dd March 23, 2018
.Dt MAC 9E
.Os
.Sh NAME
@@ -550,24 +550,28 @@ The following set of flags may be combined through a bitwise inclusive OR:
.Bl -tag -width Ds
.It Sy HCKSUM_INET_PARTIAL
This indicates that the hardware can calculate a partial checksum for
-both IPv4 and IPv6; however, it requires the pseudo-header checksum be
-calculated for it.
+both IPv4 and IPv6 UDP and TCP packets; however, it requires the pseudo-header
+checksum be calculated for it.
The pseudo-header checksum will be available for the mblk_t when calling
.Xr mac_hcksum_get 9F .
-Note this does not imply that the hardware is capable of calculating the
-IPv4 header checksum.
+Note this does not imply that the hardware is capable of calculating
+the partial checksum for other L4 protocols or the IPv4 header checksum.
That should be indicated with the
.Sy HCKSUM_IPHDRCKSUM flag.
.It Sy HCKSUM_INET_FULL_V4
-This indicates that the hardware will fully calculate the L4 checksum
-for outgoing IPv4 packets and does not require a pseudo-header checksum.
+This indicates that the hardware will fully calculate the L4 checksum for
+outgoing IPv4 UDP or TCP packets only, and does not require a pseudo-header
+checksum.
Note this does not imply that the hardware is capable of calculating the
-IPv4 header checksum.
+checksum for other L4 protocols or the IPv4 header checksum.
That should be indicated with the
.Sy HCKSUM_IPHDRCKSUM .
.It Sy HCKSUM_INET_FULL_V6
-This indicates that the hardware will fully calculate the L4 checksum
-for outgoing IPv6 packets and does not require a pseudo-header checksum.
+This indicates that the hardware will fully calculate the L4 checksum for
+outgoing IPv6 UDP or TCP packets only, and does not require a pseudo-header
+checksum.
+Note this does not imply that the hardware is capable of calculating the
+checksum for any other L4 protocols.
.It Sy HCKSUM_IPHDRCKSUM
This indicates that the hardware supports calculating the checksum for
the IPv4 header itself.
diff --git a/usr/src/uts/common/inet/ip/ip6_output.c b/usr/src/uts/common/inet/ip/ip6_output.c
index b023a2fe6a..dc074454e3 100644
--- a/usr/src/uts/common/inet/ip/ip6_output.c
+++ b/usr/src/uts/common/inet/ip/ip6_output.c
@@ -23,6 +23,7 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2017 OmniTI Computer Consulting, Inc. All rights reserved.
+ * Copyright 2018 Joyent, Inc.
*/
/* Copyright (c) 1990 Mentat Inc. */
@@ -866,8 +867,16 @@ ip_output_cksum_v6(iaflags_t ixaflags, mblk_t *mp, ip6_t *ip6h,
ixa->ixa_raw_cksum_offset);
cksum = htons(protocol);
} else if (protocol == IPPROTO_ICMPV6) {
- cksump = IPH_ICMPV6_CHECKSUMP(ip6h, ip_hdr_length);
- cksum = IP_ICMPV6_CSUM_COMP; /* Pseudo-header cksum */
+ /*
+ * Currently we assume no HW support for ICMP checksum calc.
+ *
+ * When HW support is advertised for ICMP, we'll want the
+ * following to be set:
+ * cksump = IPH_ICMPV6_CHECKSUMP(ip6h, ip_hdr_length);
+ * cksum = IP_ICMPV6_CSUM_COMP; Pseudo-header cksum
+ */
+
+ return (ip_output_sw_cksum_v6(mp, ip6h, ixa));
} else {
ip_hdr_cksum:
/* No IP header checksum for IPv6 */
diff --git a/usr/src/uts/common/inet/ip/ip_output.c b/usr/src/uts/common/inet/ip/ip_output.c
index 5caa043a35..02a59e69c5 100644
--- a/usr/src/uts/common/inet/ip/ip_output.c
+++ b/usr/src/uts/common/inet/ip/ip_output.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Joyent, Inc.
*/
/* Copyright (c) 1990 Mentat Inc. */
@@ -1737,6 +1738,13 @@ ip_output_cksum_v4(iaflags_t ixaflags, mblk_t *mp, ipha_t *ipha,
#endif
sctph->sh_chksum = sctp_cksum(mp, ip_hdr_length);
goto ip_hdr_cksum;
+ } else if (protocol == IPPROTO_ICMP) {
+ /*
+ * Note that we always calculate a SW checksum for ICMP. In the
+ * future, if HW support for ICMP is advertised, we can change
+ * this.
+ */
+ return (ip_output_sw_cksum_v4(mp, ipha, ixa));
} else {
ip_hdr_cksum:
/* Calculate IPv4 header checksum */
diff --git a/usr/src/uts/common/io/qede/qede_gld.c b/usr/src/uts/common/io/qede/qede_gld.c
index 50a4013555..4098409c17 100644
--- a/usr/src/uts/common/io/qede/qede_gld.c
+++ b/usr/src/uts/common/io/qede/qede_gld.c
@@ -33,6 +33,9 @@
* limitations under the License.
*/
+/*
+ * Copyright 2018 Joyent, Inc.
+ */
#include "qede.h"
@@ -2009,12 +2012,10 @@ qede_mac_get_capability(void *arg,
}
/*
- * Hardware does not support ICMPv6 checksumming. Right now the
- * GLDv3 doesn't provide us a way to specify that we don't
- * support that. As such, we cannot indicate
- * HCKSUM_INET_FULL_V6.
+ * Hardware does not support ICMPv6 checksumming, but
+ * HCKSUM_INET_FULL_V4/6 only applies for UDP and TCP.
*/
- *tx_flags = HCKSUM_INET_FULL_V4 |
+ *tx_flags = HCKSUM_INET_FULL_V4 | HCKSUM_INET_FULL_V6 |
HCKSUM_IPHDRCKSUM;
ret = B_TRUE;
break;
diff --git a/usr/src/uts/common/sys/dlpi.h b/usr/src/uts/common/sys/dlpi.h
index 34f1c17236..d76daffeb7 100644
--- a/usr/src/uts/common/sys/dlpi.h
+++ b/usr/src/uts/common/sys/dlpi.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -676,11 +677,11 @@ typedef struct {
#define HCKSUM_ENABLE 0x01 /* Set to enable hardware checksum */
/* capability */
#define HCKSUM_INET_PARTIAL 0x02 /* Partial 1's complement checksum */
- /* ability */
+ /* ability for TCP/UDP packets. */
#define HCKSUM_INET_FULL_V4 0x04 /* Full 1's complement checksum */
- /* ability for IPv4 packets. */
+ /* ability for IPv4 TCP/UDP packets. */
#define HCKSUM_INET_FULL_V6 0x08 /* Full 1's complement checksum */
- /* ability for IPv6 packets. */
+ /* ability for IPv6 TCP/UDP packets. */
#define HCKSUM_IPHDRCKSUM 0x10 /* IPv4 Header checksum offload */
/* capability */
#ifdef _KERNEL
diff --git a/usr/src/uts/i86pc/io/viona/viona.c b/usr/src/uts/i86pc/io/viona/viona.c
index 768a85f500..427a45cfad 100644
--- a/usr/src/uts/i86pc/io/viona/viona.c
+++ b/usr/src/uts/i86pc/io/viona/viona.c
@@ -56,6 +56,7 @@
#include <sys/mac_provider.h>
#include <sys/mac_client_priv.h>
#include <sys/vlan.h>
+#include <inet/ip.h>
#include <sys/vmm_drv.h>
#include <sys/viona_io.h>
@@ -1934,6 +1935,28 @@ viona_desb_release(viona_desb_t *dp)
mutex_exit(&ring->vr_lock);
}
+static int
+viona_mb_get_uint8(mblk_t *mp, off_t off, uint8_t *out)
+{
+ size_t mpsize;
+ uint8_t *bp;
+
+ mpsize = msgsize(mp);
+ if (off + sizeof (uint8_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 boolean_t
viona_tx_csum(viona_vring_t *ring, const struct virtio_net_hdr *hdr,
mblk_t *mp, uint32_t len)
@@ -1942,6 +1965,7 @@ viona_tx_csum(viona_vring_t *ring, const struct virtio_net_hdr *hdr,
const struct ether_header *eth;
uint_t eth_len = sizeof (struct ether_header);
ushort_t ftype;
+ uint8_t ipproto = IPPROTO_NONE; /* NONE is not exactly right, but ok */
eth = (const struct ether_header *)mp->b_rptr;
if (MBLKL(mp) < sizeof (*eth)) {
@@ -1959,11 +1983,22 @@ viona_tx_csum(viona_vring_t *ring, const struct virtio_net_hdr *hdr,
ftype = ntohs(veth->ether_type);
}
+ if (ftype == ETHERTYPE_IP) {
+ const size_t off = offsetof(ipha_t, ipha_protocol) + eth_len;
+
+ (void) viona_mb_get_uint8(mp, off, &ipproto);
+ } else if (ftype == ETHERTYPE_IPV6) {
+ const size_t off = offsetof(ip6_t, ip6_nxt) + eth_len;
+
+ (void) viona_mb_get_uint8(mp, off, &ipproto);
+ }
+
/*
* Partial checksum support from the NIC is ideal, since it most
* closely maps to the interface defined by virtio.
*/
- if ((link->l_cap_csum & HCKSUM_INET_PARTIAL) != 0) {
+ if ((link->l_cap_csum & HCKSUM_INET_PARTIAL) != 0 &&
+ (ipproto == IPPROTO_TCP || ipproto == IPPROTO_UDP)) {
uint_t start, stuff, end;
/*
@@ -1984,7 +2019,8 @@ viona_tx_csum(viona_vring_t *ring, const struct virtio_net_hdr *hdr,
* checksum will need to calculated inline.
*/
if (ftype == ETHERTYPE_IP) {
- if ((link->l_cap_csum & HCKSUM_INET_FULL_V4) != 0) {
+ if ((link->l_cap_csum & HCKSUM_INET_FULL_V4) != 0 &&
+ (ipproto == IPPROTO_TCP || ipproto == IPPROTO_UDP)) {
mac_hcksum_set(mp, 0, 0, 0, 0, HCK_FULLCKSUM);
return (B_TRUE);
}
@@ -1994,7 +2030,8 @@ viona_tx_csum(viona_vring_t *ring, const struct virtio_net_hdr *hdr,
VIONA_RING_STAT_INCR(ring, fail_hcksum);
return (B_FALSE);
} else if (ftype == ETHERTYPE_IPV6) {
- if ((link->l_cap_csum & HCKSUM_INET_FULL_V6) != 0) {
+ if ((link->l_cap_csum & HCKSUM_INET_FULL_V6) != 0 &&
+ (ipproto == IPPROTO_TCP || ipproto == IPPROTO_UDP)) {
mac_hcksum_set(mp, 0, 0, 0, 0, HCK_FULLCKSUM);
return (B_TRUE);
}