xref: /dpdk/app/test-pmd/icmpecho.c (revision f9e1d67f237a00cf94feb4413e3d978fdd632052)
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=", &eth_h->src_addr);
29304d43857SDmitry Kozlyuk 			ether_addr_dump(" dst=", &eth_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 						&eth_addr);
337168dfa61SIvan Boule 				ether_addr_dump("        sha=", &eth_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 						&eth_addr);
343168dfa61SIvan Boule 				ether_addr_dump("        tha=", &eth_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(&eth_h->src_addr, &eth_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 					&eth_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 					&eth_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(&eth_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(&eth_h->src_addr, &eth_addr);
42704d43857SDmitry Kozlyuk 		rte_ether_addr_copy(&eth_h->dst_addr, &eth_h->src_addr);
42804d43857SDmitry Kozlyuk 		rte_ether_addr_copy(&eth_addr, &eth_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