xref: /dpdk/app/test-pmd/icmpecho.c (revision f9e1d67f237a00cf94feb4413e3d978fdd632052)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2013 6WIND S.A.
3  */
4 
5 #include <stdarg.h>
6 #include <string.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_per_lcore.h>
22 #include <rte_lcore.h>
23 #include <rte_branch_prediction.h>
24 #include <rte_memory.h>
25 #include <rte_mempool.h>
26 #include <rte_mbuf.h>
27 #include <rte_ether.h>
28 #include <rte_ethdev.h>
29 #include <rte_arp.h>
30 #include <rte_ip.h>
31 #include <rte_icmp.h>
32 #include <rte_string_fns.h>
33 #include <rte_flow.h>
34 
35 #include "testpmd.h"
36 
37 static const char *
38 arp_op_name(uint16_t arp_op)
39 {
40 	switch (arp_op) {
41 	case RTE_ARP_OP_REQUEST:
42 		return "ARP Request";
43 	case RTE_ARP_OP_REPLY:
44 		return "ARP Reply";
45 	case RTE_ARP_OP_REVREQUEST:
46 		return "Reverse ARP Request";
47 	case RTE_ARP_OP_REVREPLY:
48 		return "Reverse ARP Reply";
49 	case RTE_ARP_OP_INVREQUEST:
50 		return "Peer Identify Request";
51 	case RTE_ARP_OP_INVREPLY:
52 		return "Peer Identify Reply";
53 	default:
54 		break;
55 	}
56 	return "Unknown ARP op";
57 }
58 
59 static const char *
60 ip_proto_name(uint16_t ip_proto)
61 {
62 	static const char * ip_proto_names[] = {
63 		"IP6HOPOPTS", /**< IP6 hop-by-hop options */
64 		"ICMP",       /**< control message protocol */
65 		"IGMP",       /**< group mgmt protocol */
66 		"GGP",        /**< gateway^2 (deprecated) */
67 		"IPv4",       /**< IPv4 encapsulation */
68 
69 		"UNASSIGNED",
70 		"TCP",        /**< transport control protocol */
71 		"ST",         /**< Stream protocol II */
72 		"EGP",        /**< exterior gateway protocol */
73 		"PIGP",       /**< private interior gateway */
74 
75 		"RCC_MON",    /**< BBN RCC Monitoring */
76 		"NVPII",      /**< network voice protocol*/
77 		"PUP",        /**< pup */
78 		"ARGUS",      /**< Argus */
79 		"EMCON",      /**< EMCON */
80 
81 		"XNET",       /**< Cross Net Debugger */
82 		"CHAOS",      /**< Chaos*/
83 		"UDP",        /**< user datagram protocol */
84 		"MUX",        /**< Multiplexing */
85 		"DCN_MEAS",   /**< DCN Measurement Subsystems */
86 
87 		"HMP",        /**< Host Monitoring */
88 		"PRM",        /**< Packet Radio Measurement */
89 		"XNS_IDP",    /**< xns idp */
90 		"TRUNK1",     /**< Trunk-1 */
91 		"TRUNK2",     /**< Trunk-2 */
92 
93 		"LEAF1",      /**< Leaf-1 */
94 		"LEAF2",      /**< Leaf-2 */
95 		"RDP",        /**< Reliable Data */
96 		"IRTP",       /**< Reliable Transaction */
97 		"TP4",        /**< tp-4 w/ class negotiation */
98 
99 		"BLT",        /**< Bulk Data Transfer */
100 		"NSP",        /**< Network Services */
101 		"INP",        /**< Merit Internodal */
102 		"SEP",        /**< Sequential Exchange */
103 		"3PC",        /**< Third Party Connect */
104 
105 		"IDPR",       /**< InterDomain Policy Routing */
106 		"XTP",        /**< XTP */
107 		"DDP",        /**< Datagram Delivery */
108 		"CMTP",       /**< Control Message Transport */
109 		"TPXX",       /**< TP++ Transport */
110 
111 		"ILTP",       /**< IL transport protocol */
112 		"IPv6_HDR",   /**< IP6 header */
113 		"SDRP",       /**< Source Demand Routing */
114 		"IPv6_RTG",   /**< IP6 routing header */
115 		"IPv6_FRAG",  /**< IP6 fragmentation header */
116 
117 		"IDRP",       /**< InterDomain Routing*/
118 		"RSVP",       /**< resource reservation */
119 		"GRE",        /**< General Routing Encap. */
120 		"MHRP",       /**< Mobile Host Routing */
121 		"BHA",        /**< BHA */
122 
123 		"ESP",        /**< IP6 Encap Sec. Payload */
124 		"AH",         /**< IP6 Auth Header */
125 		"INLSP",      /**< Integ. Net Layer Security */
126 		"SWIPE",      /**< IP with encryption */
127 		"NHRP",       /**< Next Hop Resolution */
128 
129 		"UNASSIGNED",
130 		"UNASSIGNED",
131 		"UNASSIGNED",
132 		"ICMPv6",     /**< ICMP6 */
133 		"IPv6NONEXT", /**< IP6 no next header */
134 
135 		"Ipv6DSTOPTS",/**< IP6 destination option */
136 		"AHIP",       /**< any host internal protocol */
137 		"CFTP",       /**< CFTP */
138 		"HELLO",      /**< "hello" routing protocol */
139 		"SATEXPAK",   /**< SATNET/Backroom EXPAK */
140 
141 		"KRYPTOLAN",  /**< Kryptolan */
142 		"RVD",        /**< Remote Virtual Disk */
143 		"IPPC",       /**< Pluribus Packet Core */
144 		"ADFS",       /**< Any distributed FS */
145 		"SATMON",     /**< Satnet Monitoring */
146 
147 		"VISA",       /**< VISA Protocol */
148 		"IPCV",       /**< Packet Core Utility */
149 		"CPNX",       /**< Comp. Prot. Net. Executive */
150 		"CPHB",       /**< Comp. Prot. HeartBeat */
151 		"WSN",        /**< Wang Span Network */
152 
153 		"PVP",        /**< Packet Video Protocol */
154 		"BRSATMON",   /**< BackRoom SATNET Monitoring */
155 		"ND",         /**< Sun net disk proto (temp.) */
156 		"WBMON",      /**< WIDEBAND Monitoring */
157 		"WBEXPAK",    /**< WIDEBAND EXPAK */
158 
159 		"EON",        /**< ISO cnlp */
160 		"VMTP",       /**< VMTP */
161 		"SVMTP",      /**< Secure VMTP */
162 		"VINES",      /**< Banyon VINES */
163 		"TTP",        /**< TTP */
164 
165 		"IGP",        /**< NSFNET-IGP */
166 		"DGP",        /**< dissimilar gateway prot. */
167 		"TCF",        /**< TCF */
168 		"IGRP",       /**< Cisco/GXS IGRP */
169 		"OSPFIGP",    /**< OSPFIGP */
170 
171 		"SRPC",       /**< Strite RPC protocol */
172 		"LARP",       /**< Locus Address Resolution */
173 		"MTP",        /**< Multicast Transport */
174 		"AX25",       /**< AX.25 Frames */
175 		"4IN4",       /**< IP encapsulated in IP */
176 
177 		"MICP",       /**< Mobile Int.ing control */
178 		"SCCSP",      /**< Semaphore Comm. security */
179 		"ETHERIP",    /**< Ethernet IP encapsulation */
180 		"ENCAP",      /**< encapsulation header */
181 		"AES",        /**< any private encr. scheme */
182 
183 		"GMTP",       /**< GMTP */
184 		"IPCOMP",     /**< payload compression (IPComp) */
185 		"UNASSIGNED",
186 		"UNASSIGNED",
187 		"PIM",        /**< Protocol Independent Mcast */
188 	};
189 
190 	if (ip_proto < RTE_DIM(ip_proto_names))
191 		return ip_proto_names[ip_proto];
192 	switch (ip_proto) {
193 #ifdef IPPROTO_PGM
194 	case IPPROTO_PGM:  /**< PGM */
195 		return "PGM";
196 #endif
197 	case IPPROTO_SCTP:  /**< Stream Control Transport Protocol */
198 		return "SCTP";
199 #ifdef IPPROTO_DIVERT
200 	case IPPROTO_DIVERT: /**< divert pseudo-protocol */
201 		return "DIVERT";
202 #endif
203 	case IPPROTO_RAW: /**< raw IP packet */
204 		return "RAW";
205 	default:
206 		break;
207 	}
208 	return "UNASSIGNED";
209 }
210 
211 static void
212 ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf)
213 {
214 	uint32_t ipv4_addr;
215 
216 	ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr);
217 	sprintf(buf, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF,
218 		(ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF,
219 		ipv4_addr & 0xFF);
220 }
221 
222 static void
223 ether_addr_dump(const char *what, const struct rte_ether_addr *ea)
224 {
225 	char buf[RTE_ETHER_ADDR_FMT_SIZE];
226 
227 	rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, ea);
228 	if (what)
229 		printf("%s", what);
230 	printf("%s", buf);
231 }
232 
233 static void
234 ipv4_addr_dump(const char *what, uint32_t be_ipv4_addr)
235 {
236 	char buf[16];
237 
238 	ipv4_addr_to_dot(be_ipv4_addr, buf);
239 	if (what)
240 		printf("%s", what);
241 	printf("%s", buf);
242 }
243 
244 #define is_multicast_ipv4_addr(ipv4_addr) \
245 	(((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0)
246 
247 /*
248  * Receive a burst of packets, lookup for ICMP echo requests, and, if any,
249  * send back ICMP echo replies.
250  */
251 static bool
252 reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
253 {
254 	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
255 	struct rte_mbuf *pkt;
256 	struct rte_ether_hdr *eth_h;
257 	struct rte_vlan_hdr *vlan_h;
258 	struct rte_arp_hdr  *arp_h;
259 	struct rte_ipv4_hdr *ip_h;
260 	struct rte_icmp_hdr *icmp_h;
261 	struct rte_ether_addr eth_addr;
262 	uint32_t ip_addr;
263 	uint16_t nb_rx;
264 	uint16_t nb_replies;
265 	uint16_t eth_type;
266 	uint16_t vlan_id;
267 	uint16_t arp_op;
268 	uint16_t arp_pro;
269 	uint32_t cksum;
270 	uint8_t  i;
271 	int l2_len;
272 
273 	/*
274 	 * First, receive a burst of packets.
275 	 */
276 	nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
277 	if (unlikely(nb_rx == 0))
278 		return false;
279 
280 	nb_replies = 0;
281 	for (i = 0; i < nb_rx; i++) {
282 		if (likely(i < nb_rx - 1))
283 			rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
284 						       void *));
285 		pkt = pkts_burst[i];
286 		eth_h = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
287 		eth_type = RTE_BE_TO_CPU_16(eth_h->ether_type);
288 		l2_len = sizeof(struct rte_ether_hdr);
289 		if (verbose_level > 0) {
290 			printf("\nPort %d pkt-len=%u nb-segs=%u\n",
291 			       fs->rx_port, pkt->pkt_len, pkt->nb_segs);
292 			ether_addr_dump("  ETH:  src=", &eth_h->src_addr);
293 			ether_addr_dump(" dst=", &eth_h->dst_addr);
294 		}
295 		if (eth_type == RTE_ETHER_TYPE_VLAN) {
296 			vlan_h = (struct rte_vlan_hdr *)
297 				((char *)eth_h + sizeof(struct rte_ether_hdr));
298 			l2_len  += sizeof(struct rte_vlan_hdr);
299 			eth_type = rte_be_to_cpu_16(vlan_h->eth_proto);
300 			if (verbose_level > 0) {
301 				vlan_id = rte_be_to_cpu_16(vlan_h->vlan_tci)
302 					& 0xFFF;
303 				printf(" [vlan id=%u]", vlan_id);
304 			}
305 		}
306 		if (verbose_level > 0) {
307 			printf(" type=0x%04x\n", eth_type);
308 		}
309 
310 		/* Reply to ARP requests */
311 		if (eth_type == RTE_ETHER_TYPE_ARP) {
312 			arp_h = (struct rte_arp_hdr *) ((char *)eth_h + l2_len);
313 			arp_op = RTE_BE_TO_CPU_16(arp_h->arp_opcode);
314 			arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_protocol);
315 			if (verbose_level > 0) {
316 				printf("  ARP:  hrd=%d proto=0x%04x hln=%d "
317 				       "pln=%d op=%u (%s)\n",
318 				       RTE_BE_TO_CPU_16(arp_h->arp_hardware),
319 				       arp_pro, arp_h->arp_hlen,
320 				       arp_h->arp_plen, arp_op,
321 				       arp_op_name(arp_op));
322 			}
323 			if ((RTE_BE_TO_CPU_16(arp_h->arp_hardware) !=
324 			     RTE_ARP_HRD_ETHER) ||
325 			    (arp_pro != RTE_ETHER_TYPE_IPV4) ||
326 			    (arp_h->arp_hlen != 6) ||
327 			    (arp_h->arp_plen != 4)
328 			    ) {
329 				rte_pktmbuf_free(pkt);
330 				if (verbose_level > 0)
331 					printf("\n");
332 				continue;
333 			}
334 			if (verbose_level > 0) {
335 				rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
336 						&eth_addr);
337 				ether_addr_dump("        sha=", &eth_addr);
338 				ip_addr = arp_h->arp_data.arp_sip;
339 				ipv4_addr_dump(" sip=", ip_addr);
340 				printf("\n");
341 				rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
342 						&eth_addr);
343 				ether_addr_dump("        tha=", &eth_addr);
344 				ip_addr = arp_h->arp_data.arp_tip;
345 				ipv4_addr_dump(" tip=", ip_addr);
346 				printf("\n");
347 			}
348 			if (arp_op != RTE_ARP_OP_REQUEST) {
349 				rte_pktmbuf_free(pkt);
350 				continue;
351 			}
352 
353 			/*
354 			 * Build ARP reply.
355 			 */
356 
357 			/* Use source MAC address as destination MAC address. */
358 			rte_ether_addr_copy(&eth_h->src_addr, &eth_h->dst_addr);
359 			/* Set source MAC address with MAC address of TX port */
360 			rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
361 					&eth_h->src_addr);
362 
363 			arp_h->arp_opcode = rte_cpu_to_be_16(RTE_ARP_OP_REPLY);
364 			rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
365 					&eth_addr);
366 			rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
367 					&arp_h->arp_data.arp_tha);
368 			rte_ether_addr_copy(&eth_h->src_addr,
369 					&arp_h->arp_data.arp_sha);
370 
371 			/* Swap IP addresses in ARP payload */
372 			ip_addr = arp_h->arp_data.arp_sip;
373 			arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip;
374 			arp_h->arp_data.arp_tip = ip_addr;
375 			pkts_burst[nb_replies++] = pkt;
376 			continue;
377 		}
378 
379 		if (eth_type != RTE_ETHER_TYPE_IPV4) {
380 			rte_pktmbuf_free(pkt);
381 			continue;
382 		}
383 		ip_h = (struct rte_ipv4_hdr *) ((char *)eth_h + l2_len);
384 		if (verbose_level > 0) {
385 			ipv4_addr_dump("  IPV4: src=", ip_h->src_addr);
386 			ipv4_addr_dump(" dst=", ip_h->dst_addr);
387 			printf(" proto=%d (%s)\n",
388 			       ip_h->next_proto_id,
389 			       ip_proto_name(ip_h->next_proto_id));
390 		}
391 
392 		/*
393 		 * Check if packet is a ICMP echo request.
394 		 */
395 		icmp_h = (struct rte_icmp_hdr *) ((char *)ip_h +
396 					      sizeof(struct rte_ipv4_hdr));
397 		if (! ((ip_h->next_proto_id == IPPROTO_ICMP) &&
398 		       (icmp_h->icmp_type == RTE_ICMP_TYPE_ECHO_REQUEST) &&
399 		       (icmp_h->icmp_code == 0))) {
400 			rte_pktmbuf_free(pkt);
401 			continue;
402 		}
403 
404 		if (verbose_level > 0)
405 			printf("  ICMP: echo request seq id=%d\n",
406 			       rte_be_to_cpu_16(icmp_h->icmp_seq_nb));
407 
408 		/*
409 		 * Prepare ICMP echo reply to be sent back.
410 		 * - switch ethernet source and destinations addresses,
411 		 * - use the request IP source address as the reply IP
412 		 *    destination address,
413 		 * - if the request IP destination address is a multicast
414 		 *   address:
415 		 *     - choose a reply IP source address different from the
416 		 *       request IP source address,
417 		 *     - re-compute the IP header checksum.
418 		 *   Otherwise:
419 		 *     - switch the request IP source and destination
420 		 *       addresses in the reply IP header,
421 		 *     - keep the IP header checksum unchanged.
422 		 * - set RTE_ICMP_TYPE_ECHO_REPLY in ICMP header.
423 		 * ICMP checksum is computed by assuming it is valid in the
424 		 * echo request and not verified.
425 		 */
426 		rte_ether_addr_copy(&eth_h->src_addr, &eth_addr);
427 		rte_ether_addr_copy(&eth_h->dst_addr, &eth_h->src_addr);
428 		rte_ether_addr_copy(&eth_addr, &eth_h->dst_addr);
429 		ip_addr = ip_h->src_addr;
430 		if (is_multicast_ipv4_addr(ip_h->dst_addr)) {
431 			uint32_t ip_src;
432 
433 			ip_src = rte_be_to_cpu_32(ip_addr);
434 			if ((ip_src & 0x00000003) == 1)
435 				ip_src = (ip_src & 0xFFFFFFFC) | 0x00000002;
436 			else
437 				ip_src = (ip_src & 0xFFFFFFFC) | 0x00000001;
438 			ip_h->src_addr = rte_cpu_to_be_32(ip_src);
439 			ip_h->dst_addr = ip_addr;
440 			ip_h->hdr_checksum = rte_ipv4_cksum_simple(ip_h);
441 		} else {
442 			ip_h->src_addr = ip_h->dst_addr;
443 			ip_h->dst_addr = ip_addr;
444 		}
445 		icmp_h->icmp_type = RTE_ICMP_TYPE_ECHO_REPLY;
446 		cksum = ~icmp_h->icmp_cksum & 0xffff;
447 		cksum += ~RTE_BE16(RTE_ICMP_TYPE_ECHO_REQUEST << 8) & 0xffff;
448 		cksum += RTE_BE16(RTE_ICMP_TYPE_ECHO_REPLY << 8);
449 		cksum = (cksum & 0xffff) + (cksum >> 16);
450 		cksum = (cksum & 0xffff) + (cksum >> 16);
451 		icmp_h->icmp_cksum = ~cksum;
452 		pkts_burst[nb_replies++] = pkt;
453 	}
454 
455 	/* Send back ICMP echo replies, if any. */
456 	if (nb_replies > 0)
457 		common_fwd_stream_transmit(fs, pkts_burst, nb_replies);
458 
459 	return true;
460 }
461 
462 struct fwd_engine icmp_echo_engine = {
463 	.fwd_mode_name  = "icmpecho",
464 	.stream_init    = common_fwd_stream_init,
465 	.packet_fwd     = reply_to_icmp_echo_rqsts,
466 };
467