Enhance csum fwd engine and command lines based on current TX checksum 
framework in order to test TX Checksum offload for NVGRE packet.

It includes:
 - IPv4 and IPv6 packet
 - outer L3, inner L3 and L4 checksum offload for Tx side.

Note: The patch will need to be reworked after Olivier's patch set for 
enhancing checksum offload API is applied.

Signed-off-by: Jijiang Liu <jijiang.liu at intel.com>
---
 app/test-pmd/cmdline.c          |   19 +++++--
 app/test-pmd/csumonly.c         |  105 ++++++++++++++++++++++++++++----------
 app/test-pmd/testpmd.h          |    4 +-
 lib/librte_pmd_i40e/i40e_rxtx.c |    2 +
 4 files changed, 94 insertions(+), 36 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index ab25e24..54e0774 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -316,7 +316,7 @@ static void cmd_help_long_parsed(void *parsed_result,
                        "    Disable hardware insertion of a VLAN header in"
                        " packets sent on a port.\n\n"

-                       "tx_cksum set (ip|udp|tcp|sctp|vxlan) (hw|sw) 
(port_id)\n"
+                       "tx_cksum set (ip|udp|tcp|sctp|vxlan|nvgre) (hw|sw) 
(port_id)\n"
                        "    Select hardware or software calculation of the"
                        " checksum with when transmitting a packet using the"
                        " csum forward engine.\n"
@@ -2899,8 +2899,9 @@ cmd_tx_cksum_parsed(void *parsed_result,
                        mask = TESTPMD_TX_OFFLOAD_TCP_CKSUM;
                } else if (!strcmp(res->proto, "sctp")) {
                        mask = TESTPMD_TX_OFFLOAD_SCTP_CKSUM;
-               } else if (!strcmp(res->proto, "vxlan")) {
-                       mask = TESTPMD_TX_OFFLOAD_VXLAN_CKSUM;
+               } else if (!strcmp(res->proto, "vxlan") ||
+                               !strcmp(res->proto, "nvgre")) {
+                       mask = TESTPMD_TX_OFFLOAD_TUNNEL_CKSUM;
                }

                if (hw)
@@ -2918,8 +2919,14 @@ cmd_tx_cksum_parsed(void *parsed_result,
                (ol_flags & TESTPMD_TX_OFFLOAD_TCP_CKSUM) ? "hw" : "sw");
        printf("SCTP checksum offload is %s\n",
                (ol_flags & TESTPMD_TX_OFFLOAD_SCTP_CKSUM) ? "hw" : "sw");
-       printf("VxLAN checksum offload is %s\n",
-               (ol_flags & TESTPMD_TX_OFFLOAD_VXLAN_CKSUM) ? "hw" : "sw");
+
+       if (!strcmp(res->proto, "vxlan")) {
+               printf("VxLAN checksum offload is %s\n",
+               (ol_flags & TESTPMD_TX_OFFLOAD_TUNNEL_CKSUM) ? "hw" : "sw");
+       } else if (!strcmp(res->proto, "nvgre")) {
+               printf("NVGRE checksum offload is %s\n",
+               (ol_flags & TESTPMD_TX_OFFLOAD_TUNNEL_CKSUM) ? "hw" : "sw");
+       }

        /* display warnings if configuration is not supported by the NIC */
        rte_eth_dev_info_get(res->port_id, &dev_info);
@@ -2953,7 +2960,7 @@ cmdline_parse_token_string_t cmd_tx_cksum_mode =
                                mode, "set");
 cmdline_parse_token_string_t cmd_tx_cksum_proto =
        TOKEN_STRING_INITIALIZER(struct cmd_tx_cksum_result,
-                               proto, "ip#tcp#udp#sctp#vxlan");
+                               proto, "ip#tcp#udp#sctp#vxlan#nvgre");
 cmdline_parse_token_string_t cmd_tx_cksum_hwsw =
        TOKEN_STRING_INITIALIZER(struct cmd_tx_cksum_result,
                                hwsw, "hw#sw");
diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c
index 41711fd..8a87fbb 100644
--- a/app/test-pmd/csumonly.c
+++ b/app/test-pmd/csumonly.c
@@ -86,6 +86,12 @@
 #define _htons(x) (x)
 #endif

+/* simplified GRE header */
+struct simple_gre_hdr {
+       uint16_t flags;
+       uint16_t proto;
+};
+
 static uint16_t
 get_psd_sum(void *l3_hdr, uint16_t ethertype, uint64_t ol_flags)
 {
@@ -244,42 +250,42 @@ process_inner_cksums(void *l3_hdr, uint16_t ethertype, 
uint16_t l3_len,
        return ol_flags;
 }

-/* Calculate the checksum of outer header (only vxlan is supported,
- * meaning IP + UDP). The caller already checked that it's a vxlan
+/* Calculate the checksum of outer header (only vxlan/nvgre is supported,
+ * meaning IP + UDP/GRE). The caller already checked that it's a vxlan/NVGRE
  * packet */
 static uint64_t
 process_outer_cksums(void *outer_l3_hdr, uint16_t outer_ethertype,
-       uint16_t outer_l3_len, uint16_t testpmd_ol_flags)
+       uint16_t outer_l3_len, uint16_t testpmd_ol_flags, uint16_t l4_prot)
 {
        struct ipv4_hdr *ipv4_hdr = outer_l3_hdr;
        struct ipv6_hdr *ipv6_hdr = outer_l3_hdr;
        struct udp_hdr *udp_hdr;
        uint64_t ol_flags = 0;

-       if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_VXLAN_CKSUM)
-               ol_flags |= PKT_TX_UDP_TUNNEL_PKT;
-
        if (outer_ethertype == _htons(ETHER_TYPE_IPv4)) {
                ipv4_hdr->hdr_checksum = 0;

-               if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_VXLAN_CKSUM)
+               if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_TUNNEL_CKSUM)
                        ol_flags |= PKT_TX_OUTER_IP_CKSUM;
                else
                        ipv4_hdr->hdr_checksum = rte_ipv4_cksum(ipv4_hdr);
-       } else if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_VXLAN_CKSUM)
+       } else if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_TUNNEL_CKSUM)
                ol_flags |= PKT_TX_OUTER_IPV6;

-       udp_hdr = (struct udp_hdr *)((char *)outer_l3_hdr + outer_l3_len);
-       /* do not recalculate udp cksum if it was 0 */
-       if (udp_hdr->dgram_cksum != 0) {
-               udp_hdr->dgram_cksum = 0;
-               if (outer_ethertype == _htons(ETHER_TYPE_IPv4))
-                       udp_hdr->dgram_cksum =
-                               rte_ipv4_udptcp_cksum(ipv4_hdr, udp_hdr);
-               else
-                       udp_hdr->dgram_cksum =
-                               rte_ipv6_udptcp_cksum(ipv6_hdr, udp_hdr);
-       }
+       if (l4_prot == IPPROTO_UDP) {
+               udp_hdr = (struct udp_hdr *)((char *)outer_l3_hdr
+                               + outer_l3_len);
+               /* do not recalculate udp cksum if it was 0 */
+               if (udp_hdr->dgram_cksum != 0) {
+                       udp_hdr->dgram_cksum = 0;
+                       if (outer_ethertype == _htons(ETHER_TYPE_IPv4))
+                               udp_hdr->dgram_cksum =
+                                       rte_ipv4_udptcp_cksum(ipv4_hdr, 
udp_hdr);
+                       else
+                               udp_hdr->dgram_cksum =
+                                       rte_ipv6_udptcp_cksum(ipv6_hdr, 
udp_hdr);
+               }
+       } /* else if (l4_proto == IPPROTO_GRE), nothing to do here*/

        return ol_flags;
 }
@@ -299,12 +305,15 @@ process_outer_cksums(void *outer_l3_hdr, uint16_t 
outer_ethertype,
  *   Ether / (vlan) / IP|IP6 / UDP|TCP|SCTP .
  *   Ether / (vlan) / outer IP|IP6 / outer UDP / VxLAN / Ether / IP|IP6 /
  *           UDP|TCP|SCTP
+ *   Ether / (vlan) / outer IP|IP6 / GRE / Ether / IP|IP6 /
+ *          UDP|TCP|SCTP
  *
  * The testpmd command line for this forward engine sets the flags
  * TESTPMD_TX_OFFLOAD_* in ports[tx_port].tx_ol_flags. They control
  * wether a checksum must be calculated in software or in hardware. The
  * IP, UDP, TCP and SCTP flags always concern the inner layer.  The
- * VxLAN flag concerns the outer IP (if packet is recognized as a vxlan 
packet).
+ * TUNNEL flag concerns the outer IP (if packet is recognized as a vxlan/nvgre
+ * packet).
  */
 static void
 pkt_burst_checksum_forward(struct fwd_stream *fs)
@@ -315,6 +324,7 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
        struct ether_hdr *eth_hdr;
        void *l3_hdr = NULL, *outer_l3_hdr = NULL; /* can be IPv4 or IPv6 */
        struct udp_hdr *udp_hdr;
+       struct simple_gre_hdr *gre_hdr;
        uint16_t nb_rx;
        uint16_t nb_tx;
        uint16_t i;
@@ -386,17 +396,20 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
                                tunnel = 1;

                        /* currently, this flag is set by i40e only if the
-                        * packet is vxlan */
+                        * packet is tunneled packet */
                        } else if (m->ol_flags & (PKT_RX_TUNNEL_IPV4_HDR |
                                        PKT_RX_TUNNEL_IPV6_HDR))
                                tunnel = 1;

                        if (tunnel == 1) {
+                               if (testpmd_ol_flags &
+                                       TESTPMD_TX_OFFLOAD_TUNNEL_CKSUM)
+                                       ol_flags |= PKT_TX_UDP_TUNNEL_PKT;
+
                                outer_ethertype = ethertype;
                                outer_l2_len = l2_len;
                                outer_l3_len = l3_len;
                                outer_l3_hdr = l3_hdr;
-
                                eth_hdr = (struct ether_hdr *)((char *)udp_hdr +
                                        sizeof(struct udp_hdr) +
                                        sizeof(struct vxlan_hdr));
@@ -407,6 +420,35 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
                        }
                }

+               if ((l4_proto == IPPROTO_GRE)
+                       && ((m->ol_flags & (PKT_RX_TUNNEL_IPV4_HDR |
+                               PKT_RX_TUNNEL_IPV6_HDR)))) {
+                       gre_hdr = (struct simple_gre_hdr *)((char *)l3_hdr + 
l3_len);
+                       if (gre_hdr->proto == _htons(ETHER_TYPE_TEB)) {
+                               l4_tun_len = sizeof(struct nvgre_hdr);
+                               tunnel = 1;
+                       }
+
+                       if (tunnel == 1) {
+                               if (testpmd_ol_flags &
+                                       TESTPMD_TX_OFFLOAD_TUNNEL_CKSUM)
+                                       ol_flags |= PKT_TX_GRE_TUNNEL_PKT;
+
+                               outer_ethertype = ethertype;
+                               outer_l2_len = l2_len;
+                               outer_l3_len = l3_len;
+                               outer_l3_hdr = l3_hdr;
+
+                               /* currently, only NVGRE packet is supported */
+                               eth_hdr = (struct ether_hdr *)((char *)gre_hdr +
+                                       sizeof(struct nvgre_hdr));
+                               parse_ethernet(eth_hdr, &ethertype, &l2_len,
+                                               &l3_len, &l4_proto, &l4_len);
+                               l3_hdr = (char *)eth_hdr + l2_len;
+                       }
+
+               }
+
                /* step 2: change all source IPs (v4 or v6) so we need
                 * to recompute the chksums even if they were correct */

@@ -428,13 +470,14 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
                 * processed in hardware. */
                if (tunnel == 1) {
                        ol_flags |= process_outer_cksums(outer_l3_hdr,
-                               outer_ethertype, outer_l3_len, 
testpmd_ol_flags);
+                               outer_ethertype, outer_l3_len, testpmd_ol_flags,
+                               l4_proto);
                }

                /* step 4: fill the mbuf meta data (flags and header lengths) */

                if (tunnel == 1) {
-                       if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_VXLAN_CKSUM) {
+                       if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_TUNNEL_CKSUM) 
{
                                m->outer_l2_len = outer_l2_len;
                                m->outer_l3_len = outer_l3_len;
                                m->l2_len = l4_tun_len + l2_len;
@@ -446,9 +489,15 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
                                   we changed the ip, but it shows that
                                   we can process the inner header cksum
                                   in the nic */
-                               m->l2_len = outer_l2_len + outer_l3_len +
-                                       sizeof(struct udp_hdr) +
-                                       sizeof(struct vxlan_hdr) + l2_len;
+                               if (l4_proto == IPPROTO_UDP)
+                                       m->l2_len = outer_l2_len + outer_l3_len 
+
+                                               sizeof(struct udp_hdr) +
+                                               sizeof(struct vxlan_hdr) + 
l2_len;
+
+                               /* currently, only NVGRE is supported */
+                               else if (l4_proto == IPPROTO_GRE)
+                                       m->l2_len = outer_l2_len + outer_l3_len 
+
+                                               sizeof(struct nvgre_hdr) + 
l2_len;
                                m->l3_len = l3_len;
                                m->l4_len = l4_len;
                        }
@@ -505,7 +554,7 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
                                        "m->l4_len=%d\n",
                                        m->l2_len, m->l3_len, m->l4_len);
                        if ((tunnel == 1) &&
-                               (testpmd_ol_flags & 
TESTPMD_TX_OFFLOAD_VXLAN_CKSUM))
+                               (testpmd_ol_flags & 
TESTPMD_TX_OFFLOAD_TUNNEL_CKSUM))
                                printf("tx: m->outer_l2_len=%d 
m->outer_l3_len=%d\n",
                                        m->outer_l2_len, m->outer_l3_len);
                        if (tso_segsz != 0)
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index f8b0740..528457b 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -125,8 +125,8 @@ struct fwd_stream {
 #define TESTPMD_TX_OFFLOAD_TCP_CKSUM         0x0004
 /** Offload SCTP checksum in csum forward engine */
 #define TESTPMD_TX_OFFLOAD_SCTP_CKSUM        0x0008
-/** Offload VxLAN checksum in csum forward engine */
-#define TESTPMD_TX_OFFLOAD_VXLAN_CKSUM       0x0010
+/** Offload tunneled packet checksum in csum forward engine */
+#define TESTPMD_TX_OFFLOAD_TUNNEL_CKSUM       0x0010
 /** Insert VLAN header in forward engine */
 #define TESTPMD_TX_OFFLOAD_INSERT_VLAN       0x0020

diff --git a/lib/librte_pmd_i40e/i40e_rxtx.c b/lib/librte_pmd_i40e/i40e_rxtx.c
index 6c1e324..bf6c17c 100644
--- a/lib/librte_pmd_i40e/i40e_rxtx.c
+++ b/lib/librte_pmd_i40e/i40e_rxtx.c
@@ -1169,6 +1169,8 @@ i40e_calc_context_desc(uint64_t flags)

        if (flags | PKT_TX_UDP_TUNNEL_PKT)
                mask |= PKT_TX_UDP_TUNNEL_PKT;
+       if (flags | PKT_TX_GRE_TUNNEL_PKT)
+               mask |= PKT_TX_GRE_TUNNEL_PKT;

 #ifdef RTE_LIBRTE_IEEE1588
        mask |= PKT_TX_IEEE1588_TMST;
-- 
1.7.7.6

Reply via email to