17faa7292SOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause 27faa7292SOlivier Matz * Copyright(c) 2013 6WIND S.A. 3168dfa61SIvan Boule */ 4168dfa61SIvan Boule 5168dfa61SIvan Boule #include <stdarg.h> 6168dfa61SIvan Boule #include <string.h> 7168dfa61SIvan Boule #include <stdio.h> 8168dfa61SIvan Boule #include <errno.h> 9168dfa61SIvan Boule #include <stdint.h> 10168dfa61SIvan Boule #include <unistd.h> 11168dfa61SIvan Boule #include <inttypes.h> 12168dfa61SIvan Boule 13168dfa61SIvan Boule #include <sys/queue.h> 14168dfa61SIvan Boule #include <sys/stat.h> 15168dfa61SIvan Boule 16168dfa61SIvan Boule #include <rte_common.h> 17168dfa61SIvan Boule #include <rte_byteorder.h> 18168dfa61SIvan Boule #include <rte_log.h> 19168dfa61SIvan Boule #include <rte_debug.h> 20168dfa61SIvan Boule #include <rte_cycles.h> 21168dfa61SIvan Boule #include <rte_per_lcore.h> 22168dfa61SIvan Boule #include <rte_lcore.h> 23168dfa61SIvan Boule #include <rte_branch_prediction.h> 24168dfa61SIvan Boule #include <rte_memory.h> 25168dfa61SIvan Boule #include <rte_mempool.h> 26168dfa61SIvan Boule #include <rte_mbuf.h> 27168dfa61SIvan Boule #include <rte_ether.h> 28168dfa61SIvan Boule #include <rte_ethdev.h> 29168dfa61SIvan Boule #include <rte_arp.h> 30168dfa61SIvan Boule #include <rte_ip.h> 31168dfa61SIvan Boule #include <rte_icmp.h> 32168dfa61SIvan Boule #include <rte_string_fns.h> 33938a184aSAdrien Mazarguil #include <rte_flow.h> 34168dfa61SIvan Boule 35168dfa61SIvan Boule #include "testpmd.h" 36168dfa61SIvan Boule 37168dfa61SIvan Boule static const char * 38168dfa61SIvan Boule arp_op_name(uint16_t arp_op) 39168dfa61SIvan Boule { 40168dfa61SIvan Boule switch (arp_op) { 41e482e0faSOlivier Matz case RTE_ARP_OP_REQUEST: 42168dfa61SIvan Boule return "ARP Request"; 43e482e0faSOlivier Matz case RTE_ARP_OP_REPLY: 44168dfa61SIvan Boule return "ARP Reply"; 45e482e0faSOlivier Matz case RTE_ARP_OP_REVREQUEST: 46168dfa61SIvan Boule return "Reverse ARP Request"; 47e482e0faSOlivier Matz case RTE_ARP_OP_REVREPLY: 48168dfa61SIvan Boule return "Reverse ARP Reply"; 49e482e0faSOlivier Matz case RTE_ARP_OP_INVREQUEST: 50168dfa61SIvan Boule return "Peer Identify Request"; 51e482e0faSOlivier Matz case RTE_ARP_OP_INVREPLY: 52168dfa61SIvan Boule return "Peer Identify Reply"; 53168dfa61SIvan Boule default: 54168dfa61SIvan Boule break; 55168dfa61SIvan Boule } 564a6672c2SStephen Hemminger return "Unknown ARP op"; 57168dfa61SIvan Boule } 58168dfa61SIvan Boule 59168dfa61SIvan Boule static const char * 60257dcd86SBruce Richardson ip_proto_name(uint16_t ip_proto) 61168dfa61SIvan Boule { 62168dfa61SIvan Boule static const char * ip_proto_names[] = { 63168dfa61SIvan Boule "IP6HOPOPTS", /**< IP6 hop-by-hop options */ 64168dfa61SIvan Boule "ICMP", /**< control message protocol */ 65168dfa61SIvan Boule "IGMP", /**< group mgmt protocol */ 66168dfa61SIvan Boule "GGP", /**< gateway^2 (deprecated) */ 67168dfa61SIvan Boule "IPv4", /**< IPv4 encapsulation */ 68168dfa61SIvan Boule 69168dfa61SIvan Boule "UNASSIGNED", 70168dfa61SIvan Boule "TCP", /**< transport control protocol */ 71168dfa61SIvan Boule "ST", /**< Stream protocol II */ 72168dfa61SIvan Boule "EGP", /**< exterior gateway protocol */ 73168dfa61SIvan Boule "PIGP", /**< private interior gateway */ 74168dfa61SIvan Boule 75168dfa61SIvan Boule "RCC_MON", /**< BBN RCC Monitoring */ 76168dfa61SIvan Boule "NVPII", /**< network voice protocol*/ 77168dfa61SIvan Boule "PUP", /**< pup */ 78168dfa61SIvan Boule "ARGUS", /**< Argus */ 79168dfa61SIvan Boule "EMCON", /**< EMCON */ 80168dfa61SIvan Boule 81168dfa61SIvan Boule "XNET", /**< Cross Net Debugger */ 82168dfa61SIvan Boule "CHAOS", /**< Chaos*/ 83168dfa61SIvan Boule "UDP", /**< user datagram protocol */ 84168dfa61SIvan Boule "MUX", /**< Multiplexing */ 85168dfa61SIvan Boule "DCN_MEAS", /**< DCN Measurement Subsystems */ 86168dfa61SIvan Boule 87168dfa61SIvan Boule "HMP", /**< Host Monitoring */ 88168dfa61SIvan Boule "PRM", /**< Packet Radio Measurement */ 89168dfa61SIvan Boule "XNS_IDP", /**< xns idp */ 90168dfa61SIvan Boule "TRUNK1", /**< Trunk-1 */ 91168dfa61SIvan Boule "TRUNK2", /**< Trunk-2 */ 92168dfa61SIvan Boule 93168dfa61SIvan Boule "LEAF1", /**< Leaf-1 */ 94168dfa61SIvan Boule "LEAF2", /**< Leaf-2 */ 95168dfa61SIvan Boule "RDP", /**< Reliable Data */ 96168dfa61SIvan Boule "IRTP", /**< Reliable Transaction */ 97168dfa61SIvan Boule "TP4", /**< tp-4 w/ class negotiation */ 98168dfa61SIvan Boule 99168dfa61SIvan Boule "BLT", /**< Bulk Data Transfer */ 100168dfa61SIvan Boule "NSP", /**< Network Services */ 101168dfa61SIvan Boule "INP", /**< Merit Internodal */ 102168dfa61SIvan Boule "SEP", /**< Sequential Exchange */ 103168dfa61SIvan Boule "3PC", /**< Third Party Connect */ 104168dfa61SIvan Boule 105168dfa61SIvan Boule "IDPR", /**< InterDomain Policy Routing */ 106168dfa61SIvan Boule "XTP", /**< XTP */ 107168dfa61SIvan Boule "DDP", /**< Datagram Delivery */ 108168dfa61SIvan Boule "CMTP", /**< Control Message Transport */ 109168dfa61SIvan Boule "TPXX", /**< TP++ Transport */ 110168dfa61SIvan Boule 111168dfa61SIvan Boule "ILTP", /**< IL transport protocol */ 112168dfa61SIvan Boule "IPv6_HDR", /**< IP6 header */ 113168dfa61SIvan Boule "SDRP", /**< Source Demand Routing */ 114168dfa61SIvan Boule "IPv6_RTG", /**< IP6 routing header */ 115168dfa61SIvan Boule "IPv6_FRAG", /**< IP6 fragmentation header */ 116168dfa61SIvan Boule 117168dfa61SIvan Boule "IDRP", /**< InterDomain Routing*/ 118168dfa61SIvan Boule "RSVP", /**< resource reservation */ 119168dfa61SIvan Boule "GRE", /**< General Routing Encap. */ 120168dfa61SIvan Boule "MHRP", /**< Mobile Host Routing */ 121168dfa61SIvan Boule "BHA", /**< BHA */ 122168dfa61SIvan Boule 123168dfa61SIvan Boule "ESP", /**< IP6 Encap Sec. Payload */ 124168dfa61SIvan Boule "AH", /**< IP6 Auth Header */ 125168dfa61SIvan Boule "INLSP", /**< Integ. Net Layer Security */ 126168dfa61SIvan Boule "SWIPE", /**< IP with encryption */ 127168dfa61SIvan Boule "NHRP", /**< Next Hop Resolution */ 128168dfa61SIvan Boule 129168dfa61SIvan Boule "UNASSIGNED", 130168dfa61SIvan Boule "UNASSIGNED", 131168dfa61SIvan Boule "UNASSIGNED", 132168dfa61SIvan Boule "ICMPv6", /**< ICMP6 */ 133168dfa61SIvan Boule "IPv6NONEXT", /**< IP6 no next header */ 134168dfa61SIvan Boule 135168dfa61SIvan Boule "Ipv6DSTOPTS",/**< IP6 destination option */ 136168dfa61SIvan Boule "AHIP", /**< any host internal protocol */ 137168dfa61SIvan Boule "CFTP", /**< CFTP */ 138168dfa61SIvan Boule "HELLO", /**< "hello" routing protocol */ 139168dfa61SIvan Boule "SATEXPAK", /**< SATNET/Backroom EXPAK */ 140168dfa61SIvan Boule 141168dfa61SIvan Boule "KRYPTOLAN", /**< Kryptolan */ 142168dfa61SIvan Boule "RVD", /**< Remote Virtual Disk */ 143168dfa61SIvan Boule "IPPC", /**< Pluribus Packet Core */ 144168dfa61SIvan Boule "ADFS", /**< Any distributed FS */ 145168dfa61SIvan Boule "SATMON", /**< Satnet Monitoring */ 146168dfa61SIvan Boule 147168dfa61SIvan Boule "VISA", /**< VISA Protocol */ 148168dfa61SIvan Boule "IPCV", /**< Packet Core Utility */ 149168dfa61SIvan Boule "CPNX", /**< Comp. Prot. Net. Executive */ 150168dfa61SIvan Boule "CPHB", /**< Comp. Prot. HeartBeat */ 151168dfa61SIvan Boule "WSN", /**< Wang Span Network */ 152168dfa61SIvan Boule 153168dfa61SIvan Boule "PVP", /**< Packet Video Protocol */ 154168dfa61SIvan Boule "BRSATMON", /**< BackRoom SATNET Monitoring */ 155168dfa61SIvan Boule "ND", /**< Sun net disk proto (temp.) */ 156168dfa61SIvan Boule "WBMON", /**< WIDEBAND Monitoring */ 157168dfa61SIvan Boule "WBEXPAK", /**< WIDEBAND EXPAK */ 158168dfa61SIvan Boule 159168dfa61SIvan Boule "EON", /**< ISO cnlp */ 160168dfa61SIvan Boule "VMTP", /**< VMTP */ 161168dfa61SIvan Boule "SVMTP", /**< Secure VMTP */ 162168dfa61SIvan Boule "VINES", /**< Banyon VINES */ 163168dfa61SIvan Boule "TTP", /**< TTP */ 164168dfa61SIvan Boule 165168dfa61SIvan Boule "IGP", /**< NSFNET-IGP */ 166168dfa61SIvan Boule "DGP", /**< dissimilar gateway prot. */ 167168dfa61SIvan Boule "TCF", /**< TCF */ 168168dfa61SIvan Boule "IGRP", /**< Cisco/GXS IGRP */ 169168dfa61SIvan Boule "OSPFIGP", /**< OSPFIGP */ 170168dfa61SIvan Boule 171168dfa61SIvan Boule "SRPC", /**< Strite RPC protocol */ 172547d946cSNirmoy Das "LARP", /**< Locus Address Resolution */ 173168dfa61SIvan Boule "MTP", /**< Multicast Transport */ 174168dfa61SIvan Boule "AX25", /**< AX.25 Frames */ 175168dfa61SIvan Boule "4IN4", /**< IP encapsulated in IP */ 176168dfa61SIvan Boule 177168dfa61SIvan Boule "MICP", /**< Mobile Int.ing control */ 178168dfa61SIvan Boule "SCCSP", /**< Semaphore Comm. security */ 179168dfa61SIvan Boule "ETHERIP", /**< Ethernet IP encapsulation */ 180168dfa61SIvan Boule "ENCAP", /**< encapsulation header */ 181168dfa61SIvan Boule "AES", /**< any private encr. scheme */ 182168dfa61SIvan Boule 183168dfa61SIvan Boule "GMTP", /**< GMTP */ 184168dfa61SIvan Boule "IPCOMP", /**< payload compression (IPComp) */ 185168dfa61SIvan Boule "UNASSIGNED", 186168dfa61SIvan Boule "UNASSIGNED", 187168dfa61SIvan Boule "PIM", /**< Protocol Independent Mcast */ 188168dfa61SIvan Boule }; 189168dfa61SIvan Boule 19071bdd8a1SPavan Nikhilesh if (ip_proto < RTE_DIM(ip_proto_names)) 191168dfa61SIvan Boule return ip_proto_names[ip_proto]; 192168dfa61SIvan Boule switch (ip_proto) { 193d07180f2SThomas Monjalon #ifdef IPPROTO_PGM 194168dfa61SIvan Boule case IPPROTO_PGM: /**< PGM */ 195168dfa61SIvan Boule return "PGM"; 196d07180f2SThomas Monjalon #endif 197168dfa61SIvan Boule case IPPROTO_SCTP: /**< Stream Control Transport Protocol */ 198168dfa61SIvan Boule return "SCTP"; 199d07180f2SThomas Monjalon #ifdef IPPROTO_DIVERT 200168dfa61SIvan Boule case IPPROTO_DIVERT: /**< divert pseudo-protocol */ 201168dfa61SIvan Boule return "DIVERT"; 202d07180f2SThomas Monjalon #endif 203168dfa61SIvan Boule case IPPROTO_RAW: /**< raw IP packet */ 204168dfa61SIvan Boule return "RAW"; 205168dfa61SIvan Boule default: 206168dfa61SIvan Boule break; 207168dfa61SIvan Boule } 208168dfa61SIvan Boule return "UNASSIGNED"; 209168dfa61SIvan Boule } 210168dfa61SIvan Boule 211168dfa61SIvan Boule static void 212168dfa61SIvan Boule ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf) 213168dfa61SIvan Boule { 214168dfa61SIvan Boule uint32_t ipv4_addr; 215168dfa61SIvan Boule 216168dfa61SIvan Boule ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr); 217168dfa61SIvan Boule sprintf(buf, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF, 218168dfa61SIvan Boule (ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF, 219168dfa61SIvan Boule ipv4_addr & 0xFF); 220168dfa61SIvan Boule } 221168dfa61SIvan Boule 222168dfa61SIvan Boule static void 2236d13ea8eSOlivier Matz ether_addr_dump(const char *what, const struct rte_ether_addr *ea) 224168dfa61SIvan Boule { 22535b2d13fSOlivier Matz char buf[RTE_ETHER_ADDR_FMT_SIZE]; 226168dfa61SIvan Boule 22735b2d13fSOlivier Matz rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, ea); 228168dfa61SIvan Boule if (what) 229168dfa61SIvan Boule printf("%s", what); 230168dfa61SIvan Boule printf("%s", buf); 231168dfa61SIvan Boule } 232168dfa61SIvan Boule 233168dfa61SIvan Boule static void 234168dfa61SIvan Boule ipv4_addr_dump(const char *what, uint32_t be_ipv4_addr) 235168dfa61SIvan Boule { 236168dfa61SIvan Boule char buf[16]; 237168dfa61SIvan Boule 238168dfa61SIvan Boule ipv4_addr_to_dot(be_ipv4_addr, buf); 239168dfa61SIvan Boule if (what) 240168dfa61SIvan Boule printf("%s", what); 241168dfa61SIvan Boule printf("%s", buf); 242168dfa61SIvan Boule } 243168dfa61SIvan Boule 2448443ce81SIvan Boule #define is_multicast_ipv4_addr(ipv4_addr) \ 2458443ce81SIvan Boule (((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0) 2468443ce81SIvan Boule 247168dfa61SIvan Boule /* 248547d946cSNirmoy Das * Receive a burst of packets, lookup for ICMP echo requests, and, if any, 249168dfa61SIvan Boule * send back ICMP echo replies. 250168dfa61SIvan Boule */ 25106c20561SDavid Marchand static bool 252168dfa61SIvan Boule reply_to_icmp_echo_rqsts(struct fwd_stream *fs) 253168dfa61SIvan Boule { 254168dfa61SIvan Boule struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 255168dfa61SIvan Boule struct rte_mbuf *pkt; 2566d13ea8eSOlivier Matz struct rte_ether_hdr *eth_h; 2576d13ea8eSOlivier Matz struct rte_vlan_hdr *vlan_h; 258f2745bfeSOlivier Matz struct rte_arp_hdr *arp_h; 259a7c528e5SOlivier Matz struct rte_ipv4_hdr *ip_h; 2606d961b06SOlivier Matz struct rte_icmp_hdr *icmp_h; 2616d13ea8eSOlivier Matz struct rte_ether_addr eth_addr; 262168dfa61SIvan Boule uint32_t ip_addr; 263168dfa61SIvan Boule uint16_t nb_rx; 264168dfa61SIvan Boule uint16_t nb_replies; 265168dfa61SIvan Boule uint16_t eth_type; 266168dfa61SIvan Boule uint16_t vlan_id; 267168dfa61SIvan Boule uint16_t arp_op; 268168dfa61SIvan Boule uint16_t arp_pro; 269f7719131SAdrien Mazarguil uint32_t cksum; 270168dfa61SIvan Boule uint8_t i; 271168dfa61SIvan Boule int l2_len; 272168dfa61SIvan Boule 273168dfa61SIvan Boule /* 274168dfa61SIvan Boule * First, receive a burst of packets. 275168dfa61SIvan Boule */ 276d3dae396SDavid Marchand nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst); 2777569b8c1SHonnappa Nagarahalli if (unlikely(nb_rx == 0)) 27806c20561SDavid Marchand return false; 2797569b8c1SHonnappa Nagarahalli 280168dfa61SIvan Boule nb_replies = 0; 281168dfa61SIvan Boule for (i = 0; i < nb_rx; i++) { 2827fdb263bSJerin Jacob if (likely(i < nb_rx - 1)) 2837fdb263bSJerin Jacob rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1], 2847fdb263bSJerin Jacob void *)); 285168dfa61SIvan Boule pkt = pkts_burst[i]; 2866d13ea8eSOlivier Matz eth_h = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); 287168dfa61SIvan Boule eth_type = RTE_BE_TO_CPU_16(eth_h->ether_type); 2886d13ea8eSOlivier Matz l2_len = sizeof(struct rte_ether_hdr); 289168dfa61SIvan Boule if (verbose_level > 0) { 290168dfa61SIvan Boule printf("\nPort %d pkt-len=%u nb-segs=%u\n", 291ea672a8bSOlivier Matz fs->rx_port, pkt->pkt_len, pkt->nb_segs); 29204d43857SDmitry Kozlyuk ether_addr_dump(" ETH: src=", ð_h->src_addr); 29304d43857SDmitry Kozlyuk ether_addr_dump(" dst=", ð_h->dst_addr); 294168dfa61SIvan Boule } 29535b2d13fSOlivier Matz if (eth_type == RTE_ETHER_TYPE_VLAN) { 2966d13ea8eSOlivier Matz vlan_h = (struct rte_vlan_hdr *) 2976d13ea8eSOlivier Matz ((char *)eth_h + sizeof(struct rte_ether_hdr)); 2986d13ea8eSOlivier Matz l2_len += sizeof(struct rte_vlan_hdr); 299168dfa61SIvan Boule eth_type = rte_be_to_cpu_16(vlan_h->eth_proto); 300168dfa61SIvan Boule if (verbose_level > 0) { 301168dfa61SIvan Boule vlan_id = rte_be_to_cpu_16(vlan_h->vlan_tci) 302168dfa61SIvan Boule & 0xFFF; 303168dfa61SIvan Boule printf(" [vlan id=%u]", vlan_id); 304168dfa61SIvan Boule } 305168dfa61SIvan Boule } 306168dfa61SIvan Boule if (verbose_level > 0) { 307168dfa61SIvan Boule printf(" type=0x%04x\n", eth_type); 308168dfa61SIvan Boule } 309168dfa61SIvan Boule 310168dfa61SIvan Boule /* Reply to ARP requests */ 31135b2d13fSOlivier Matz if (eth_type == RTE_ETHER_TYPE_ARP) { 312f2745bfeSOlivier Matz arp_h = (struct rte_arp_hdr *) ((char *)eth_h + l2_len); 313f2745bfeSOlivier Matz arp_op = RTE_BE_TO_CPU_16(arp_h->arp_opcode); 314f2745bfeSOlivier Matz arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_protocol); 315168dfa61SIvan Boule if (verbose_level > 0) { 316168dfa61SIvan Boule printf(" ARP: hrd=%d proto=0x%04x hln=%d " 317168dfa61SIvan Boule "pln=%d op=%u (%s)\n", 318f2745bfeSOlivier Matz RTE_BE_TO_CPU_16(arp_h->arp_hardware), 319f2745bfeSOlivier Matz arp_pro, arp_h->arp_hlen, 320f2745bfeSOlivier Matz arp_h->arp_plen, arp_op, 321168dfa61SIvan Boule arp_op_name(arp_op)); 322168dfa61SIvan Boule } 323f2745bfeSOlivier Matz if ((RTE_BE_TO_CPU_16(arp_h->arp_hardware) != 324e482e0faSOlivier Matz RTE_ARP_HRD_ETHER) || 3250c9da755SDavid Marchand (arp_pro != RTE_ETHER_TYPE_IPV4) || 326f2745bfeSOlivier Matz (arp_h->arp_hlen != 6) || 327f2745bfeSOlivier Matz (arp_h->arp_plen != 4) 328168dfa61SIvan Boule ) { 329168dfa61SIvan Boule rte_pktmbuf_free(pkt); 330168dfa61SIvan Boule if (verbose_level > 0) 331168dfa61SIvan Boule printf("\n"); 332168dfa61SIvan Boule continue; 333168dfa61SIvan Boule } 334168dfa61SIvan Boule if (verbose_level > 0) { 335538da7a1SOlivier Matz rte_ether_addr_copy(&arp_h->arp_data.arp_sha, 336538da7a1SOlivier Matz ð_addr); 337168dfa61SIvan Boule ether_addr_dump(" sha=", ð_addr); 33831db4d38SMaciej Gajdzica ip_addr = arp_h->arp_data.arp_sip; 339168dfa61SIvan Boule ipv4_addr_dump(" sip=", ip_addr); 340168dfa61SIvan Boule printf("\n"); 341538da7a1SOlivier Matz rte_ether_addr_copy(&arp_h->arp_data.arp_tha, 342538da7a1SOlivier Matz ð_addr); 343168dfa61SIvan Boule ether_addr_dump(" tha=", ð_addr); 34431db4d38SMaciej Gajdzica ip_addr = arp_h->arp_data.arp_tip; 345168dfa61SIvan Boule ipv4_addr_dump(" tip=", ip_addr); 346168dfa61SIvan Boule printf("\n"); 347168dfa61SIvan Boule } 348e482e0faSOlivier Matz if (arp_op != RTE_ARP_OP_REQUEST) { 349168dfa61SIvan Boule rte_pktmbuf_free(pkt); 350168dfa61SIvan Boule continue; 351168dfa61SIvan Boule } 352168dfa61SIvan Boule 353168dfa61SIvan Boule /* 354168dfa61SIvan Boule * Build ARP reply. 355168dfa61SIvan Boule */ 356168dfa61SIvan Boule 357168dfa61SIvan Boule /* Use source MAC address as destination MAC address. */ 35804d43857SDmitry Kozlyuk rte_ether_addr_copy(ð_h->src_addr, ð_h->dst_addr); 359168dfa61SIvan Boule /* Set source MAC address with MAC address of TX port */ 360538da7a1SOlivier Matz rte_ether_addr_copy(&ports[fs->tx_port].eth_addr, 36104d43857SDmitry Kozlyuk ð_h->src_addr); 362168dfa61SIvan Boule 363e482e0faSOlivier Matz arp_h->arp_opcode = rte_cpu_to_be_16(RTE_ARP_OP_REPLY); 364538da7a1SOlivier Matz rte_ether_addr_copy(&arp_h->arp_data.arp_tha, 365538da7a1SOlivier Matz ð_addr); 366538da7a1SOlivier Matz rte_ether_addr_copy(&arp_h->arp_data.arp_sha, 367538da7a1SOlivier Matz &arp_h->arp_data.arp_tha); 36804d43857SDmitry Kozlyuk rte_ether_addr_copy(ð_h->src_addr, 369538da7a1SOlivier Matz &arp_h->arp_data.arp_sha); 370168dfa61SIvan Boule 371168dfa61SIvan Boule /* Swap IP addresses in ARP payload */ 37231db4d38SMaciej Gajdzica ip_addr = arp_h->arp_data.arp_sip; 37331db4d38SMaciej Gajdzica arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip; 37431db4d38SMaciej Gajdzica arp_h->arp_data.arp_tip = ip_addr; 375168dfa61SIvan Boule pkts_burst[nb_replies++] = pkt; 376168dfa61SIvan Boule continue; 377168dfa61SIvan Boule } 378168dfa61SIvan Boule 3790c9da755SDavid Marchand if (eth_type != RTE_ETHER_TYPE_IPV4) { 380168dfa61SIvan Boule rte_pktmbuf_free(pkt); 381168dfa61SIvan Boule continue; 382168dfa61SIvan Boule } 383a7c528e5SOlivier Matz ip_h = (struct rte_ipv4_hdr *) ((char *)eth_h + l2_len); 384168dfa61SIvan Boule if (verbose_level > 0) { 385168dfa61SIvan Boule ipv4_addr_dump(" IPV4: src=", ip_h->src_addr); 386168dfa61SIvan Boule ipv4_addr_dump(" dst=", ip_h->dst_addr); 387168dfa61SIvan Boule printf(" proto=%d (%s)\n", 388168dfa61SIvan Boule ip_h->next_proto_id, 389168dfa61SIvan Boule ip_proto_name(ip_h->next_proto_id)); 390168dfa61SIvan Boule } 391168dfa61SIvan Boule 392168dfa61SIvan Boule /* 393168dfa61SIvan Boule * Check if packet is a ICMP echo request. 394168dfa61SIvan Boule */ 3956d961b06SOlivier Matz icmp_h = (struct rte_icmp_hdr *) ((char *)ip_h + 396a7c528e5SOlivier Matz sizeof(struct rte_ipv4_hdr)); 397168dfa61SIvan Boule if (! ((ip_h->next_proto_id == IPPROTO_ICMP) && 39887bde5aeSRobin Jarry (icmp_h->icmp_type == RTE_ICMP_TYPE_ECHO_REQUEST) && 399168dfa61SIvan Boule (icmp_h->icmp_code == 0))) { 400168dfa61SIvan Boule rte_pktmbuf_free(pkt); 401168dfa61SIvan Boule continue; 402168dfa61SIvan Boule } 403168dfa61SIvan Boule 404168dfa61SIvan Boule if (verbose_level > 0) 405168dfa61SIvan Boule printf(" ICMP: echo request seq id=%d\n", 406168dfa61SIvan Boule rte_be_to_cpu_16(icmp_h->icmp_seq_nb)); 407168dfa61SIvan Boule 408168dfa61SIvan Boule /* 409168dfa61SIvan Boule * Prepare ICMP echo reply to be sent back. 410168dfa61SIvan Boule * - switch ethernet source and destinations addresses, 4118443ce81SIvan Boule * - use the request IP source address as the reply IP 4128443ce81SIvan Boule * destination address, 4138443ce81SIvan Boule * - if the request IP destination address is a multicast 4148443ce81SIvan Boule * address: 4158443ce81SIvan Boule * - choose a reply IP source address different from the 4168443ce81SIvan Boule * request IP source address, 4178443ce81SIvan Boule * - re-compute the IP header checksum. 4188443ce81SIvan Boule * Otherwise: 4198443ce81SIvan Boule * - switch the request IP source and destination 4208443ce81SIvan Boule * addresses in the reply IP header, 4218443ce81SIvan Boule * - keep the IP header checksum unchanged. 42287bde5aeSRobin Jarry * - set RTE_ICMP_TYPE_ECHO_REPLY in ICMP header. 423f7719131SAdrien Mazarguil * ICMP checksum is computed by assuming it is valid in the 424f7719131SAdrien Mazarguil * echo request and not verified. 425168dfa61SIvan Boule */ 42604d43857SDmitry Kozlyuk rte_ether_addr_copy(ð_h->src_addr, ð_addr); 42704d43857SDmitry Kozlyuk rte_ether_addr_copy(ð_h->dst_addr, ð_h->src_addr); 42804d43857SDmitry Kozlyuk rte_ether_addr_copy(ð_addr, ð_h->dst_addr); 429168dfa61SIvan Boule ip_addr = ip_h->src_addr; 4308443ce81SIvan Boule if (is_multicast_ipv4_addr(ip_h->dst_addr)) { 4318443ce81SIvan Boule uint32_t ip_src; 4328443ce81SIvan Boule 4338443ce81SIvan Boule ip_src = rte_be_to_cpu_32(ip_addr); 4348443ce81SIvan Boule if ((ip_src & 0x00000003) == 1) 4358443ce81SIvan Boule ip_src = (ip_src & 0xFFFFFFFC) | 0x00000002; 4368443ce81SIvan Boule else 4378443ce81SIvan Boule ip_src = (ip_src & 0xFFFFFFFC) | 0x00000001; 4388443ce81SIvan Boule ip_h->src_addr = rte_cpu_to_be_32(ip_src); 4398443ce81SIvan Boule ip_h->dst_addr = ip_addr; 440*f9e1d67fSBruce Richardson ip_h->hdr_checksum = rte_ipv4_cksum_simple(ip_h); 4418443ce81SIvan Boule } else { 442168dfa61SIvan Boule ip_h->src_addr = ip_h->dst_addr; 443168dfa61SIvan Boule ip_h->dst_addr = ip_addr; 4448443ce81SIvan Boule } 44587bde5aeSRobin Jarry icmp_h->icmp_type = RTE_ICMP_TYPE_ECHO_REPLY; 446f7719131SAdrien Mazarguil cksum = ~icmp_h->icmp_cksum & 0xffff; 44787bde5aeSRobin Jarry cksum += ~RTE_BE16(RTE_ICMP_TYPE_ECHO_REQUEST << 8) & 0xffff; 44887bde5aeSRobin Jarry cksum += RTE_BE16(RTE_ICMP_TYPE_ECHO_REPLY << 8); 449f7719131SAdrien Mazarguil cksum = (cksum & 0xffff) + (cksum >> 16); 450f7719131SAdrien Mazarguil cksum = (cksum & 0xffff) + (cksum >> 16); 451f7719131SAdrien Mazarguil icmp_h->icmp_cksum = ~cksum; 452168dfa61SIvan Boule pkts_burst[nb_replies++] = pkt; 453168dfa61SIvan Boule } 454168dfa61SIvan Boule 455168dfa61SIvan Boule /* Send back ICMP echo replies, if any. */ 456655131ccSDavid Marchand if (nb_replies > 0) 457655131ccSDavid Marchand common_fwd_stream_transmit(fs, pkts_burst, nb_replies); 458168dfa61SIvan Boule 45906c20561SDavid Marchand return true; 460168dfa61SIvan Boule } 461168dfa61SIvan Boule 462168dfa61SIvan Boule struct fwd_engine icmp_echo_engine = { 463168dfa61SIvan Boule .fwd_mode_name = "icmpecho", 464180ba023SDavid Marchand .stream_init = common_fwd_stream_init, 465168dfa61SIvan Boule .packet_fwd = reply_to_icmp_echo_rqsts, 466168dfa61SIvan Boule }; 467