LCOV - code coverage report
Current view: top level - app/test-pmd - csumonly.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 352 0.0 %
Date: 2025-04-03 19:37:06 Functions: 0 10 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2010-2014 Intel Corporation.
       3                 :            :  * Copyright 2014 6WIND S.A.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include <stdarg.h>
       7                 :            : #include <stdio.h>
       8                 :            : #include <errno.h>
       9                 :            : #include <stdint.h>
      10                 :            : #include <unistd.h>
      11                 :            : #include <inttypes.h>
      12                 :            : 
      13                 :            : #include <sys/queue.h>
      14                 :            : #include <sys/stat.h>
      15                 :            : 
      16                 :            : #include <rte_common.h>
      17                 :            : #include <rte_byteorder.h>
      18                 :            : #include <rte_log.h>
      19                 :            : #include <rte_debug.h>
      20                 :            : #include <rte_cycles.h>
      21                 :            : #include <rte_memory.h>
      22                 :            : #include <rte_memcpy.h>
      23                 :            : #include <rte_launch.h>
      24                 :            : #include <rte_eal.h>
      25                 :            : #include <rte_per_lcore.h>
      26                 :            : #include <rte_lcore.h>
      27                 :            : #include <rte_branch_prediction.h>
      28                 :            : #include <rte_mempool.h>
      29                 :            : #include <rte_mbuf.h>
      30                 :            : #include <rte_interrupts.h>
      31                 :            : #include <rte_ether.h>
      32                 :            : #include <rte_ethdev.h>
      33                 :            : #include <rte_ip.h>
      34                 :            : #include <rte_tcp.h>
      35                 :            : #include <rte_udp.h>
      36                 :            : #include <rte_vxlan.h>
      37                 :            : #include <rte_sctp.h>
      38                 :            : #include <rte_gtp.h>
      39                 :            : #include <rte_prefetch.h>
      40                 :            : #include <rte_string_fns.h>
      41                 :            : #include <rte_flow.h>
      42                 :            : #ifdef RTE_LIB_GRO
      43                 :            : #include <rte_gro.h>
      44                 :            : #endif
      45                 :            : #ifdef RTE_LIB_GSO
      46                 :            : #include <rte_gso.h>
      47                 :            : #endif
      48                 :            : #include <rte_geneve.h>
      49                 :            : #include <rte_net.h>
      50                 :            : 
      51                 :            : #include "testpmd.h"
      52                 :            : 
      53                 :            : #define IP_DEFTTL  64   /* from RFC 1340. */
      54                 :            : 
      55                 :            : #define GRE_CHECKSUM_PRESENT    0x8000
      56                 :            : #define GRE_KEY_PRESENT         0x2000
      57                 :            : #define GRE_SEQUENCE_PRESENT    0x1000
      58                 :            : #define GRE_EXT_LEN             4
      59                 :            : #define GRE_SUPPORTED_FIELDS    (GRE_CHECKSUM_PRESENT | GRE_KEY_PRESENT |\
      60                 :            :                                  GRE_SEQUENCE_PRESENT)
      61                 :            : 
      62                 :            : #define MAX_VLAN_HEADERS 8
      63                 :            : 
      64                 :            : /* We cannot use rte_cpu_to_be_16() on a constant in a switch/case */
      65                 :            : #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
      66                 :            : #define _htons(x) ((uint16_t)((((x) & 0x00ffU) << 8) | (((x) & 0xff00U) >> 8)))
      67                 :            : #else
      68                 :            : #define _htons(x) (x)
      69                 :            : #endif
      70                 :            : 
      71                 :            : uint16_t vxlan_gpe_udp_port = RTE_VXLAN_GPE_DEFAULT_PORT;
      72                 :            : uint16_t geneve_udp_port = RTE_GENEVE_DEFAULT_PORT;
      73                 :            : 
      74                 :            : /* structure that caches offload info for the current packet */
      75                 :            : struct testpmd_offload_info {
      76                 :            :         uint16_t ethertype;
      77                 :            : #ifdef RTE_LIB_GSO
      78                 :            :         uint8_t gso_enable;
      79                 :            : #endif
      80                 :            :         uint16_t l2_len;
      81                 :            :         uint16_t l3_len;
      82                 :            :         uint16_t l4_len;
      83                 :            :         uint8_t l4_proto;
      84                 :            :         uint8_t is_tunnel;
      85                 :            :         uint16_t outer_ethertype;
      86                 :            :         uint16_t outer_l2_len;
      87                 :            :         uint16_t outer_l3_len;
      88                 :            :         uint8_t outer_l4_proto;
      89                 :            :         uint16_t tso_segsz;
      90                 :            :         uint16_t tunnel_tso_segsz;
      91                 :            :         uint32_t pkt_len;
      92                 :            : };
      93                 :            : 
      94                 :            : /* simplified GRE header */
      95                 :            : struct simple_gre_hdr {
      96                 :            :         uint16_t flags;
      97                 :            :         uint16_t proto;
      98                 :            : };
      99                 :            : 
     100                 :            : static uint16_t
     101                 :          0 : get_udptcp_checksum(struct rte_mbuf *m, void *l3_hdr, uint16_t l4_off,
     102                 :            :                     uint16_t ethertype)
     103                 :            : {
     104                 :          0 :         if (ethertype == _htons(RTE_ETHER_TYPE_IPV4))
     105                 :          0 :                 return rte_ipv4_udptcp_cksum_mbuf(m, l3_hdr, l4_off);
     106                 :            :         else /* assume ethertype == RTE_ETHER_TYPE_IPV6 */
     107                 :          0 :                 return rte_ipv6_udptcp_cksum_mbuf(m, l3_hdr, l4_off);
     108                 :            : }
     109                 :            : 
     110                 :            : /* Fill in outer layers length */
     111                 :            : static void
     112                 :            : update_tunnel_outer(struct testpmd_offload_info *info)
     113                 :            : {
     114                 :            :         info->is_tunnel = 1;
     115                 :          0 :         info->outer_ethertype = info->ethertype;
     116                 :          0 :         info->outer_l2_len = info->l2_len;
     117                 :          0 :         info->outer_l3_len = info->l3_len;
     118                 :          0 :         info->outer_l4_proto = info->l4_proto;
     119                 :          0 :         info->l4_proto = 0;
     120                 :            : }
     121                 :            : 
     122                 :            : /* if possible, calculate the checksum of a packet in hw or sw,
     123                 :            :  * depending on the testpmd command line configuration */
     124                 :            : static uint64_t
     125                 :          0 : process_inner_cksums(void *l3_hdr, const struct testpmd_offload_info *info,
     126                 :            :         uint64_t tx_offloads, struct rte_mbuf *m)
     127                 :            : {
     128                 :            :         struct rte_ipv4_hdr *ipv4_hdr = l3_hdr;
     129                 :            :         struct rte_udp_hdr *udp_hdr;
     130                 :            :         struct rte_tcp_hdr *tcp_hdr;
     131                 :            :         struct rte_sctp_hdr *sctp_hdr;
     132                 :            :         uint64_t ol_flags = 0;
     133                 :            :         uint32_t max_pkt_len, tso_segsz = 0;
     134                 :            :         uint16_t l4_off;
     135                 :            :         uint64_t all_tunnel_tso = RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
     136                 :            :                                 RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
     137                 :            :                                 RTE_ETH_TX_OFFLOAD_IPIP_TNL_TSO |
     138                 :            :                                 RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO |
     139                 :            :                                 RTE_ETH_TX_OFFLOAD_IP_TNL_TSO |
     140                 :            :                                 RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO;
     141                 :            : 
     142                 :            :         /* ensure packet is large enough to require tso */
     143                 :          0 :         if (!info->is_tunnel) {
     144                 :          0 :                 max_pkt_len = info->l2_len + info->l3_len + info->l4_len +
     145                 :          0 :                         info->tso_segsz;
     146                 :          0 :                 if (info->tso_segsz != 0 && info->pkt_len > max_pkt_len)
     147                 :          0 :                         tso_segsz = info->tso_segsz;
     148                 :            :         } else {
     149                 :          0 :                 max_pkt_len = info->outer_l2_len + info->outer_l3_len +
     150                 :          0 :                         info->l2_len + info->l3_len + info->l4_len +
     151                 :          0 :                         info->tunnel_tso_segsz;
     152                 :          0 :                 if (info->tunnel_tso_segsz != 0 && info->pkt_len > max_pkt_len)
     153                 :          0 :                         tso_segsz = info->tunnel_tso_segsz;
     154                 :            :         }
     155                 :            : 
     156                 :          0 :         if (info->ethertype == _htons(RTE_ETHER_TYPE_IPV4)) {
     157                 :            :                 ipv4_hdr = l3_hdr;
     158                 :            : 
     159                 :            :                 ol_flags |= RTE_MBUF_F_TX_IPV4;
     160                 :          0 :                 if (info->l4_proto == IPPROTO_TCP && tso_segsz) {
     161                 :            :                         ol_flags |= RTE_MBUF_F_TX_IP_CKSUM;
     162                 :            :                 } else {
     163                 :          0 :                         if (tx_offloads & RTE_ETH_TX_OFFLOAD_IPV4_CKSUM) {
     164                 :            :                                 ol_flags |= RTE_MBUF_F_TX_IP_CKSUM;
     165                 :            :                         } else {
     166                 :          0 :                                 ipv4_hdr->hdr_checksum = 0;
     167                 :          0 :                                 ipv4_hdr->hdr_checksum =
     168                 :            :                                         rte_ipv4_cksum(ipv4_hdr);
     169                 :            :                         }
     170                 :            :                 }
     171                 :          0 :         } else if (info->ethertype == _htons(RTE_ETHER_TYPE_IPV6))
     172                 :            :                 ol_flags |= RTE_MBUF_F_TX_IPV6;
     173                 :            :         else
     174                 :            :                 return 0; /* packet type not supported, nothing to do */
     175                 :            : 
     176                 :          0 :         if (info->l4_proto == IPPROTO_UDP) {
     177                 :          0 :                 udp_hdr = (struct rte_udp_hdr *)((char *)l3_hdr + info->l3_len);
     178                 :            :                 /* do not recalculate udp cksum if it was 0 */
     179                 :          0 :                 if (udp_hdr->dgram_cksum != 0) {
     180                 :          0 :                         if (tso_segsz && (tx_offloads & RTE_ETH_TX_OFFLOAD_UDP_TSO))
     181                 :          0 :                                 ol_flags |= RTE_MBUF_F_TX_UDP_SEG;
     182                 :          0 :                         else if (tx_offloads & RTE_ETH_TX_OFFLOAD_UDP_CKSUM) {
     183                 :          0 :                                 ol_flags |= RTE_MBUF_F_TX_UDP_CKSUM;
     184                 :            :                         } else {
     185                 :          0 :                                 if (info->is_tunnel)
     186                 :          0 :                                         l4_off = info->outer_l2_len +
     187                 :          0 :                                                  info->outer_l3_len +
     188                 :          0 :                                                  info->l2_len + info->l3_len;
     189                 :            :                                 else
     190                 :          0 :                                         l4_off = info->l2_len +      info->l3_len;
     191                 :          0 :                                 udp_hdr->dgram_cksum = 0;
     192                 :          0 :                                 udp_hdr->dgram_cksum =
     193                 :          0 :                                         get_udptcp_checksum(m, l3_hdr, l4_off,
     194                 :            :                                                 info->ethertype);
     195                 :            :                         }
     196                 :            :                 }
     197                 :            : #ifdef RTE_LIB_GSO
     198                 :          0 :                 if (info->gso_enable)
     199                 :          0 :                         ol_flags |= RTE_MBUF_F_TX_UDP_SEG;
     200                 :            : #endif
     201                 :          0 :         } else if (info->l4_proto == IPPROTO_TCP) {
     202                 :          0 :                 tcp_hdr = (struct rte_tcp_hdr *)((char *)l3_hdr + info->l3_len);
     203                 :          0 :                 if (tso_segsz &&
     204                 :          0 :                     (tx_offloads & (RTE_ETH_TX_OFFLOAD_TCP_TSO | all_tunnel_tso)))
     205                 :          0 :                         ol_flags |= RTE_MBUF_F_TX_TCP_SEG;
     206                 :          0 :                 else if (tx_offloads & RTE_ETH_TX_OFFLOAD_TCP_CKSUM) {
     207                 :          0 :                         ol_flags |= RTE_MBUF_F_TX_TCP_CKSUM;
     208                 :            :                 } else {
     209                 :          0 :                         if (info->is_tunnel)
     210                 :          0 :                                 l4_off = info->outer_l2_len + info->outer_l3_len +
     211                 :          0 :                                          info->l2_len + info->l3_len;
     212                 :            :                         else
     213                 :          0 :                                 l4_off = info->l2_len + info->l3_len;
     214                 :          0 :                         tcp_hdr->cksum = 0;
     215                 :          0 :                         tcp_hdr->cksum =
     216                 :          0 :                                 get_udptcp_checksum(m, l3_hdr, l4_off,
     217                 :            :                                         info->ethertype);
     218                 :            :                 }
     219                 :            : #ifdef RTE_LIB_GSO
     220                 :          0 :                 if (info->gso_enable)
     221                 :          0 :                         ol_flags |= RTE_MBUF_F_TX_TCP_SEG;
     222                 :            : #endif
     223                 :          0 :         } else if (info->l4_proto == IPPROTO_SCTP) {
     224                 :          0 :                 sctp_hdr = (struct rte_sctp_hdr *)
     225                 :          0 :                         ((char *)l3_hdr + info->l3_len);
     226                 :            :                 /* sctp payload must be a multiple of 4 to be
     227                 :            :                  * offloaded */
     228                 :          0 :                 if ((tx_offloads & RTE_ETH_TX_OFFLOAD_SCTP_CKSUM) &&
     229                 :          0 :                         ((ipv4_hdr->total_length & 0x3) == 0)) {
     230                 :          0 :                         ol_flags |= RTE_MBUF_F_TX_SCTP_CKSUM;
     231                 :            :                 } else {
     232                 :          0 :                         sctp_hdr->cksum = 0;
     233                 :            :                         /* XXX implement CRC32c, example available in
     234                 :            :                          * RFC3309 */
     235                 :            :                 }
     236                 :            :         }
     237                 :            : 
     238                 :            :         return ol_flags;
     239                 :            : }
     240                 :            : 
     241                 :            : /* Calculate the checksum of outer header */
     242                 :            : static uint64_t
     243                 :          0 : process_outer_cksums(void *outer_l3_hdr, struct testpmd_offload_info *info,
     244                 :            :         uint64_t tx_offloads, int tso_enabled, struct rte_mbuf *m)
     245                 :            : {
     246                 :            :         struct rte_udp_hdr *udp_hdr;
     247                 :            :         uint64_t ol_flags = 0;
     248                 :            : 
     249                 :          0 :         if (info->outer_ethertype == _htons(RTE_ETHER_TYPE_IPV4)) {
     250                 :            :                 ol_flags |= RTE_MBUF_F_TX_OUTER_IPV4;
     251                 :            : 
     252                 :          0 :                 if (tx_offloads & RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM) {
     253                 :            :                         ol_flags |= RTE_MBUF_F_TX_OUTER_IP_CKSUM;
     254                 :            :                 } else {
     255                 :            :                         struct rte_ipv4_hdr *ipv4_hdr = outer_l3_hdr;
     256                 :            : 
     257                 :          0 :                         ipv4_hdr->hdr_checksum = 0;
     258                 :          0 :                         ipv4_hdr->hdr_checksum = rte_ipv4_cksum(ipv4_hdr);
     259                 :            :                 }
     260                 :            :         } else {
     261                 :            :                 ol_flags |= RTE_MBUF_F_TX_OUTER_IPV6;
     262                 :            :         }
     263                 :            : 
     264                 :          0 :         if (info->outer_l4_proto != IPPROTO_UDP)
     265                 :            :                 return ol_flags;
     266                 :            : 
     267                 :          0 :         udp_hdr = (struct rte_udp_hdr *)
     268                 :          0 :                 ((char *)outer_l3_hdr + info->outer_l3_len);
     269                 :            : 
     270                 :          0 :         if (tso_enabled && info->l4_proto == IPPROTO_TCP)
     271                 :          0 :                 ol_flags |= RTE_MBUF_F_TX_TCP_SEG;
     272                 :          0 :         else if (tso_enabled && info->l4_proto == IPPROTO_UDP)
     273                 :          0 :                 ol_flags |= RTE_MBUF_F_TX_UDP_SEG;
     274                 :            : 
     275                 :            :         /* Skip SW outer UDP checksum generation if HW supports it */
     276                 :          0 :         if (tx_offloads & RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM) {
     277                 :          0 :                 ol_flags |= RTE_MBUF_F_TX_OUTER_UDP_CKSUM;
     278                 :          0 :                 return ol_flags;
     279                 :            :         }
     280                 :            : 
     281                 :            :         /* Outer UDP checksum is done in software.
     282                 :            :          *
     283                 :            :          * If a packet will be TSOed into small packets by NIC, we cannot
     284                 :            :          * set/calculate a non-zero checksum, because it will be a wrong
     285                 :            :          * value after the packet be split into several small packets.
     286                 :            :          */
     287                 :          0 :         if (!tso_enabled && udp_hdr->dgram_cksum != 0) {
     288                 :          0 :                 udp_hdr->dgram_cksum = 0;
     289                 :          0 :                 udp_hdr->dgram_cksum = get_udptcp_checksum(m, outer_l3_hdr,
     290                 :          0 :                                         info->outer_l2_len + info->outer_l3_len,
     291                 :            :                                         info->outer_ethertype);
     292                 :            :         }
     293                 :            : 
     294                 :            :         return ol_flags;
     295                 :            : }
     296                 :            : 
     297                 :            : /*
     298                 :            :  * Helper function.
     299                 :            :  * Performs actual copying.
     300                 :            :  * Returns number of segments in the destination mbuf on success,
     301                 :            :  * or negative error code on failure.
     302                 :            :  */
     303                 :            : static int
     304                 :          0 : mbuf_copy_split(const struct rte_mbuf *ms, struct rte_mbuf *md[],
     305                 :            :         uint16_t seglen[], uint8_t nb_seg)
     306                 :            : {
     307                 :            :         uint32_t dlen, slen, tlen;
     308                 :            :         uint32_t i, len;
     309                 :            :         const struct rte_mbuf *m;
     310                 :            :         const uint8_t *src;
     311                 :            :         uint8_t *dst;
     312                 :            : 
     313                 :            :         dlen = 0;
     314                 :            :         slen = 0;
     315                 :            :         tlen = 0;
     316                 :            : 
     317                 :            :         dst = NULL;
     318                 :            :         src = NULL;
     319                 :            : 
     320                 :            :         m = ms;
     321                 :            :         i = 0;
     322                 :          0 :         while (ms != NULL && i != nb_seg) {
     323                 :            : 
     324                 :          0 :                 if (slen == 0) {
     325                 :          0 :                         slen = rte_pktmbuf_data_len(ms);
     326                 :          0 :                         src = rte_pktmbuf_mtod(ms, const uint8_t *);
     327                 :            :                 }
     328                 :            : 
     329                 :          0 :                 if (dlen == 0) {
     330                 :          0 :                         dlen = RTE_MIN(seglen[i], slen);
     331                 :          0 :                         md[i]->data_len = dlen;
     332                 :          0 :                         md[i]->next = (i + 1 == nb_seg) ? NULL : md[i + 1];
     333                 :          0 :                         dst = rte_pktmbuf_mtod(md[i], uint8_t *);
     334                 :            :                 }
     335                 :            : 
     336                 :          0 :                 len = RTE_MIN(slen, dlen);
     337                 :          0 :                 memcpy(dst, src, len);
     338                 :          0 :                 tlen += len;
     339                 :          0 :                 slen -= len;
     340                 :          0 :                 dlen -= len;
     341                 :          0 :                 src += len;
     342                 :          0 :                 dst += len;
     343                 :            : 
     344                 :          0 :                 if (slen == 0)
     345                 :          0 :                         ms = ms->next;
     346                 :          0 :                 if (dlen == 0)
     347                 :          0 :                         i++;
     348                 :            :         }
     349                 :            : 
     350                 :          0 :         if (ms != NULL)
     351                 :            :                 return -ENOBUFS;
     352                 :          0 :         else if (tlen != m->pkt_len)
     353                 :            :                 return -EINVAL;
     354                 :            : 
     355                 :          0 :         md[0]->nb_segs = nb_seg;
     356                 :          0 :         md[0]->pkt_len = tlen;
     357                 :          0 :         md[0]->vlan_tci = m->vlan_tci;
     358                 :          0 :         md[0]->vlan_tci_outer = m->vlan_tci_outer;
     359                 :          0 :         md[0]->ol_flags = m->ol_flags;
     360                 :          0 :         md[0]->tx_offload = m->tx_offload;
     361                 :            : 
     362                 :          0 :         return nb_seg;
     363                 :            : }
     364                 :            : 
     365                 :            : /*
     366                 :            :  * Allocate a new mbuf with up to tx_pkt_nb_segs segments.
     367                 :            :  * Copy packet contents and offload information into the new segmented mbuf.
     368                 :            :  */
     369                 :            : static struct rte_mbuf *
     370                 :          0 : pkt_copy_split(const struct rte_mbuf *pkt)
     371                 :            : {
     372                 :            :         int32_t n, rc;
     373                 :            :         uint32_t i, len, nb_seg;
     374                 :            :         struct rte_mempool *mp;
     375                 :            :         uint16_t seglen[RTE_MAX_SEGS_PER_PKT];
     376                 :            :         struct rte_mbuf *p, *md[RTE_MAX_SEGS_PER_PKT];
     377                 :            : 
     378                 :          0 :         mp = current_fwd_lcore()->mbp;
     379                 :            : 
     380                 :          0 :         if (tx_pkt_split == TX_PKT_SPLIT_RND)
     381                 :          0 :                 nb_seg = rte_rand() % tx_pkt_nb_segs + 1;
     382                 :            :         else
     383                 :          0 :                 nb_seg = tx_pkt_nb_segs;
     384                 :            : 
     385                 :          0 :         memcpy(seglen, tx_pkt_seg_lengths, nb_seg * sizeof(seglen[0]));
     386                 :            : 
     387                 :            :         /* calculate number of segments to use and their length. */
     388                 :            :         len = 0;
     389                 :          0 :         for (i = 0; i != nb_seg && len < pkt->pkt_len; i++) {
     390                 :          0 :                 len += seglen[i];
     391                 :          0 :                 md[i] = NULL;
     392                 :            :         }
     393                 :            : 
     394                 :          0 :         n = pkt->pkt_len - len;
     395                 :            : 
     396                 :            :         /* update size of the last segment to fit rest of the packet */
     397                 :          0 :         if (n >= 0) {
     398                 :          0 :                 seglen[i - 1] += n;
     399                 :            :                 len += n;
     400                 :            :         }
     401                 :            : 
     402                 :            :         nb_seg = i;
     403                 :          0 :         while (i != 0) {
     404                 :          0 :                 p = rte_pktmbuf_alloc(mp);
     405                 :          0 :                 if (p == NULL) {
     406                 :          0 :                         TESTPMD_LOG(ERR,
     407                 :            :                                 "failed to allocate %u-th of %u mbuf "
     408                 :            :                                 "from mempool: %s\n",
     409                 :            :                                 nb_seg - i, nb_seg, mp->name);
     410                 :          0 :                         break;
     411                 :            :                 }
     412                 :            : 
     413                 :          0 :                 md[--i] = p;
     414                 :          0 :                 if (rte_pktmbuf_tailroom(md[i]) < seglen[i]) {
     415                 :          0 :                         TESTPMD_LOG(ERR, "mempool %s, %u-th segment: "
     416                 :            :                                 "expected seglen: %u, "
     417                 :            :                                 "actual mbuf tailroom: %u\n",
     418                 :            :                                 mp->name, i, seglen[i],
     419                 :            :                                 rte_pktmbuf_tailroom(md[i]));
     420                 :          0 :                         break;
     421                 :            :                 }
     422                 :            :         }
     423                 :            : 
     424                 :            :         /* all mbufs successfully allocated, do copy */
     425                 :          0 :         if (i == 0) {
     426                 :          0 :                 rc = mbuf_copy_split(pkt, md, seglen, nb_seg);
     427                 :          0 :                 if (rc < 0)
     428                 :          0 :                         TESTPMD_LOG(ERR,
     429                 :            :                                 "mbuf_copy_split for %p(len=%u, nb_seg=%u) "
     430                 :            :                                 "into %u segments failed with error code: %d\n",
     431                 :            :                                 pkt, pkt->pkt_len, pkt->nb_segs, nb_seg, rc);
     432                 :            : 
     433                 :            :                 /* figure out how many mbufs to free. */
     434                 :          0 :                 i = RTE_MAX(rc, 0);
     435                 :            :         }
     436                 :            : 
     437                 :            :         /* free unused mbufs */
     438                 :          0 :         for (; i != nb_seg; i++) {
     439                 :          0 :                 rte_pktmbuf_free_seg(md[i]);
     440                 :          0 :                 md[i] = NULL;
     441                 :            :         }
     442                 :            : 
     443                 :          0 :         return md[0];
     444                 :            : }
     445                 :            : 
     446                 :            : #if defined(RTE_LIB_GRO) || defined(RTE_LIB_GSO)
     447                 :            : /*
     448                 :            :  * Re-calculate IP checksum for merged/fragmented packets.
     449                 :            :  */
     450                 :            : static void
     451                 :          0 : pkts_ip_csum_recalc(struct rte_mbuf **pkts_burst, const uint16_t nb_pkts, uint64_t tx_offloads)
     452                 :            : {
     453                 :            :         int i;
     454                 :            :         struct rte_ipv4_hdr *ipv4_hdr;
     455                 :          0 :         for (i = 0; i < nb_pkts; i++) {
     456                 :          0 :                 if ((pkts_burst[i]->ol_flags & RTE_MBUF_F_TX_IPV4) &&
     457                 :          0 :                         (tx_offloads & RTE_ETH_TX_OFFLOAD_IPV4_CKSUM) == 0) {
     458                 :          0 :                         ipv4_hdr = rte_pktmbuf_mtod_offset(pkts_burst[i],
     459                 :            :                                                 struct rte_ipv4_hdr *,
     460                 :            :                                                 pkts_burst[i]->l2_len);
     461                 :          0 :                         ipv4_hdr->hdr_checksum = 0;
     462                 :          0 :                         ipv4_hdr->hdr_checksum = rte_ipv4_cksum(ipv4_hdr);
     463                 :            :                 }
     464                 :            :         }
     465                 :          0 : }
     466                 :            : #endif
     467                 :            : 
     468                 :            : static uint32_t
     469                 :          0 : get_ethertype_by_ptype(struct rte_ether_hdr *eth_hdr, uint32_t ptype)
     470                 :            : {
     471                 :            :         struct rte_vlan_hdr *vlan_hdr, *max_vlans;
     472                 :            :         uint16_t ethertype;
     473                 :            : 
     474                 :          0 :         switch (ptype) {
     475                 :            :         case RTE_PTYPE_L3_IPV4:
     476                 :            :         case RTE_PTYPE_L3_IPV4_EXT:
     477                 :            :         case RTE_PTYPE_L3_IPV4_EXT_UNKNOWN:
     478                 :            :         case RTE_PTYPE_INNER_L3_IPV4:
     479                 :            :         case RTE_PTYPE_INNER_L3_IPV4_EXT:
     480                 :            :         case RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN:
     481                 :            :                 return _htons(RTE_ETHER_TYPE_IPV4);
     482                 :          0 :         case RTE_PTYPE_L3_IPV6:
     483                 :            :         case RTE_PTYPE_L3_IPV6_EXT:
     484                 :            :         case RTE_PTYPE_L3_IPV6_EXT_UNKNOWN:
     485                 :            :         case RTE_PTYPE_INNER_L3_IPV6:
     486                 :            :         case RTE_PTYPE_INNER_L3_IPV6_EXT:
     487                 :            :         case RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN:
     488                 :          0 :                 return _htons(RTE_ETHER_TYPE_IPV6);
     489                 :          0 :         default:
     490                 :          0 :                 ethertype = eth_hdr->ether_type;
     491                 :          0 :                 vlan_hdr = RTE_PTR_ADD(eth_hdr, offsetof(struct rte_ether_hdr, ether_type));
     492                 :          0 :                 max_vlans = vlan_hdr + MAX_VLAN_HEADERS;
     493                 :          0 :                 while ((ethertype == _htons(RTE_ETHER_TYPE_VLAN) ||
     494                 :          0 :                                 ethertype == _htons(RTE_ETHER_TYPE_QINQ)) &&
     495                 :            :                                 vlan_hdr < max_vlans) {
     496                 :          0 :                         vlan_hdr++;
     497                 :          0 :                         ethertype = vlan_hdr->eth_proto;
     498                 :            :                 }
     499                 :          0 :                 return ethertype;
     500                 :            :         }
     501                 :            : }
     502                 :            : 
     503                 :            : static uint64_t
     504                 :          0 : get_tunnel_ol_flags_by_ptype(uint32_t ptype)
     505                 :            : {
     506                 :          0 :         switch ((ptype & RTE_PTYPE_TUNNEL_MASK)) {
     507                 :            :         case RTE_PTYPE_TUNNEL_GTPC:
     508                 :            :         case RTE_PTYPE_TUNNEL_GTPU:
     509                 :            :                 return RTE_MBUF_F_TX_TUNNEL_GTP;
     510                 :          0 :         case RTE_PTYPE_TUNNEL_VXLAN_GPE:
     511                 :          0 :                 return RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE;
     512                 :          0 :         case RTE_PTYPE_TUNNEL_VXLAN:
     513                 :          0 :                 return RTE_MBUF_F_TX_TUNNEL_VXLAN;
     514                 :          0 :         case RTE_PTYPE_TUNNEL_GENEVE:
     515                 :          0 :                 return RTE_MBUF_F_TX_TUNNEL_GENEVE;
     516                 :          0 :         case RTE_PTYPE_TUNNEL_NVGRE:
     517                 :            :         case RTE_PTYPE_TUNNEL_GRE:
     518                 :          0 :                 return RTE_MBUF_F_TX_TUNNEL_GRE;
     519                 :          0 :         case RTE_PTYPE_TUNNEL_IP:
     520                 :          0 :                 return RTE_MBUF_F_TX_TUNNEL_IPIP;
     521                 :          0 :         default:
     522                 :            :                 printf("unrecognized tunnel ptype: %x\n",
     523                 :            :                         (ptype & RTE_PTYPE_TUNNEL_MASK));
     524                 :          0 :                 return 0;
     525                 :            :         }
     526                 :            : }
     527                 :            : 
     528                 :            : static void
     529                 :            : parse_inner_l4_proto(void *outer_l3_hdr,
     530                 :            :                         struct testpmd_offload_info *info)
     531                 :            : {
     532                 :            :         struct rte_ipv4_hdr *ipv4_hdr = outer_l3_hdr;
     533                 :            :         struct rte_ipv6_hdr *ipv6_hdr = outer_l3_hdr;
     534                 :          0 :         if (info->ethertype == _htons(RTE_ETHER_TYPE_IPV4))
     535                 :          0 :                 info->l4_proto = ipv4_hdr->next_proto_id;
     536                 :            :         else
     537                 :          0 :                 info->l4_proto = ipv6_hdr->proto;
     538                 :            : }
     539                 :            : 
     540                 :            : static uint8_t
     541                 :          0 : parse_l4_proto(const struct rte_mbuf *m, uint32_t off, uint32_t ptype)
     542                 :            : {
     543                 :          0 :         int frag = 0, ret;
     544                 :            : 
     545                 :          0 :         if (RTE_ETH_IS_IPV4_HDR(ptype)) {
     546                 :            :                 const struct rte_ipv4_hdr *ip4h;
     547                 :            :                 struct rte_ipv4_hdr ip4h_copy;
     548                 :          0 :                 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
     549                 :          0 :                 if (unlikely(ip4h == NULL))
     550                 :            :                         return 0;
     551                 :            : 
     552                 :          0 :                 return ip4h->next_proto_id;
     553                 :          0 :         } else if (RTE_ETH_IS_IPV6_HDR(ptype)) {
     554                 :            :                 const struct rte_ipv6_hdr *ip6h;
     555                 :            :                 struct rte_ipv6_hdr ip6h_copy;
     556                 :          0 :                 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
     557                 :          0 :                 if (unlikely(ip6h == NULL))
     558                 :            :                         return 0;
     559                 :            : 
     560                 :          0 :                 if ((ptype & RTE_PTYPE_INNER_L3_MASK) ==
     561                 :            :                                 RTE_PTYPE_INNER_L3_IPV6_EXT) {
     562                 :          0 :                         ret = rte_net_skip_ip6_ext(ip6h->proto, m, &off, &frag);
     563                 :          0 :                         if (ret < 0)
     564                 :            :                                 return 0;
     565                 :          0 :                         return ret;
     566                 :            :                 }
     567                 :            : 
     568                 :          0 :                 return ip6h->proto;
     569                 :            :         }
     570                 :            :         return 0;
     571                 :            : }
     572                 :            : 
     573                 :            : /*
     574                 :            :  * Receive a burst of packets, and for each packet:
     575                 :            :  *  - parse packet, and try to recognize a supported packet type (1)
     576                 :            :  *  - if it's not a supported packet type, don't touch the packet, else:
     577                 :            :  *  - reprocess the checksum of all supported layers. This is done in SW
     578                 :            :  *    or HW, depending on testpmd command line configuration
     579                 :            :  *  - if TSO is enabled in testpmd command line, also flag the mbuf for TCP
     580                 :            :  *    segmentation offload (this implies HW TCP checksum)
     581                 :            :  * Then transmit packets on the output port.
     582                 :            :  *
     583                 :            :  * (1) Supported packets are:
     584                 :            :  *   Ether / (vlan) / IP|IP6 / UDP|TCP|SCTP .
     585                 :            :  *   Ether / (vlan) / outer IP|IP6 / outer UDP / VxLAN / Ether / IP|IP6 /
     586                 :            :  *           UDP|TCP|SCTP
     587                 :            :  *   Ether / (vlan) / outer IP|IP6 / outer UDP / VXLAN-GPE / Ether / IP|IP6 /
     588                 :            :  *           UDP|TCP|SCTP
     589                 :            :  *   Ether / (vlan) / outer IP|IP6 / outer UDP / VXLAN-GPE / IP|IP6 /
     590                 :            :  *           UDP|TCP|SCTP
     591                 :            :  *   Ether / (vlan) / outer IP / outer UDP / GTP / IP|IP6 / UDP|TCP|SCTP
     592                 :            :  *   Ether / (vlan) / outer IP|IP6 / GRE / Ether / IP|IP6 / UDP|TCP|SCTP
     593                 :            :  *   Ether / (vlan) / outer IP|IP6 / GRE / IP|IP6 / UDP|TCP|SCTP
     594                 :            :  *   Ether / (vlan) / outer IP|IP6 / IP|IP6 / UDP|TCP|SCTP
     595                 :            :  *
     596                 :            :  * The testpmd command line for this forward engine sets the flags
     597                 :            :  * TESTPMD_TX_OFFLOAD_* in ports[tx_port].tx_ol_flags. They control
     598                 :            :  * whether a checksum must be calculated in software or in hardware. The
     599                 :            :  * IP, UDP, TCP and SCTP flags always concern the inner layer. The
     600                 :            :  * OUTER_IP is only useful for tunnel packets.
     601                 :            :  */
     602                 :            : static bool
     603                 :          0 : pkt_burst_checksum_forward(struct fwd_stream *fs)
     604                 :            : {
     605                 :            :         struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
     606                 :            : #ifdef RTE_LIB_GSO
     607                 :            :         struct rte_mbuf *gso_segments[GSO_MAX_PKT_BURST];
     608                 :            :         struct rte_gso_ctx *gso_ctx;
     609                 :            : #endif
     610                 :            :         struct rte_mbuf **tx_pkts_burst;
     611                 :            :         struct rte_port *txp;
     612                 :            :         struct rte_mbuf *m, *p;
     613                 :            :         struct rte_ether_hdr *eth_hdr;
     614                 :            :         void *l3_hdr = NULL, *outer_l3_hdr = NULL; /* can be IPv4 or IPv6 */
     615                 :            : #ifdef RTE_LIB_GRO
     616                 :            :         void **gro_ctx;
     617                 :            :         uint16_t gro_pkts_num;
     618                 :            :         uint8_t gro_enable;
     619                 :            : #endif
     620                 :            :         uint16_t nb_rx;
     621                 :            :         uint16_t nb_prep;
     622                 :            :         uint16_t i;
     623                 :            :         uint64_t rx_ol_flags, tx_ol_flags;
     624                 :            :         uint64_t tx_offloads;
     625                 :            :         uint32_t rx_bad_ip_csum;
     626                 :            :         uint32_t rx_bad_l4_csum;
     627                 :            :         uint32_t rx_bad_outer_l4_csum;
     628                 :            :         uint32_t rx_bad_outer_ip_csum;
     629                 :            :         struct testpmd_offload_info info;
     630                 :          0 :         struct rte_net_hdr_lens hdr_lens = {0};
     631                 :            :         uint32_t ptype;
     632                 :            : 
     633                 :            :         /* receive a burst of packet */
     634                 :          0 :         nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
     635                 :          0 :         if (unlikely(nb_rx == 0)) {
     636                 :            : #ifndef RTE_LIB_GRO
     637                 :            :                 return false;
     638                 :            : #else
     639                 :          0 :                 gro_enable = gro_ports[fs->rx_port].enable;
     640                 :            :                 /*
     641                 :            :                  * Check if packets need to be flushed in the GRO context
     642                 :            :                  * due to a timeout.
     643                 :            :                  *
     644                 :            :                  * Continue only in GRO heavyweight mode and if there are
     645                 :            :                  * packets in the GRO context.
     646                 :            :                  */
     647                 :          0 :                 if (!gro_enable || (gro_flush_cycles == GRO_DEFAULT_FLUSH_CYCLES) ||
     648                 :          0 :                         (rte_gro_get_pkt_count(current_fwd_lcore()->gro_ctx) == 0))
     649                 :          0 :                         return false;
     650                 :            : #endif
     651                 :            :         }
     652                 :            : 
     653                 :            :         rx_bad_ip_csum = 0;
     654                 :            :         rx_bad_l4_csum = 0;
     655                 :            :         rx_bad_outer_l4_csum = 0;
     656                 :            :         rx_bad_outer_ip_csum = 0;
     657                 :            : 
     658                 :          0 :         txp = &ports[fs->tx_port];
     659                 :          0 :         tx_offloads = txp->dev_conf.txmode.offloads;
     660                 :            :         memset(&info, 0, sizeof(info));
     661                 :          0 :         info.tso_segsz = txp->tso_segsz;
     662                 :          0 :         info.tunnel_tso_segsz = txp->tunnel_tso_segsz;
     663                 :            : #ifdef RTE_LIB_GSO
     664                 :          0 :         if (gso_ports[fs->tx_port].enable)
     665                 :          0 :                 info.gso_enable = 1;
     666                 :            : #endif
     667                 :            : 
     668                 :          0 :         for (i = 0; i < nb_rx; i++) {
     669                 :          0 :                 if (likely(i < nb_rx - 1))
     670                 :          0 :                         rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
     671                 :            :                                                        void *));
     672                 :            : 
     673                 :          0 :                 m = pkts_burst[i];
     674                 :          0 :                 info.is_tunnel = 0;
     675                 :          0 :                 info.pkt_len = rte_pktmbuf_pkt_len(m);
     676                 :          0 :                 tx_ol_flags = m->ol_flags &
     677                 :            :                               (RTE_MBUF_F_INDIRECT | RTE_MBUF_F_EXTERNAL);
     678                 :            :                 rx_ol_flags = m->ol_flags;
     679                 :            : 
     680                 :            :                 /* Update the L3/L4 checksum error packet statistics */
     681                 :          0 :                 if ((rx_ol_flags & RTE_MBUF_F_RX_IP_CKSUM_MASK) == RTE_MBUF_F_RX_IP_CKSUM_BAD)
     682                 :          0 :                         rx_bad_ip_csum += 1;
     683                 :          0 :                 if ((rx_ol_flags & RTE_MBUF_F_RX_L4_CKSUM_MASK) == RTE_MBUF_F_RX_L4_CKSUM_BAD)
     684                 :          0 :                         rx_bad_l4_csum += 1;
     685                 :          0 :                 if (rx_ol_flags & RTE_MBUF_F_RX_OUTER_L4_CKSUM_BAD)
     686                 :          0 :                         rx_bad_outer_l4_csum += 1;
     687                 :          0 :                 if (rx_ol_flags & RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD)
     688                 :          0 :                         rx_bad_outer_ip_csum += 1;
     689                 :            : 
     690                 :            :                 /* step 1: dissect packet, parsing optional vlan, ip4/ip6, vxlan
     691                 :            :                  * and inner headers */
     692                 :            : 
     693                 :          0 :                 eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
     694                 :          0 :                 if (ports[fs->tx_port].fwd_mac_swap) {
     695                 :          0 :                         rte_ether_addr_copy(&peer_eth_addrs[fs->peer_addr],
     696                 :            :                                             &eth_hdr->dst_addr);
     697                 :            :                         rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
     698                 :            :                                             &eth_hdr->src_addr);
     699                 :            :                 }
     700                 :            : 
     701                 :          0 :                 ptype = rte_net_get_ptype(m, &hdr_lens, RTE_PTYPE_ALL_MASK);
     702                 :          0 :                 info.l2_len = hdr_lens.l2_len;
     703                 :          0 :                 info.l3_len = hdr_lens.l3_len;
     704                 :          0 :                 info.l4_len = hdr_lens.l4_len;
     705                 :          0 :                 info.ethertype = get_ethertype_by_ptype(eth_hdr,
     706                 :            :                                         ptype & RTE_PTYPE_L3_MASK);
     707                 :          0 :                 info.l4_proto = parse_l4_proto(m, info.l2_len, ptype);
     708                 :            : 
     709                 :          0 :                 l3_hdr = (char *)eth_hdr + info.l2_len;
     710                 :            :                 /* check if it's a supported tunnel */
     711                 :          0 :                 if (txp->parse_tunnel && RTE_ETH_IS_TUNNEL_PKT(ptype) != 0) {
     712                 :          0 :                         info.is_tunnel = 1;
     713                 :            :                         update_tunnel_outer(&info);
     714                 :          0 :                         info.l2_len = hdr_lens.inner_l2_len + hdr_lens.tunnel_len;
     715                 :          0 :                         info.l3_len = hdr_lens.inner_l3_len;
     716                 :          0 :                         info.l4_len = hdr_lens.inner_l4_len;
     717                 :          0 :                         eth_hdr = (struct rte_ether_hdr *)(char *)l3_hdr +
     718                 :          0 :                                         info.outer_l3_len + hdr_lens.tunnel_len;
     719                 :          0 :                         info.ethertype = get_ethertype_by_ptype(eth_hdr,
     720                 :            :                                                 ptype & RTE_PTYPE_INNER_L3_MASK);
     721                 :          0 :                         tx_ol_flags |= get_tunnel_ol_flags_by_ptype(ptype);
     722                 :            :                 }
     723                 :            :                 /* update l3_hdr and outer_l3_hdr if a tunnel was parsed */
     724                 :          0 :                 if (info.is_tunnel) {
     725                 :            :                         outer_l3_hdr = l3_hdr;
     726                 :          0 :                         l3_hdr = (char *)l3_hdr + info.outer_l3_len + info.l2_len;
     727                 :            :                         parse_inner_l4_proto(l3_hdr, &info);
     728                 :            :                 }
     729                 :            :                 /* step 2: depending on user command line configuration,
     730                 :            :                  * recompute checksum either in software or flag the
     731                 :            :                  * mbuf to offload the calculation to the NIC. If TSO
     732                 :            :                  * is configured, prepare the mbuf for TCP segmentation. */
     733                 :            : 
     734                 :            :                 /* process checksums of inner headers first */
     735                 :          0 :                 tx_ol_flags |= process_inner_cksums(l3_hdr, &info,
     736                 :            :                         tx_offloads, m);
     737                 :            : 
     738                 :            :                 /* Then process outer headers if any. Note that the software
     739                 :            :                  * checksum will be wrong if one of the inner checksums is
     740                 :            :                  * processed in hardware. */
     741                 :          0 :                 if (info.is_tunnel == 1) {
     742                 :          0 :                         tx_ol_flags |= process_outer_cksums(outer_l3_hdr, &info,
     743                 :            :                                         tx_offloads,
     744                 :          0 :                                         !!(tx_ol_flags & (RTE_MBUF_F_TX_TCP_SEG |
     745                 :            :                                                 RTE_MBUF_F_TX_UDP_SEG)),
     746                 :            :                                         m);
     747                 :            :                 }
     748                 :            : 
     749                 :            :                 /* step 3: fill the mbuf meta data (flags and header lengths) */
     750                 :            : 
     751                 :          0 :                 m->tx_offload = 0;
     752                 :          0 :                 if (info.is_tunnel == 1) {
     753                 :          0 :                         if (info.tunnel_tso_segsz ||
     754                 :            :                             (tx_offloads &
     755                 :          0 :                              RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM) ||
     756                 :            :                             (tx_offloads &
     757                 :            :                              RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM)) {
     758                 :          0 :                                 m->outer_l2_len = info.outer_l2_len;
     759                 :          0 :                                 m->outer_l3_len = info.outer_l3_len;
     760                 :          0 :                                 m->l2_len = info.l2_len;
     761                 :          0 :                                 m->l3_len = info.l3_len;
     762                 :          0 :                                 m->l4_len = info.l4_len;
     763                 :          0 :                                 m->tso_segsz = info.tunnel_tso_segsz;
     764                 :            :                         }
     765                 :            :                         else {
     766                 :            :                                 /* if there is a outer UDP cksum
     767                 :            :                                    processed in sw and the inner in hw,
     768                 :            :                                    the outer checksum will be wrong as
     769                 :            :                                    the payload will be modified by the
     770                 :            :                                    hardware */
     771                 :          0 :                                 m->l2_len = info.outer_l2_len +
     772                 :          0 :                                         info.outer_l3_len + info.l2_len;
     773                 :          0 :                                 m->l3_len = info.l3_len;
     774                 :          0 :                                 m->l4_len = info.l4_len;
     775                 :            :                         }
     776                 :            :                 } else {
     777                 :            :                         /* this is only useful if an offload flag is
     778                 :            :                          * set, but it does not hurt to fill it in any
     779                 :            :                          * case */
     780                 :          0 :                         m->l2_len = info.l2_len;
     781                 :          0 :                         m->l3_len = info.l3_len;
     782                 :          0 :                         m->l4_len = info.l4_len;
     783                 :          0 :                         m->tso_segsz = info.tso_segsz;
     784                 :            :                 }
     785                 :          0 :                 m->ol_flags = tx_ol_flags;
     786                 :            : 
     787                 :            :                 /* Do split & copy for the packet. */
     788                 :          0 :                 if (tx_pkt_split != TX_PKT_SPLIT_OFF) {
     789                 :          0 :                         p = pkt_copy_split(m);
     790                 :          0 :                         if (p != NULL) {
     791                 :          0 :                                 rte_pktmbuf_free(m);
     792                 :            :                                 m = p;
     793                 :          0 :                                 pkts_burst[i] = m;
     794                 :            :                         }
     795                 :            :                 }
     796                 :            : 
     797                 :            :                 /* if verbose mode is enabled, dump debug info */
     798                 :          0 :                 if (verbose_level > 0) {
     799                 :            :                         char buf[256];
     800                 :            : 
     801                 :            :                         printf("-----------------\n");
     802                 :          0 :                         printf("port=%u, mbuf=%p, pkt_len=%u, nb_segs=%u:\n",
     803                 :          0 :                                 fs->rx_port, m, m->pkt_len, m->nb_segs);
     804                 :            :                         /* dump rx parsed packet info */
     805                 :          0 :                         rte_get_rx_ol_flag_list(rx_ol_flags, buf, sizeof(buf));
     806                 :          0 :                         printf("rx: l2_len=%d ethertype=%x l3_len=%d "
     807                 :            :                                 "l4_proto=%d l4_len=%d flags=%s\n",
     808                 :          0 :                                 info.l2_len, rte_be_to_cpu_16(info.ethertype),
     809                 :          0 :                                 info.l3_len, info.l4_proto, info.l4_len, buf);
     810                 :          0 :                         if (rx_ol_flags & RTE_MBUF_F_RX_LRO)
     811                 :          0 :                                 printf("rx: m->lro_segsz=%u\n", m->tso_segsz);
     812                 :          0 :                         if (info.is_tunnel == 1)
     813                 :          0 :                                 printf("rx: outer_l2_len=%d outer_ethertype=%x "
     814                 :          0 :                                         "outer_l3_len=%d\n", info.outer_l2_len,
     815                 :          0 :                                         rte_be_to_cpu_16(info.outer_ethertype),
     816                 :          0 :                                         info.outer_l3_len);
     817                 :            :                         /* dump tx packet info */
     818                 :          0 :                         if ((tx_offloads & (RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
     819                 :            :                                             RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
     820                 :            :                                             RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
     821                 :          0 :                                             RTE_ETH_TX_OFFLOAD_SCTP_CKSUM)) ||
     822                 :          0 :                                 info.tso_segsz != 0)
     823                 :          0 :                                 printf("tx: m->l2_len=%d m->l3_len=%d "
     824                 :            :                                         "m->l4_len=%d\n",
     825                 :          0 :                                         m->l2_len, m->l3_len, m->l4_len);
     826                 :          0 :                         if (info.is_tunnel == 1) {
     827                 :          0 :                                 if ((tx_offloads &
     828                 :          0 :                                     RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM) ||
     829                 :            :                                     (tx_offloads &
     830                 :          0 :                                     RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM) ||
     831                 :          0 :                                     (tx_ol_flags & RTE_MBUF_F_TX_OUTER_IPV6))
     832                 :          0 :                                         printf("tx: m->outer_l2_len=%d "
     833                 :            :                                                 "m->outer_l3_len=%d\n",
     834                 :          0 :                                                 m->outer_l2_len,
     835                 :          0 :                                                 m->outer_l3_len);
     836                 :          0 :                                 if (info.tunnel_tso_segsz != 0 &&
     837                 :          0 :                                                 (m->ol_flags & (RTE_MBUF_F_TX_TCP_SEG |
     838                 :            :                                                         RTE_MBUF_F_TX_UDP_SEG)))
     839                 :          0 :                                         printf("tx: m->tso_segsz=%d\n",
     840                 :          0 :                                                 m->tso_segsz);
     841                 :          0 :                         } else if (info.tso_segsz != 0 &&
     842                 :          0 :                                         (m->ol_flags & (RTE_MBUF_F_TX_TCP_SEG |
     843                 :            :                                                 RTE_MBUF_F_TX_UDP_SEG)))
     844                 :          0 :                                 printf("tx: m->tso_segsz=%d\n", m->tso_segsz);
     845                 :          0 :                         rte_get_tx_ol_flag_list(m->ol_flags, buf, sizeof(buf));
     846                 :            :                         printf("tx: flags=%s", buf);
     847                 :            :                         printf("\n");
     848                 :            :                 }
     849                 :            :         }
     850                 :            : 
     851                 :            : #ifdef RTE_LIB_GRO
     852                 :          0 :         gro_enable = gro_ports[fs->rx_port].enable;
     853                 :          0 :         if (unlikely(gro_enable)) {
     854                 :          0 :                 if (gro_flush_cycles == GRO_DEFAULT_FLUSH_CYCLES) {
     855                 :          0 :                         nb_rx = rte_gro_reassemble_burst(pkts_burst, nb_rx,
     856                 :          0 :                                         &(gro_ports[fs->rx_port].param));
     857                 :            :                 } else {
     858                 :          0 :                         gro_ctx = current_fwd_lcore()->gro_ctx;
     859                 :          0 :                         nb_rx = rte_gro_reassemble(pkts_burst, nb_rx, gro_ctx);
     860                 :            : 
     861                 :          0 :                         if (++fs->gro_times >= gro_flush_cycles) {
     862                 :          0 :                                 gro_pkts_num = rte_gro_get_pkt_count(gro_ctx);
     863                 :          0 :                                 if (gro_pkts_num > MAX_PKT_BURST - nb_rx)
     864                 :          0 :                                         gro_pkts_num = MAX_PKT_BURST - nb_rx;
     865                 :            : 
     866                 :          0 :                                 nb_rx += rte_gro_timeout_flush(gro_ctx, 0,
     867                 :            :                                                 RTE_GRO_TCP_IPV4,
     868                 :            :                                                 &pkts_burst[nb_rx],
     869                 :            :                                                 gro_pkts_num);
     870                 :          0 :                                 fs->gro_times = 0;
     871                 :            :                         }
     872                 :          0 :                         if (nb_rx == 0)
     873                 :            :                                 return false;
     874                 :            :                 }
     875                 :            : 
     876                 :          0 :                 pkts_ip_csum_recalc(pkts_burst, nb_rx, tx_offloads);
     877                 :            :         }
     878                 :            : #endif
     879                 :            : 
     880                 :            : #ifdef RTE_LIB_GSO
     881                 :          0 :         if (gso_ports[fs->tx_port].enable != 0) {
     882                 :            :                 uint16_t nb_segments = 0;
     883                 :            : 
     884                 :          0 :                 gso_ctx = &(current_fwd_lcore()->gso_ctx);
     885                 :          0 :                 gso_ctx->gso_size = gso_max_segment_size;
     886                 :          0 :                 for (i = 0; i < nb_rx; i++) {
     887                 :            :                         int ret;
     888                 :            : 
     889                 :          0 :                         ret = rte_gso_segment(pkts_burst[i], gso_ctx,
     890                 :          0 :                                         &gso_segments[nb_segments],
     891                 :          0 :                                         GSO_MAX_PKT_BURST - nb_segments);
     892                 :          0 :                         if (ret >= 1) {
     893                 :            :                                 /* pkts_burst[i] can be freed safely here. */
     894                 :          0 :                                 rte_pktmbuf_free(pkts_burst[i]);
     895                 :          0 :                                 nb_segments += ret;
     896                 :          0 :                         } else if (ret == 0) {
     897                 :            :                                 /* 0 means it can be transmitted directly
     898                 :            :                                  * without gso.
     899                 :            :                                  */
     900                 :          0 :                                 gso_segments[nb_segments] = pkts_burst[i];
     901                 :          0 :                                 nb_segments += 1;
     902                 :            :                         } else {
     903                 :          0 :                                 TESTPMD_LOG(DEBUG, "Unable to segment packet");
     904                 :          0 :                                 rte_pktmbuf_free(pkts_burst[i]);
     905                 :            :                         }
     906                 :            :                 }
     907                 :            : 
     908                 :            :                 tx_pkts_burst = gso_segments;
     909                 :            :                 nb_rx = nb_segments;
     910                 :            : 
     911                 :          0 :                 pkts_ip_csum_recalc(tx_pkts_burst, nb_rx, tx_offloads);
     912                 :            :         } else
     913                 :            : #endif
     914                 :            :                 tx_pkts_burst = pkts_burst;
     915                 :            : 
     916                 :          0 :         nb_prep = rte_eth_tx_prepare(fs->tx_port, fs->tx_queue,
     917                 :            :                         tx_pkts_burst, nb_rx);
     918                 :          0 :         if (nb_prep != nb_rx) {
     919                 :          0 :                 fprintf(stderr,
     920                 :            :                         "Preparing packet burst to transmit failed: %s\n",
     921                 :            :                         rte_strerror(rte_errno));
     922                 :          0 :                 fs->fwd_dropped += (nb_rx - nb_prep);
     923                 :          0 :                 rte_pktmbuf_free_bulk(&tx_pkts_burst[nb_prep], nb_rx - nb_prep);
     924                 :            :         }
     925                 :            : 
     926                 :          0 :         common_fwd_stream_transmit(fs, tx_pkts_burst, nb_prep);
     927                 :            : 
     928                 :          0 :         fs->rx_bad_ip_csum += rx_bad_ip_csum;
     929                 :          0 :         fs->rx_bad_l4_csum += rx_bad_l4_csum;
     930                 :          0 :         fs->rx_bad_outer_l4_csum += rx_bad_outer_l4_csum;
     931                 :          0 :         fs->rx_bad_outer_ip_csum += rx_bad_outer_ip_csum;
     932                 :            : 
     933                 :          0 :         return true;
     934                 :            : }
     935                 :            : 
     936                 :            : struct fwd_engine csum_fwd_engine = {
     937                 :            :         .fwd_mode_name  = "csum",
     938                 :            :         .stream_init    = common_fwd_stream_init,
     939                 :            :         .packet_fwd     = pkt_burst_checksum_forward,
     940                 :            : };

Generated by: LCOV version 1.14