1
2
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_atomic.h>
24#include <rte_branch_prediction.h>
25#include <rte_memory.h>
26#include <rte_mempool.h>
27#include <rte_mbuf.h>
28#include <rte_ether.h>
29#include <rte_ethdev.h>
30#include <rte_arp.h>
31#include <rte_ip.h>
32#include <rte_icmp.h>
33#include <rte_string_fns.h>
34#include <rte_flow.h>
35
36#include "testpmd.h"
37
38static const char *
39arp_op_name(uint16_t arp_op)
40{
41 switch (arp_op) {
42 case RTE_ARP_OP_REQUEST:
43 return "ARP Request";
44 case RTE_ARP_OP_REPLY:
45 return "ARP Reply";
46 case RTE_ARP_OP_REVREQUEST:
47 return "Reverse ARP Request";
48 case RTE_ARP_OP_REVREPLY:
49 return "Reverse ARP Reply";
50 case RTE_ARP_OP_INVREQUEST:
51 return "Peer Identify Request";
52 case RTE_ARP_OP_INVREPLY:
53 return "Peer Identify Reply";
54 default:
55 break;
56 }
57 return "Unkwown ARP op";
58}
59
60static const char *
61ip_proto_name(uint16_t ip_proto)
62{
63 static const char * ip_proto_names[] = {
64 "IP6HOPOPTS",
65 "ICMP",
66 "IGMP",
67 "GGP",
68 "IPv4",
69
70 "UNASSIGNED",
71 "TCP",
72 "ST",
73 "EGP",
74 "PIGP",
75
76 "RCC_MON",
77 "NVPII",
78 "PUP",
79 "ARGUS",
80 "EMCON",
81
82 "XNET",
83 "CHAOS",
84 "UDP",
85 "MUX",
86 "DCN_MEAS",
87
88 "HMP",
89 "PRM",
90 "XNS_IDP",
91 "TRUNK1",
92 "TRUNK2",
93
94 "LEAF1",
95 "LEAF2",
96 "RDP",
97 "IRTP",
98 "TP4",
99
100 "BLT",
101 "NSP",
102 "INP",
103 "SEP",
104 "3PC",
105
106 "IDPR",
107 "XTP",
108 "DDP",
109 "CMTP",
110 "TPXX",
111
112 "ILTP",
113 "IPv6_HDR",
114 "SDRP",
115 "IPv6_RTG",
116 "IPv6_FRAG",
117
118 "IDRP",
119 "RSVP",
120 "GRE",
121 "MHRP",
122 "BHA",
123
124 "ESP",
125 "AH",
126 "INLSP",
127 "SWIPE",
128 "NHRP",
129
130 "UNASSIGNED",
131 "UNASSIGNED",
132 "UNASSIGNED",
133 "ICMPv6",
134 "IPv6NONEXT",
135
136 "Ipv6DSTOPTS",
137 "AHIP",
138 "CFTP",
139 "HELLO",
140 "SATEXPAK",
141
142 "KRYPTOLAN",
143 "RVD",
144 "IPPC",
145 "ADFS",
146 "SATMON",
147
148 "VISA",
149 "IPCV",
150 "CPNX",
151 "CPHB",
152 "WSN",
153
154 "PVP",
155 "BRSATMON",
156 "ND",
157 "WBMON",
158 "WBEXPAK",
159
160 "EON",
161 "VMTP",
162 "SVMTP",
163 "VINES",
164 "TTP",
165
166 "IGP",
167 "DGP",
168 "TCF",
169 "IGRP",
170 "OSPFIGP",
171
172 "SRPC",
173 "LARP",
174 "MTP",
175 "AX25",
176 "4IN4",
177
178 "MICP",
179 "SCCSP",
180 "ETHERIP",
181 "ENCAP",
182 "AES",
183
184 "GMTP",
185 "IPCOMP",
186 "UNASSIGNED",
187 "UNASSIGNED",
188 "PIM",
189 };
190
191 if (ip_proto < RTE_DIM(ip_proto_names))
192 return ip_proto_names[ip_proto];
193 switch (ip_proto) {
194#ifdef IPPROTO_PGM
195 case IPPROTO_PGM:
196 return "PGM";
197#endif
198 case IPPROTO_SCTP:
199 return "SCTP";
200#ifdef IPPROTO_DIVERT
201 case IPPROTO_DIVERT:
202 return "DIVERT";
203#endif
204 case IPPROTO_RAW:
205 return "RAW";
206 default:
207 break;
208 }
209 return "UNASSIGNED";
210}
211
212static void
213ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf)
214{
215 uint32_t ipv4_addr;
216
217 ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr);
218 sprintf(buf, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF,
219 (ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF,
220 ipv4_addr & 0xFF);
221}
222
223static void
224ether_addr_dump(const char *what, const struct rte_ether_addr *ea)
225{
226 char buf[RTE_ETHER_ADDR_FMT_SIZE];
227
228 rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, ea);
229 if (what)
230 printf("%s", what);
231 printf("%s", buf);
232}
233
234static void
235ipv4_addr_dump(const char *what, uint32_t be_ipv4_addr)
236{
237 char buf[16];
238
239 ipv4_addr_to_dot(be_ipv4_addr, buf);
240 if (what)
241 printf("%s", what);
242 printf("%s", buf);
243}
244
245static uint16_t
246ipv4_hdr_cksum(struct rte_ipv4_hdr *ip_h)
247{
248 uint16_t *v16_h;
249 uint32_t ip_cksum;
250
251
252
253
254
255 v16_h = (unaligned_uint16_t *) ip_h;
256 ip_cksum = v16_h[0] + v16_h[1] + v16_h[2] + v16_h[3] +
257 v16_h[4] + v16_h[6] + v16_h[7] + v16_h[8] + v16_h[9];
258
259
260 ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16);
261 ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16);
262 ip_cksum = (~ip_cksum) & 0x0000FFFF;
263 return (ip_cksum == 0) ? 0xFFFF : (uint16_t) ip_cksum;
264}
265
266#define is_multicast_ipv4_addr(ipv4_addr) \
267 (((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0)
268
269
270
271
272
273static void
274reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
275{
276 struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
277 struct rte_mbuf *pkt;
278 struct rte_ether_hdr *eth_h;
279 struct rte_vlan_hdr *vlan_h;
280 struct rte_arp_hdr *arp_h;
281 struct rte_ipv4_hdr *ip_h;
282 struct rte_icmp_hdr *icmp_h;
283 struct rte_ether_addr eth_addr;
284 uint32_t retry;
285 uint32_t ip_addr;
286 uint16_t nb_rx;
287 uint16_t nb_tx;
288 uint16_t nb_replies;
289 uint16_t eth_type;
290 uint16_t vlan_id;
291 uint16_t arp_op;
292 uint16_t arp_pro;
293 uint32_t cksum;
294 uint8_t i;
295 int l2_len;
296 uint64_t start_tsc = 0;
297
298 get_start_cycles(&start_tsc);
299
300
301
302
303 nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
304 nb_pkt_per_burst);
305 inc_rx_burst_stats(fs, nb_rx);
306 if (unlikely(nb_rx == 0))
307 return;
308
309 fs->rx_packets += nb_rx;
310 nb_replies = 0;
311 for (i = 0; i < nb_rx; i++) {
312 if (likely(i < nb_rx - 1))
313 rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
314 void *));
315 pkt = pkts_burst[i];
316 eth_h = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
317 eth_type = RTE_BE_TO_CPU_16(eth_h->ether_type);
318 l2_len = sizeof(struct rte_ether_hdr);
319 if (verbose_level > 0) {
320 printf("\nPort %d pkt-len=%u nb-segs=%u\n",
321 fs->rx_port, pkt->pkt_len, pkt->nb_segs);
322 ether_addr_dump(" ETH: src=", ð_h->s_addr);
323 ether_addr_dump(" dst=", ð_h->d_addr);
324 }
325 if (eth_type == RTE_ETHER_TYPE_VLAN) {
326 vlan_h = (struct rte_vlan_hdr *)
327 ((char *)eth_h + sizeof(struct rte_ether_hdr));
328 l2_len += sizeof(struct rte_vlan_hdr);
329 eth_type = rte_be_to_cpu_16(vlan_h->eth_proto);
330 if (verbose_level > 0) {
331 vlan_id = rte_be_to_cpu_16(vlan_h->vlan_tci)
332 & 0xFFF;
333 printf(" [vlan id=%u]", vlan_id);
334 }
335 }
336 if (verbose_level > 0) {
337 printf(" type=0x%04x\n", eth_type);
338 }
339
340
341 if (eth_type == RTE_ETHER_TYPE_ARP) {
342 arp_h = (struct rte_arp_hdr *) ((char *)eth_h + l2_len);
343 arp_op = RTE_BE_TO_CPU_16(arp_h->arp_opcode);
344 arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_protocol);
345 if (verbose_level > 0) {
346 printf(" ARP: hrd=%d proto=0x%04x hln=%d "
347 "pln=%d op=%u (%s)\n",
348 RTE_BE_TO_CPU_16(arp_h->arp_hardware),
349 arp_pro, arp_h->arp_hlen,
350 arp_h->arp_plen, arp_op,
351 arp_op_name(arp_op));
352 }
353 if ((RTE_BE_TO_CPU_16(arp_h->arp_hardware) !=
354 RTE_ARP_HRD_ETHER) ||
355 (arp_pro != RTE_ETHER_TYPE_IPV4) ||
356 (arp_h->arp_hlen != 6) ||
357 (arp_h->arp_plen != 4)
358 ) {
359 rte_pktmbuf_free(pkt);
360 if (verbose_level > 0)
361 printf("\n");
362 continue;
363 }
364 if (verbose_level > 0) {
365 rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
366 ð_addr);
367 ether_addr_dump(" sha=", ð_addr);
368 ip_addr = arp_h->arp_data.arp_sip;
369 ipv4_addr_dump(" sip=", ip_addr);
370 printf("\n");
371 rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
372 ð_addr);
373 ether_addr_dump(" tha=", ð_addr);
374 ip_addr = arp_h->arp_data.arp_tip;
375 ipv4_addr_dump(" tip=", ip_addr);
376 printf("\n");
377 }
378 if (arp_op != RTE_ARP_OP_REQUEST) {
379 rte_pktmbuf_free(pkt);
380 continue;
381 }
382
383
384
385
386
387
388 rte_ether_addr_copy(ð_h->s_addr, ð_h->d_addr);
389
390 rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
391 ð_h->s_addr);
392
393 arp_h->arp_opcode = rte_cpu_to_be_16(RTE_ARP_OP_REPLY);
394 rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
395 ð_addr);
396 rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
397 &arp_h->arp_data.arp_tha);
398 rte_ether_addr_copy(ð_h->s_addr,
399 &arp_h->arp_data.arp_sha);
400
401
402 ip_addr = arp_h->arp_data.arp_sip;
403 arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip;
404 arp_h->arp_data.arp_tip = ip_addr;
405 pkts_burst[nb_replies++] = pkt;
406 continue;
407 }
408
409 if (eth_type != RTE_ETHER_TYPE_IPV4) {
410 rte_pktmbuf_free(pkt);
411 continue;
412 }
413 ip_h = (struct rte_ipv4_hdr *) ((char *)eth_h + l2_len);
414 if (verbose_level > 0) {
415 ipv4_addr_dump(" IPV4: src=", ip_h->src_addr);
416 ipv4_addr_dump(" dst=", ip_h->dst_addr);
417 printf(" proto=%d (%s)\n",
418 ip_h->next_proto_id,
419 ip_proto_name(ip_h->next_proto_id));
420 }
421
422
423
424
425 icmp_h = (struct rte_icmp_hdr *) ((char *)ip_h +
426 sizeof(struct rte_ipv4_hdr));
427 if (! ((ip_h->next_proto_id == IPPROTO_ICMP) &&
428 (icmp_h->icmp_type == RTE_IP_ICMP_ECHO_REQUEST) &&
429 (icmp_h->icmp_code == 0))) {
430 rte_pktmbuf_free(pkt);
431 continue;
432 }
433
434 if (verbose_level > 0)
435 printf(" ICMP: echo request seq id=%d\n",
436 rte_be_to_cpu_16(icmp_h->icmp_seq_nb));
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456 rte_ether_addr_copy(ð_h->s_addr, ð_addr);
457 rte_ether_addr_copy(ð_h->d_addr, ð_h->s_addr);
458 rte_ether_addr_copy(ð_addr, ð_h->d_addr);
459 ip_addr = ip_h->src_addr;
460 if (is_multicast_ipv4_addr(ip_h->dst_addr)) {
461 uint32_t ip_src;
462
463 ip_src = rte_be_to_cpu_32(ip_addr);
464 if ((ip_src & 0x00000003) == 1)
465 ip_src = (ip_src & 0xFFFFFFFC) | 0x00000002;
466 else
467 ip_src = (ip_src & 0xFFFFFFFC) | 0x00000001;
468 ip_h->src_addr = rte_cpu_to_be_32(ip_src);
469 ip_h->dst_addr = ip_addr;
470 ip_h->hdr_checksum = ipv4_hdr_cksum(ip_h);
471 } else {
472 ip_h->src_addr = ip_h->dst_addr;
473 ip_h->dst_addr = ip_addr;
474 }
475 icmp_h->icmp_type = RTE_IP_ICMP_ECHO_REPLY;
476 cksum = ~icmp_h->icmp_cksum & 0xffff;
477 cksum += ~RTE_BE16(RTE_IP_ICMP_ECHO_REQUEST << 8) & 0xffff;
478 cksum += RTE_BE16(RTE_IP_ICMP_ECHO_REPLY << 8);
479 cksum = (cksum & 0xffff) + (cksum >> 16);
480 cksum = (cksum & 0xffff) + (cksum >> 16);
481 icmp_h->icmp_cksum = ~cksum;
482 pkts_burst[nb_replies++] = pkt;
483 }
484
485
486 if (nb_replies > 0) {
487 nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst,
488 nb_replies);
489
490
491
492 if (unlikely(nb_tx < nb_replies) && fs->retry_enabled) {
493 retry = 0;
494 while (nb_tx < nb_replies &&
495 retry++ < burst_tx_retry_num) {
496 rte_delay_us(burst_tx_delay_time);
497 nb_tx += rte_eth_tx_burst(fs->tx_port,
498 fs->tx_queue,
499 &pkts_burst[nb_tx],
500 nb_replies - nb_tx);
501 }
502 }
503 fs->tx_packets += nb_tx;
504 inc_tx_burst_stats(fs, nb_tx);
505 if (unlikely(nb_tx < nb_replies)) {
506 fs->fwd_dropped += (nb_replies - nb_tx);
507 do {
508 rte_pktmbuf_free(pkts_burst[nb_tx]);
509 } while (++nb_tx < nb_replies);
510 }
511 }
512
513 get_end_cycles(fs, start_tsc);
514}
515
516struct fwd_engine icmp_echo_engine = {
517 .fwd_mode_name = "icmpecho",
518 .port_fwd_begin = NULL,
519 .port_fwd_end = NULL,
520 .packet_fwd = reply_to_icmp_echo_rqsts,
521};
522