Branch data Line data Source code
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 : 0 : switch (arp_op) {
41 : : case RTE_ARP_OP_REQUEST:
42 : : return "ARP Request";
43 : 0 : case RTE_ARP_OP_REPLY:
44 : 0 : return "ARP Reply";
45 : 0 : case RTE_ARP_OP_REVREQUEST:
46 : 0 : return "Reverse ARP Request";
47 : 0 : case RTE_ARP_OP_REVREPLY:
48 : 0 : return "Reverse ARP Reply";
49 : 0 : case RTE_ARP_OP_INVREQUEST:
50 : 0 : return "Peer Identify Request";
51 : 0 : case RTE_ARP_OP_INVREPLY:
52 : 0 : return "Peer Identify Reply";
53 : : default:
54 : : break;
55 : : }
56 : 0 : 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 : 0 : if (ip_proto < RTE_DIM(ip_proto_names))
191 : 0 : return ip_proto_names[ip_proto];
192 : 0 : 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 : 0 : case IPPROTO_RAW: /**< raw IP packet */
204 : 0 : return "RAW";
205 : : default:
206 : : break;
207 : : }
208 : 0 : return "UNASSIGNED";
209 : : }
210 : :
211 : : static void
212 : 0 : ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf)
213 : : {
214 : : uint32_t ipv4_addr;
215 : :
216 : 0 : ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr);
217 : 0 : sprintf(buf, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF,
218 : 0 : (ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF,
219 : : ipv4_addr & 0xFF);
220 : 0 : }
221 : :
222 : : static void
223 : 0 : ether_addr_dump(const char *what, const struct rte_ether_addr *ea)
224 : : {
225 : : char buf[RTE_ETHER_ADDR_FMT_SIZE];
226 : :
227 : 0 : rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, ea);
228 : 0 : if (what)
229 : : printf("%s", what);
230 : : printf("%s", buf);
231 : 0 : }
232 : :
233 : : static void
234 : 0 : ipv4_addr_dump(const char *what, uint32_t be_ipv4_addr)
235 : : {
236 : : char buf[16];
237 : :
238 : 0 : ipv4_addr_to_dot(be_ipv4_addr, buf);
239 : 0 : if (what)
240 : : printf("%s", what);
241 : : printf("%s", buf);
242 : 0 : }
243 : :
244 : : static uint16_t
245 : 0 : ipv4_hdr_cksum(struct rte_ipv4_hdr *ip_h)
246 : : {
247 : : uint16_t *v16_h;
248 : : uint32_t ip_cksum;
249 : :
250 : : /*
251 : : * Compute the sum of successive 16-bit words of the IPv4 header,
252 : : * skipping the checksum field of the header.
253 : : */
254 : : v16_h = (unaligned_uint16_t *) ip_h;
255 : 0 : ip_cksum = v16_h[0] + v16_h[1] + v16_h[2] + v16_h[3] +
256 : 0 : v16_h[4] + v16_h[6] + v16_h[7] + v16_h[8] + v16_h[9];
257 : :
258 : : /* reduce 32 bit checksum to 16 bits and complement it */
259 : 0 : ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16);
260 : 0 : ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16);
261 : 0 : ip_cksum = (~ip_cksum) & 0x0000FFFF;
262 : 0 : return (ip_cksum == 0) ? 0xFFFF : (uint16_t) ip_cksum;
263 : : }
264 : :
265 : : #define is_multicast_ipv4_addr(ipv4_addr) \
266 : : (((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0)
267 : :
268 : : /*
269 : : * Receive a burst of packets, lookup for ICMP echo requests, and, if any,
270 : : * send back ICMP echo replies.
271 : : */
272 : : static bool
273 : 0 : reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
274 : : {
275 : : struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
276 : : struct rte_mbuf *pkt;
277 : : struct rte_ether_hdr *eth_h;
278 : : struct rte_vlan_hdr *vlan_h;
279 : : struct rte_arp_hdr *arp_h;
280 : : struct rte_ipv4_hdr *ip_h;
281 : : struct rte_icmp_hdr *icmp_h;
282 : : struct rte_ether_addr eth_addr;
283 : : uint32_t ip_addr;
284 : : uint16_t nb_rx;
285 : : uint16_t nb_replies;
286 : : uint16_t eth_type;
287 : : uint16_t vlan_id;
288 : : uint16_t arp_op;
289 : : uint16_t arp_pro;
290 : : uint32_t cksum;
291 : : uint8_t i;
292 : : int l2_len;
293 : :
294 : : /*
295 : : * First, receive a burst of packets.
296 : : */
297 : 0 : nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
298 : 0 : if (unlikely(nb_rx == 0))
299 : : return false;
300 : :
301 : : nb_replies = 0;
302 : 0 : for (i = 0; i < nb_rx; i++) {
303 : 0 : if (likely(i < nb_rx - 1))
304 : 0 : rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
305 : : void *));
306 : 0 : pkt = pkts_burst[i];
307 : 0 : eth_h = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
308 : 0 : eth_type = RTE_BE_TO_CPU_16(eth_h->ether_type);
309 : : l2_len = sizeof(struct rte_ether_hdr);
310 : 0 : if (verbose_level > 0) {
311 : 0 : printf("\nPort %d pkt-len=%u nb-segs=%u\n",
312 : 0 : fs->rx_port, pkt->pkt_len, pkt->nb_segs);
313 : 0 : ether_addr_dump(" ETH: src=", ð_h->src_addr);
314 : 0 : ether_addr_dump(" dst=", ð_h->dst_addr);
315 : : }
316 : 0 : if (eth_type == RTE_ETHER_TYPE_VLAN) {
317 : : vlan_h = (struct rte_vlan_hdr *)
318 : : ((char *)eth_h + sizeof(struct rte_ether_hdr));
319 : : l2_len += sizeof(struct rte_vlan_hdr);
320 : 0 : eth_type = rte_be_to_cpu_16(vlan_h->eth_proto);
321 : 0 : if (verbose_level > 0) {
322 : 0 : vlan_id = rte_be_to_cpu_16(vlan_h->vlan_tci)
323 : : & 0xFFF;
324 : 0 : printf(" [vlan id=%u]", vlan_id);
325 : : }
326 : : }
327 : 0 : if (verbose_level > 0) {
328 : 0 : printf(" type=0x%04x\n", eth_type);
329 : : }
330 : :
331 : : /* Reply to ARP requests */
332 : 0 : if (eth_type == RTE_ETHER_TYPE_ARP) {
333 : 0 : arp_h = (struct rte_arp_hdr *) ((char *)eth_h + l2_len);
334 : 0 : arp_op = RTE_BE_TO_CPU_16(arp_h->arp_opcode);
335 : 0 : arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_protocol);
336 : 0 : if (verbose_level > 0) {
337 : 0 : printf(" ARP: hrd=%d proto=0x%04x hln=%d "
338 : : "pln=%d op=%u (%s)\n",
339 : 0 : RTE_BE_TO_CPU_16(arp_h->arp_hardware),
340 : 0 : arp_pro, arp_h->arp_hlen,
341 : 0 : arp_h->arp_plen, arp_op,
342 : : arp_op_name(arp_op));
343 : : }
344 : 0 : if ((RTE_BE_TO_CPU_16(arp_h->arp_hardware) !=
345 : 0 : RTE_ARP_HRD_ETHER) ||
346 : : (arp_pro != RTE_ETHER_TYPE_IPV4) ||
347 : 0 : (arp_h->arp_hlen != 6) ||
348 : : (arp_h->arp_plen != 4)
349 : : ) {
350 : 0 : rte_pktmbuf_free(pkt);
351 : 0 : if (verbose_level > 0)
352 : : printf("\n");
353 : 0 : continue;
354 : : }
355 : 0 : if (verbose_level > 0) {
356 : : rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
357 : : ð_addr);
358 : 0 : ether_addr_dump(" sha=", ð_addr);
359 : 0 : ip_addr = arp_h->arp_data.arp_sip;
360 : 0 : ipv4_addr_dump(" sip=", ip_addr);
361 : : printf("\n");
362 : : rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
363 : : ð_addr);
364 : 0 : ether_addr_dump(" tha=", ð_addr);
365 : 0 : ip_addr = arp_h->arp_data.arp_tip;
366 : 0 : ipv4_addr_dump(" tip=", ip_addr);
367 : : printf("\n");
368 : : }
369 : 0 : if (arp_op != RTE_ARP_OP_REQUEST) {
370 : 0 : rte_pktmbuf_free(pkt);
371 : 0 : continue;
372 : : }
373 : :
374 : : /*
375 : : * Build ARP reply.
376 : : */
377 : :
378 : : /* Use source MAC address as destination MAC address. */
379 : : rte_ether_addr_copy(ð_h->src_addr, ð_h->dst_addr);
380 : : /* Set source MAC address with MAC address of TX port */
381 : 0 : rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
382 : : ð_h->src_addr);
383 : :
384 : 0 : arp_h->arp_opcode = rte_cpu_to_be_16(RTE_ARP_OP_REPLY);
385 : : rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
386 : : ð_addr);
387 : : rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
388 : : &arp_h->arp_data.arp_tha);
389 : : rte_ether_addr_copy(ð_h->src_addr,
390 : : &arp_h->arp_data.arp_sha);
391 : :
392 : : /* Swap IP addresses in ARP payload */
393 : 0 : ip_addr = arp_h->arp_data.arp_sip;
394 : 0 : arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip;
395 : 0 : arp_h->arp_data.arp_tip = ip_addr;
396 : 0 : pkts_burst[nb_replies++] = pkt;
397 : 0 : continue;
398 : : }
399 : :
400 : 0 : if (eth_type != RTE_ETHER_TYPE_IPV4) {
401 : 0 : rte_pktmbuf_free(pkt);
402 : 0 : continue;
403 : : }
404 : 0 : ip_h = (struct rte_ipv4_hdr *) ((char *)eth_h + l2_len);
405 : 0 : if (verbose_level > 0) {
406 : 0 : ipv4_addr_dump(" IPV4: src=", ip_h->src_addr);
407 : 0 : ipv4_addr_dump(" dst=", ip_h->dst_addr);
408 : 0 : printf(" proto=%d (%s)\n",
409 : : ip_h->next_proto_id,
410 : 0 : ip_proto_name(ip_h->next_proto_id));
411 : : }
412 : :
413 : : /*
414 : : * Check if packet is a ICMP echo request.
415 : : */
416 : : icmp_h = (struct rte_icmp_hdr *) ((char *)ip_h +
417 : : sizeof(struct rte_ipv4_hdr));
418 : 0 : if (! ((ip_h->next_proto_id == IPPROTO_ICMP) &&
419 : 0 : (icmp_h->icmp_type == RTE_IP_ICMP_ECHO_REQUEST) &&
420 : 0 : (icmp_h->icmp_code == 0))) {
421 : 0 : rte_pktmbuf_free(pkt);
422 : 0 : continue;
423 : : }
424 : :
425 : 0 : if (verbose_level > 0)
426 : 0 : printf(" ICMP: echo request seq id=%d\n",
427 : 0 : rte_be_to_cpu_16(icmp_h->icmp_seq_nb));
428 : :
429 : : /*
430 : : * Prepare ICMP echo reply to be sent back.
431 : : * - switch ethernet source and destinations addresses,
432 : : * - use the request IP source address as the reply IP
433 : : * destination address,
434 : : * - if the request IP destination address is a multicast
435 : : * address:
436 : : * - choose a reply IP source address different from the
437 : : * request IP source address,
438 : : * - re-compute the IP header checksum.
439 : : * Otherwise:
440 : : * - switch the request IP source and destination
441 : : * addresses in the reply IP header,
442 : : * - keep the IP header checksum unchanged.
443 : : * - set RTE_IP_ICMP_ECHO_REPLY in ICMP header.
444 : : * ICMP checksum is computed by assuming it is valid in the
445 : : * echo request and not verified.
446 : : */
447 : : rte_ether_addr_copy(ð_h->src_addr, ð_addr);
448 : : rte_ether_addr_copy(ð_h->dst_addr, ð_h->src_addr);
449 : : rte_ether_addr_copy(ð_addr, ð_h->dst_addr);
450 : 0 : ip_addr = ip_h->src_addr;
451 : 0 : if (is_multicast_ipv4_addr(ip_h->dst_addr)) {
452 : : uint32_t ip_src;
453 : :
454 : 0 : ip_src = rte_be_to_cpu_32(ip_addr);
455 : 0 : if ((ip_src & 0x00000003) == 1)
456 : 0 : ip_src = (ip_src & 0xFFFFFFFC) | 0x00000002;
457 : : else
458 : 0 : ip_src = (ip_src & 0xFFFFFFFC) | 0x00000001;
459 : 0 : ip_h->src_addr = rte_cpu_to_be_32(ip_src);
460 : 0 : ip_h->dst_addr = ip_addr;
461 : 0 : ip_h->hdr_checksum = ipv4_hdr_cksum(ip_h);
462 : : } else {
463 : 0 : ip_h->src_addr = ip_h->dst_addr;
464 : 0 : ip_h->dst_addr = ip_addr;
465 : : }
466 : 0 : icmp_h->icmp_type = RTE_IP_ICMP_ECHO_REPLY;
467 : 0 : cksum = ~icmp_h->icmp_cksum & 0xffff;
468 : 0 : cksum += ~RTE_BE16(RTE_IP_ICMP_ECHO_REQUEST << 8) & 0xffff;
469 : : cksum += RTE_BE16(RTE_IP_ICMP_ECHO_REPLY << 8);
470 : 0 : cksum = (cksum & 0xffff) + (cksum >> 16);
471 : 0 : cksum = (cksum & 0xffff) + (cksum >> 16);
472 : 0 : icmp_h->icmp_cksum = ~cksum;
473 : 0 : pkts_burst[nb_replies++] = pkt;
474 : : }
475 : :
476 : : /* Send back ICMP echo replies, if any. */
477 : 0 : if (nb_replies > 0)
478 : 0 : common_fwd_stream_transmit(fs, pkts_burst, nb_replies);
479 : :
480 : : return true;
481 : : }
482 : :
483 : : struct fwd_engine icmp_echo_engine = {
484 : : .fwd_mode_name = "icmpecho",
485 : : .stream_init = common_fwd_stream_init,
486 : : .packet_fwd = reply_to_icmp_echo_rqsts,
487 : : };
|