net: add rte prefix to ICMP defines
[dpdk.git] / app / test-pmd / icmpecho.c
index 4a277b8..949cc55 100644 (file)
@@ -1,35 +1,5 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2013 6WIND
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of 6WIND S.A. nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2013 6WIND S.A.
  */
 
 #include <stdarg.h>
@@ -52,7 +22,6 @@
 #include <rte_lcore.h>
 #include <rte_atomic.h>
 #include <rte_branch_prediction.h>
-#include <rte_ring.h>
 #include <rte_memory.h>
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
 #include <rte_ip.h>
 #include <rte_icmp.h>
 #include <rte_string_fns.h>
+#include <rte_flow.h>
 
 #include "testpmd.h"
 
 static const char *
 arp_op_name(uint16_t arp_op)
 {
-       switch (arp_op ) {
-       case ARP_OP_REQUEST:
+       switch (arp_op) {
+       case RTE_ARP_OP_REQUEST:
                return "ARP Request";
-       case ARP_OP_REPLY:
+       case RTE_ARP_OP_REPLY:
                return "ARP Reply";
-       case ARP_OP_REVREQUEST:
+       case RTE_ARP_OP_REVREQUEST:
                return "Reverse ARP Request";
-       case ARP_OP_REVREPLY:
+       case RTE_ARP_OP_REVREPLY:
                return "Reverse ARP Reply";
-       case ARP_OP_INVREQUEST:
+       case RTE_ARP_OP_INVREQUEST:
                return "Peer Identify Request";
-       case ARP_OP_INVREPLY:
+       case RTE_ARP_OP_INVREPLY:
                return "Peer Identify Reply";
        default:
                break;
@@ -88,7 +58,7 @@ arp_op_name(uint16_t arp_op)
 }
 
 static const char *
-ip_proto_name(uint8_t ip_proto)
+ip_proto_name(uint16_t ip_proto)
 {
        static const char * ip_proto_names[] = {
                "IP6HOPOPTS", /**< IP6 hop-by-hop options */
@@ -200,7 +170,7 @@ ip_proto_name(uint8_t ip_proto)
                "OSPFIGP",    /**< OSPFIGP */
 
                "SRPC",       /**< Strite RPC protocol */
-               "LARP",       /**< Locus Address Resoloution */
+               "LARP",       /**< Locus Address Resolution */
                "MTP",        /**< Multicast Transport */
                "AX25",       /**< AX.25 Frames */
                "4IN4",       /**< IP encapsulated in IP */
@@ -221,12 +191,16 @@ ip_proto_name(uint8_t ip_proto)
        if (ip_proto < sizeof(ip_proto_names) / sizeof(ip_proto_names[0]))
                return ip_proto_names[ip_proto];
        switch (ip_proto) {
+#ifdef IPPROTO_PGM
        case IPPROTO_PGM:  /**< PGM */
                return "PGM";
+#endif
        case IPPROTO_SCTP:  /**< Stream Control Transport Protocol */
                return "SCTP";
+#ifdef IPPROTO_DIVERT
        case IPPROTO_DIVERT: /**< divert pseudo-protocol */
                return "DIVERT";
+#endif
        case IPPROTO_RAW: /**< raw IP packet */
                return "RAW";
        default:
@@ -235,18 +209,6 @@ ip_proto_name(uint8_t ip_proto)
        return "UNASSIGNED";
 }
 
-static void
-ether_addr_to_hexa(const struct ether_addr *ea, char *buf)
-{
-       sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
-               ea->addr_bytes[0],
-               ea->addr_bytes[1],
-               ea->addr_bytes[2],
-               ea->addr_bytes[3],
-               ea->addr_bytes[4],
-               ea->addr_bytes[5]);
-}
-
 static void
 ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf)
 {
@@ -259,11 +221,11 @@ ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf)
 }
 
 static void
-ether_addr_dump(const char *what, const struct ether_addr *ea)
+ether_addr_dump(const char *what, const struct rte_ether_addr *ea)
 {
-       char buf[18];
+       char buf[RTE_ETHER_ADDR_FMT_SIZE];
 
-       ether_addr_to_hexa(ea, buf);
+       rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, ea);
        if (what)
                printf("%s", what);
        printf("%s", buf);
@@ -280,8 +242,32 @@ ipv4_addr_dump(const char *what, uint32_t be_ipv4_addr)
        printf("%s", buf);
 }
 
+static uint16_t
+ipv4_hdr_cksum(struct ipv4_hdr *ip_h)
+{
+       uint16_t *v16_h;
+       uint32_t ip_cksum;
+
+       /*
+        * Compute the sum of successive 16-bit words of the IPv4 header,
+        * skipping the checksum field of the header.
+        */
+       v16_h = (unaligned_uint16_t *) ip_h;
+       ip_cksum = v16_h[0] + v16_h[1] + v16_h[2] + v16_h[3] +
+               v16_h[4] + v16_h[6] + v16_h[7] + v16_h[8] + v16_h[9];
+
+       /* reduce 32 bit checksum to 16 bits and complement it */
+       ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16);
+       ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16);
+       ip_cksum = (~ip_cksum) & 0x0000FFFF;
+       return (ip_cksum == 0) ? 0xFFFF : (uint16_t) ip_cksum;
+}
+
+#define is_multicast_ipv4_addr(ipv4_addr) \
+       (((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0)
+
 /*
- * Receive a burst of packets, lookup for ICMP echo requets, and, if any,
+ * Receive a burst of packets, lookup for ICMP echo requests, and, if any,
  * send back ICMP echo replies.
  */
 static void
@@ -289,12 +275,13 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
 {
        struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
        struct rte_mbuf *pkt;
-       struct ether_hdr *eth_h;
-       struct vlan_hdr *vlan_h;
-       struct arp_hdr  *arp_h;
+       struct rte_ether_hdr *eth_h;
+       struct rte_vlan_hdr *vlan_h;
+       struct rte_arp_hdr  *arp_h;
        struct ipv4_hdr *ip_h;
-       struct icmp_hdr *icmp_h;
-       struct ether_addr eth_addr;
+       struct rte_icmp_hdr *icmp_h;
+       struct rte_ether_addr eth_addr;
+       uint32_t retry;
        uint32_t ip_addr;
        uint16_t nb_rx;
        uint16_t nb_tx;
@@ -303,6 +290,7 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
        uint16_t vlan_id;
        uint16_t arp_op;
        uint16_t arp_pro;
+       uint32_t cksum;
        uint8_t  i;
        int l2_len;
 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
@@ -329,20 +317,23 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
        fs->rx_packets += nb_rx;
        nb_replies = 0;
        for (i = 0; i < nb_rx; i++) {
+               if (likely(i < nb_rx - 1))
+                       rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
+                                                      void *));
                pkt = pkts_burst[i];
-               eth_h = (struct ether_hdr *) pkt->data;
+               eth_h = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
                eth_type = RTE_BE_TO_CPU_16(eth_h->ether_type);
-               l2_len = sizeof(struct ether_hdr);
+               l2_len = sizeof(struct rte_ether_hdr);
                if (verbose_level > 0) {
                        printf("\nPort %d pkt-len=%u nb-segs=%u\n",
                               fs->rx_port, pkt->pkt_len, pkt->nb_segs);
                        ether_addr_dump("  ETH:  src=", &eth_h->s_addr);
                        ether_addr_dump(" dst=", &eth_h->d_addr);
                }
-               if (eth_type == ETHER_TYPE_VLAN) {
-                       vlan_h = (struct vlan_hdr *)
-                               ((char *)eth_h + sizeof(struct ether_hdr));
-                       l2_len  += sizeof(struct vlan_hdr);
+               if (eth_type == RTE_ETHER_TYPE_VLAN) {
+                       vlan_h = (struct rte_vlan_hdr *)
+                               ((char *)eth_h + sizeof(struct rte_ether_hdr));
+                       l2_len  += sizeof(struct rte_vlan_hdr);
                        eth_type = rte_be_to_cpu_16(vlan_h->eth_proto);
                        if (verbose_level > 0) {
                                vlan_id = rte_be_to_cpu_16(vlan_h->vlan_tci)
@@ -355,23 +346,23 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
                }
 
                /* Reply to ARP requests */
-               if (eth_type == ETHER_TYPE_ARP) {
-                       arp_h = (struct arp_hdr *) ((char *)eth_h + l2_len);
-                       arp_op = RTE_BE_TO_CPU_16(arp_h->arp_op);
-                       arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_pro);
+               if (eth_type == RTE_ETHER_TYPE_ARP) {
+                       arp_h = (struct rte_arp_hdr *) ((char *)eth_h + l2_len);
+                       arp_op = RTE_BE_TO_CPU_16(arp_h->arp_opcode);
+                       arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_protocol);
                        if (verbose_level > 0) {
                                printf("  ARP:  hrd=%d proto=0x%04x hln=%d "
                                       "pln=%d op=%u (%s)\n",
-                                      RTE_BE_TO_CPU_16(arp_h->arp_hrd),
-                                      arp_pro, arp_h->arp_hln,
-                                      arp_h->arp_pln, arp_op,
+                                      RTE_BE_TO_CPU_16(arp_h->arp_hardware),
+                                      arp_pro, arp_h->arp_hlen,
+                                      arp_h->arp_plen, arp_op,
                                       arp_op_name(arp_op));
                        }
-                       if ((RTE_BE_TO_CPU_16(arp_h->arp_hrd) !=
-                            ARP_HRD_ETHER) ||
-                           (arp_pro != ETHER_TYPE_IPv4) ||
-                           (arp_h->arp_hln != 6) ||
-                           (arp_h->arp_pln != 4)
+                       if ((RTE_BE_TO_CPU_16(arp_h->arp_hardware) !=
+                            RTE_ARP_HRD_ETHER) ||
+                           (arp_pro != RTE_ETHER_TYPE_IPv4) ||
+                           (arp_h->arp_hlen != 6) ||
+                           (arp_h->arp_plen != 4)
                            ) {
                                rte_pktmbuf_free(pkt);
                                if (verbose_level > 0)
@@ -379,22 +370,20 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
                                continue;
                        }
                        if (verbose_level > 0) {
-                               memcpy(&eth_addr,
-                                      arp_h->arp_data.arp_ip.arp_sha, 6);
+                               rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
+                                               &eth_addr);
                                ether_addr_dump("        sha=", &eth_addr);
-                               memcpy(&ip_addr,
-                                      arp_h->arp_data.arp_ip.arp_sip, 4);
+                               ip_addr = arp_h->arp_data.arp_sip;
                                ipv4_addr_dump(" sip=", ip_addr);
                                printf("\n");
-                               memcpy(&eth_addr,
-                                      arp_h->arp_data.arp_ip.arp_tha, 6);
+                               rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
+                                               &eth_addr);
                                ether_addr_dump("        tha=", &eth_addr);
-                               memcpy(&ip_addr,
-                                      arp_h->arp_data.arp_ip.arp_tip, 4);
+                               ip_addr = arp_h->arp_data.arp_tip;
                                ipv4_addr_dump(" tip=", ip_addr);
                                printf("\n");
                        }
-                       if (arp_op != ARP_OP_REQUEST) {
+                       if (arp_op != RTE_ARP_OP_REQUEST) {
                                rte_pktmbuf_free(pkt);
                                continue;
                        }
@@ -404,28 +393,28 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
                         */
 
                        /* Use source MAC address as destination MAC address. */
-                       ether_addr_copy(&eth_h->s_addr, &eth_h->d_addr);
+                       rte_ether_addr_copy(&eth_h->s_addr, &eth_h->d_addr);
                        /* Set source MAC address with MAC address of TX port */
-                       ether_addr_copy(&ports[fs->tx_port].eth_addr,
+                       rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
                                        &eth_h->s_addr);
 
-                       arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
-                       memcpy(&eth_addr, arp_h->arp_data.arp_ip.arp_tha, 6);
-                       memcpy(arp_h->arp_data.arp_ip.arp_tha,
-                              arp_h->arp_data.arp_ip.arp_sha, 6);
-                       memcpy(arp_h->arp_data.arp_ip.arp_sha,
-                              &eth_h->s_addr, 6);
+                       arp_h->arp_opcode = rte_cpu_to_be_16(RTE_ARP_OP_REPLY);
+                       rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
+                                       &eth_addr);
+                       rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
+                                       &arp_h->arp_data.arp_tha);
+                       rte_ether_addr_copy(&eth_h->s_addr,
+                                       &arp_h->arp_data.arp_sha);
 
                        /* Swap IP addresses in ARP payload */
-                       memcpy(&ip_addr, arp_h->arp_data.arp_ip.arp_sip, 4);
-                       memcpy(arp_h->arp_data.arp_ip.arp_sip,
-                              arp_h->arp_data.arp_ip.arp_tip, 4);
-                       memcpy(arp_h->arp_data.arp_ip.arp_tip, &ip_addr, 4);
+                       ip_addr = arp_h->arp_data.arp_sip;
+                       arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip;
+                       arp_h->arp_data.arp_tip = ip_addr;
                        pkts_burst[nb_replies++] = pkt;
                        continue;
                }
 
-               if (eth_type != ETHER_TYPE_IPv4) {
+               if (eth_type != RTE_ETHER_TYPE_IPv4) {
                        rte_pktmbuf_free(pkt);
                        continue;
                }
@@ -441,10 +430,10 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
                /*
                 * Check if packet is a ICMP echo request.
                 */
-               icmp_h = (struct icmp_hdr *) ((char *)ip_h +
+               icmp_h = (struct rte_icmp_hdr *) ((char *)ip_h +
                                              sizeof(struct ipv4_hdr));
                if (! ((ip_h->next_proto_id == IPPROTO_ICMP) &&
-                      (icmp_h->icmp_type == IP_ICMP_ECHO_REQUEST) &&
+                      (icmp_h->icmp_type == RTE_IP_ICMP_ECHO_REQUEST) &&
                       (icmp_h->icmp_code == 0))) {
                        rte_pktmbuf_free(pkt);
                        continue;
@@ -457,19 +446,47 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
                /*
                 * Prepare ICMP echo reply to be sent back.
                 * - switch ethernet source and destinations addresses,
-                * - switch IPv4 source and destinations addresses,
-                * - set IP_ICMP_ECHO_REPLY in ICMP header.
-                * No need to re-compute the IP header checksum.
-                * Reset ICMP checksum.
+                * - use the request IP source address as the reply IP
+                *    destination address,
+                * - if the request IP destination address is a multicast
+                *   address:
+                *     - choose a reply IP source address different from the
+                *       request IP source address,
+                *     - re-compute the IP header checksum.
+                *   Otherwise:
+                *     - switch the request IP source and destination
+                *       addresses in the reply IP header,
+                *     - keep the IP header checksum unchanged.
+                * - set RTE_IP_ICMP_ECHO_REPLY in ICMP header.
+                * ICMP checksum is computed by assuming it is valid in the
+                * echo request and not verified.
                 */
-               ether_addr_copy(&eth_h->s_addr, &eth_addr);
-               ether_addr_copy(&eth_h->d_addr, &eth_h->s_addr);
-               ether_addr_copy(&eth_addr, &eth_h->d_addr);
+               rte_ether_addr_copy(&eth_h->s_addr, &eth_addr);
+               rte_ether_addr_copy(&eth_h->d_addr, &eth_h->s_addr);
+               rte_ether_addr_copy(&eth_addr, &eth_h->d_addr);
                ip_addr = ip_h->src_addr;
-               ip_h->src_addr = ip_h->dst_addr;
-               ip_h->dst_addr = ip_addr;
-               icmp_h->icmp_type = IP_ICMP_ECHO_REPLY;
-               icmp_h->icmp_cksum = 0;
+               if (is_multicast_ipv4_addr(ip_h->dst_addr)) {
+                       uint32_t ip_src;
+
+                       ip_src = rte_be_to_cpu_32(ip_addr);
+                       if ((ip_src & 0x00000003) == 1)
+                               ip_src = (ip_src & 0xFFFFFFFC) | 0x00000002;
+                       else
+                               ip_src = (ip_src & 0xFFFFFFFC) | 0x00000001;
+                       ip_h->src_addr = rte_cpu_to_be_32(ip_src);
+                       ip_h->dst_addr = ip_addr;
+                       ip_h->hdr_checksum = ipv4_hdr_cksum(ip_h);
+               } else {
+                       ip_h->src_addr = ip_h->dst_addr;
+                       ip_h->dst_addr = ip_addr;
+               }
+               icmp_h->icmp_type = RTE_IP_ICMP_ECHO_REPLY;
+               cksum = ~icmp_h->icmp_cksum & 0xffff;
+               cksum += ~htons(RTE_IP_ICMP_ECHO_REQUEST << 8) & 0xffff;
+               cksum += htons(RTE_IP_ICMP_ECHO_REPLY << 8);
+               cksum = (cksum & 0xffff) + (cksum >> 16);
+               cksum = (cksum & 0xffff) + (cksum >> 16);
+               icmp_h->icmp_cksum = ~cksum;
                pkts_burst[nb_replies++] = pkt;
        }
 
@@ -477,6 +494,20 @@ reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
        if (nb_replies > 0) {
                nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst,
                                         nb_replies);
+               /*
+                * Retry if necessary
+                */
+               if (unlikely(nb_tx < nb_replies) && fs->retry_enabled) {
+                       retry = 0;
+                       while (nb_tx < nb_replies &&
+                                       retry++ < burst_tx_retry_num) {
+                               rte_delay_us(burst_tx_delay_time);
+                               nb_tx += rte_eth_tx_burst(fs->tx_port,
+                                               fs->tx_queue,
+                                               &pkts_burst[nb_tx],
+                                               nb_replies - nb_tx);
+                       }
+               }
                fs->tx_packets += nb_tx;
 #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
                fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;