diff options
-rw-r--r-- | usr/src/man/man7d/i40e.7d | 4 | ||||
-rw-r--r-- | usr/src/uts/common/io/i40e/i40e_gld.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/io/i40e/i40e_transceiver.c | 3 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_gld.c | 6 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_sw.h | 7 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_tx.c | 61 | ||||
-rw-r--r-- | usr/src/uts/common/io/ixgbe/ixgbe_gld.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/io/ixgbe/ixgbe_sw.h | 1 | ||||
-rw-r--r-- | usr/src/uts/common/io/ixgbe/ixgbe_tx.c | 61 |
9 files changed, 109 insertions, 42 deletions
diff --git a/usr/src/man/man7d/i40e.7d b/usr/src/man/man7d/i40e.7d index 81ab257f6e..c5ba043149 100644 --- a/usr/src/man/man7d/i40e.7d +++ b/usr/src/man/man7d/i40e.7d @@ -11,7 +11,7 @@ .\" .\" Copyright (c) 2018 Joyent, Inc. .\" -.Dd Jan 10, 2020 +.Dd April 15, 2020 .Dt I40E 7D .Os .Sh NAME @@ -44,6 +44,8 @@ Promiscuous access via IPv4 Checksum Offload .It TCP, UDP, and SCTP checksum offload +.It +IPv4 and IPv6 TCP Segmentation offload .El .Pp At this time, the diff --git a/usr/src/uts/common/io/i40e/i40e_gld.c b/usr/src/uts/common/io/i40e/i40e_gld.c index ccf814be0b..1bf40bbce3 100644 --- a/usr/src/uts/common/io/i40e/i40e_gld.c +++ b/usr/src/uts/common/io/i40e/i40e_gld.c @@ -733,8 +733,10 @@ i40e_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) mac_capab_lso_t *cap_lso = cap_data; if (i40e->i40e_tx_lso_enable == B_TRUE) { - cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; + cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4 | + LSO_TX_BASIC_TCP_IPV6; cap_lso->lso_basic_tcp_ipv4.lso_max = I40E_LSO_MAXLEN; + cap_lso->lso_basic_tcp_ipv6.lso_max = I40E_LSO_MAXLEN; } else { return (B_FALSE); } diff --git a/usr/src/uts/common/io/i40e/i40e_transceiver.c b/usr/src/uts/common/io/i40e/i40e_transceiver.c index 9662cb58f5..e324957625 100644 --- a/usr/src/uts/common/io/i40e/i40e_transceiver.c +++ b/usr/src/uts/common/io/i40e/i40e_transceiver.c @@ -1782,7 +1782,8 @@ i40e_tx_context(i40e_t *i40e, i40e_trqpair_t *itrq, mblk_t *mp, * LSO requires that checksum offloads are enabled. If for * some reason they're not we bail out with an error. */ - if ((chkflags & HCK_IPV4_HDRCKSUM) == 0 || + if ((meo->meoi_l3proto == ETHERTYPE_IP && + (chkflags & HCK_IPV4_HDRCKSUM) == 0) || (chkflags & HCK_PARTIALCKSUM) == 0) { txs->itxs_lso_nohck.value.ui64++; return (-1); diff --git a/usr/src/uts/common/io/igb/igb_gld.c b/usr/src/uts/common/io/igb/igb_gld.c index 2bb4f99d6f..f68c4b73e9 100644 --- a/usr/src/uts/common/io/igb/igb_gld.c +++ b/usr/src/uts/common/io/igb/igb_gld.c @@ -965,8 +965,10 @@ igb_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) mac_capab_lso_t *cap_lso = cap_data; if (igb->lso_enable) { - cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; + cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4 | + LSO_TX_BASIC_TCP_IPV6; cap_lso->lso_basic_tcp_ipv4.lso_max = IGB_LSO_MAXLEN; + cap_lso->lso_basic_tcp_ipv6.lso_max = IGB_LSO_MAXLEN; break; } else { return (B_FALSE); @@ -1645,7 +1647,7 @@ igb_priv_prop_info(igb_t *igb, const char *pr_name, mac_prop_info_handle_t prh) value = DEFAULT_RX_COPY_THRESHOLD; } else if (strcmp(pr_name, "_rx_limit_per_intr") == 0) { value = DEFAULT_RX_LIMIT_PER_INTR; - } else if (strcmp(pr_name, "_intr_throttling") == 0) { + } else if (strcmp(pr_name, "_intr_throttling") == 0) { value = igb->capab->def_intr_throttle; } else { return; diff --git a/usr/src/uts/common/io/igb/igb_sw.h b/usr/src/uts/common/io/igb/igb_sw.h index f689c44b14..2e329d6fdc 100644 --- a/usr/src/uts/common/io/igb/igb_sw.h +++ b/usr/src/uts/common/io/igb/igb_sw.h @@ -227,7 +227,7 @@ extern "C" { enum ioc_reply { IOC_INVAL = -1, /* bad, NAK with EINVAL */ - IOC_DONE, /* OK, reply sent */ + IOC_DONE, /* OK, reply sent */ IOC_ACK, /* OK, just send ACK */ IOC_REPLY /* OK, just send reply */ }; @@ -355,6 +355,7 @@ typedef struct tx_context { uint32_t hcksum_flags; uint32_t ip_hdr_len; uint32_t mac_hdr_len; + uint32_t l3_proto; uint32_t l4_proto; uint32_t mss; uint32_t l4_hdr_len; @@ -558,7 +559,7 @@ typedef struct igb_rx_group { } igb_rx_group_t; typedef struct igb { - int instance; + int instance; mac_handle_t mac_hdl; dev_info_t *dip; struct e1000_hw hw; @@ -606,7 +607,7 @@ typedef struct igb { boolean_t tx_ring_init; boolean_t tx_head_wb_enable; /* Tx head wrtie-back */ boolean_t tx_hcksum_enable; /* Tx h/w cksum offload */ - boolean_t lso_enable; /* Large Segment Offload */ + boolean_t lso_enable; /* Large Segment Offload */ uint32_t tx_copy_thresh; /* Tx copy threshold */ uint32_t tx_recycle_thresh; /* Tx recycle threshold */ uint32_t tx_overload_thresh; /* Tx overload threshold */ diff --git a/usr/src/uts/common/io/igb/igb_tx.c b/usr/src/uts/common/io/igb/igb_tx.c index 0496bf59fe..5245312adc 100644 --- a/usr/src/uts/common/io/igb/igb_tx.c +++ b/usr/src/uts/common/io/igb/igb_tx.c @@ -598,6 +598,7 @@ igb_get_tx_context(mblk_t *mp, tx_context_t *ctx) uint32_t start; uint32_t flags; uint32_t lso_flag; + uint32_t lso_cksum; uint32_t mss; uint32_t len; uint32_t size; @@ -622,19 +623,6 @@ igb_get_tx_context(mblk_t *mp, tx_context_t *ctx) ctx->mss = mss; ctx->lso_flag = (lso_flag == HW_LSO); - /* - * LSO relies on tx h/w checksum, so here the packet will be - * dropped if the h/w checksum flags are not set. - */ - if (ctx->lso_flag) { - if (!((ctx->hcksum_flags & HCK_PARTIALCKSUM) && - (ctx->hcksum_flags & HCK_IPV4_HDRCKSUM))) { - igb_log(NULL, IGB_LOG_INFO, "igb_tx: h/w " - "checksum flags are not set for LSO"); - return (TX_CXT_E_LSO_CSUM); - } - } - etype = 0; mac_hdr_len = 0; l4_proto = 0; @@ -679,6 +667,8 @@ igb_get_tx_context(mblk_t *mp, tx_context_t *ctx) * Here we assume the IP(V6) header is fully included in one * mblk fragment. */ + lso_cksum = HCK_PARTIALCKSUM; + ctx->l3_proto = etype; switch (etype) { case ETHERTYPE_IP: offset = mac_hdr_len; @@ -703,11 +693,27 @@ igb_get_tx_context(mblk_t *mp, tx_context_t *ctx) * with zero. Currently the tcp/ip stack has done * these. */ + lso_cksum |= HCK_IPV4_HDRCKSUM; } l4_proto = *(uint8_t *)(pos + offsetof(ipha_t, ipha_protocol)); break; case ETHERTYPE_IPV6: + /* + * We need to zero out the length in the header. + */ + if (ctx->lso_flag) { + offset = offsetof(ip6_t, ip6_plen) + mac_hdr_len; + while (size <= offset) { + mp = mp->b_cont; + ASSERT(mp != NULL); + len = MBLKL(mp); + size += len; + } + pos = mp->b_rptr + offset + len - size; + *((uint16_t *)(uintptr_t)(pos)) = 0; + } + offset = offsetof(ip6_t, ip6_nxt) + mac_hdr_len; while (size <= offset) { mp = mp->b_cont; @@ -727,6 +733,18 @@ igb_get_tx_context(mblk_t *mp, tx_context_t *ctx) } if (ctx->lso_flag) { + /* + * LSO relies on tx h/w checksum, so here the packet will be + * dropped if the h/w checksum flags are not set. + */ + if ((ctx->hcksum_flags & lso_cksum) != lso_cksum) { + igb_log(NULL, IGB_LOG_INFO, "igb_tx: h/w " + "checksum flags are not set for LSO, found " + "0x%x, needed bits 0x%x", ctx->hcksum_flags, + lso_cksum); + return (TX_CXT_E_LSO_CSUM); + } + offset = mac_hdr_len + start; while (size <= offset) { mp = mp->b_cont; @@ -771,6 +789,7 @@ igb_check_tx_context(igb_tx_ring_t *tx_ring, tx_context_t *ctx) * need to be checked are: * hcksum_flags * l4_proto + * l3_proto * mss (only check for LSO) * l4_hdr_len (only check for LSO) * ip_hdr_len @@ -783,6 +802,7 @@ igb_check_tx_context(igb_tx_ring_t *tx_ring, tx_context_t *ctx) if (ctx->hcksum_flags != 0) { if ((ctx->hcksum_flags != last->hcksum_flags) || (ctx->l4_proto != last->l4_proto) || + (ctx->l3_proto != last->l3_proto) || (ctx->lso_flag && ((ctx->mss != last->mss) || (ctx->l4_hdr_len != last->l4_hdr_len))) || (ctx->ip_hdr_len != last->ip_hdr_len) || @@ -814,10 +834,19 @@ igb_fill_tx_context(struct e1000_adv_tx_context_desc *ctx_tbd, ctx_tbd->type_tucmd_mlhl = E1000_ADVTXD_DCMD_DEXT | E1000_ADVTXD_DTYP_CTXT; - if (ctx->hcksum_flags & HCK_IPV4_HDRCKSUM) - ctx_tbd->type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV4; + /* + * When we have a TX context set up, we enforce that the ethertype is + * either IPv4 or IPv6 in igb_get_tx_context(). + */ + if (ctx->lso_flag || ctx->hcksum_flags & HCK_IPV4_HDRCKSUM) { + if (ctx->l3_proto == ETHERTYPE_IP) { + ctx_tbd->type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV4; + } else { + ctx_tbd->type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV6; + } + } - if (ctx->hcksum_flags & HCK_PARTIALCKSUM) { + if (ctx->lso_flag || ctx->hcksum_flags & HCK_PARTIALCKSUM) { switch (ctx->l4_proto) { case IPPROTO_TCP: ctx_tbd->type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_TCP; diff --git a/usr/src/uts/common/io/ixgbe/ixgbe_gld.c b/usr/src/uts/common/io/ixgbe/ixgbe_gld.c index ea888220fa..8508e32b82 100644 --- a/usr/src/uts/common/io/ixgbe/ixgbe_gld.c +++ b/usr/src/uts/common/io/ixgbe/ixgbe_gld.c @@ -304,8 +304,10 @@ ixgbe_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) mac_capab_lso_t *cap_lso = cap_data; if (ixgbe->lso_enable) { - cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; + cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4 | + LSO_TX_BASIC_TCP_IPV6; cap_lso->lso_basic_tcp_ipv4.lso_max = IXGBE_LSO_MAXLEN; + cap_lso->lso_basic_tcp_ipv6.lso_max = IXGBE_LSO_MAXLEN; break; } else { return (B_FALSE); diff --git a/usr/src/uts/common/io/ixgbe/ixgbe_sw.h b/usr/src/uts/common/io/ixgbe/ixgbe_sw.h index cfd987787a..8bf93afe9c 100644 --- a/usr/src/uts/common/io/ixgbe/ixgbe_sw.h +++ b/usr/src/uts/common/io/ixgbe/ixgbe_sw.h @@ -408,6 +408,7 @@ typedef struct ixgbe_tx_context { uint32_t hcksum_flags; uint32_t ip_hdr_len; uint32_t mac_hdr_len; + uint32_t l3_proto; uint32_t l4_proto; uint32_t mss; uint32_t l4_hdr_len; diff --git a/usr/src/uts/common/io/ixgbe/ixgbe_tx.c b/usr/src/uts/common/io/ixgbe/ixgbe_tx.c index 9191aad058..b6926fc3b7 100644 --- a/usr/src/uts/common/io/ixgbe/ixgbe_tx.c +++ b/usr/src/uts/common/io/ixgbe/ixgbe_tx.c @@ -697,6 +697,7 @@ ixgbe_get_context(mblk_t *mp, ixgbe_tx_context_t *ctx) uint32_t start; uint32_t hckflags; uint32_t lsoflags; + uint32_t lsocksum; uint32_t mss; uint32_t len; uint32_t size; @@ -722,19 +723,6 @@ ixgbe_get_context(mblk_t *mp, ixgbe_tx_context_t *ctx) ctx->mss = mss; ctx->lso_flag = (lsoflags == HW_LSO); - /* - * LSO relies on tx h/w checksum, so here will drop the package - * if h/w checksum flag is not declared. - */ - if (ctx->lso_flag) { - if (!((ctx->hcksum_flags & HCK_PARTIALCKSUM) && - (ctx->hcksum_flags & HCK_IPV4_HDRCKSUM))) { - IXGBE_DEBUGLOG_0(NULL, "ixgbe_tx: h/w " - "checksum flags are not specified when doing LSO"); - return (-1); - } - } - etype = 0; mac_hdr_len = 0; l4_proto = 0; @@ -779,6 +767,8 @@ ixgbe_get_context(mblk_t *mp, ixgbe_tx_context_t *ctx) * Here we don't assume the IP(V6) header is fully included in * one mblk fragment. */ + lsocksum = HCK_PARTIALCKSUM; + ctx->l3_proto = etype; switch (etype) { case ETHERTYPE_IP: if (ctx->lso_flag) { @@ -810,6 +800,7 @@ ixgbe_get_context(mblk_t *mp, ixgbe_tx_context_t *ctx) * (ip_source_addr, ip_destination_addr, l4_proto) * Currently the tcp/ip stack has done it. */ + lsocksum |= HCK_IPV4_HDRCKSUM; } offset = offsetof(ipha_t, ipha_protocol) + mac_hdr_len; @@ -824,6 +815,21 @@ ixgbe_get_context(mblk_t *mp, ixgbe_tx_context_t *ctx) l4_proto = *(uint8_t *)pos; break; case ETHERTYPE_IPV6: + /* + * We need to zero out the length in the header. + */ + if (ctx->lso_flag) { + offset = offsetof(ip6_t, ip6_plen) + mac_hdr_len; + while (size <= offset) { + mp = mp->b_cont; + ASSERT(mp != NULL); + len = MBLKL(mp); + size += len; + } + pos = mp->b_rptr + offset + len - size; + *((uint16_t *)(uintptr_t)(pos)) = 0; + } + offset = offsetof(ip6_t, ip6_nxt) + mac_hdr_len; while (size <= offset) { mp = mp->b_cont; @@ -842,6 +848,18 @@ ixgbe_get_context(mblk_t *mp, ixgbe_tx_context_t *ctx) } if (ctx->lso_flag) { + /* + * LSO relies on tx h/w checksum, so here will drop the packet + * if h/w checksum flag is not declared. + */ + if ((ctx->hcksum_flags & lsocksum) != lsocksum) { + IXGBE_DEBUGLOG_2(NULL, "ixgbe_tx: h/w checksum flags " + "are not set for LSO, found 0x%x, needed bits 0x%x", + ctx->hcksum_flags, lsocksum); + return (-1); + } + + offset = mac_hdr_len + start; while (size <= offset) { mp = mp->b_cont; @@ -898,6 +916,7 @@ ixgbe_check_context(ixgbe_tx_ring_t *tx_ring, ixgbe_tx_context_t *ctx) if ((ctx->hcksum_flags != last->hcksum_flags) || (ctx->l4_proto != last->l4_proto) || + (ctx->l3_proto != last->l3_proto) || (ctx->mac_hdr_len != last->mac_hdr_len) || (ctx->ip_hdr_len != last->ip_hdr_len) || (ctx->lso_flag != last->lso_flag) || @@ -928,11 +947,19 @@ ixgbe_fill_context(struct ixgbe_adv_tx_context_desc *ctx_tbd, ctx_tbd->type_tucmd_mlhl = IXGBE_ADVTXD_DCMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT; + /* + * When we have a TX context set up, we enforce that the ethertype is + * either IPv4 or IPv6 in ixgbe_get_tx_context(). + */ + if (ctx->lso_flag || ctx->hcksum_flags & HCK_IPV4_HDRCKSUM) { + if (ctx->l3_proto == ETHERTYPE_IP) { + ctx_tbd->type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + } else { + ctx_tbd->type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV6; + } + } - if (ctx->hcksum_flags & HCK_IPV4_HDRCKSUM) - ctx_tbd->type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; - - if (ctx->hcksum_flags & HCK_PARTIALCKSUM) { + if (ctx->lso_flag || ctx->hcksum_flags & HCK_PARTIALCKSUM) { switch (ctx->l4_proto) { case IPPROTO_TCP: ctx_tbd->type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; |