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 : : #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 : 0 : 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 : 0 : nb_rx = common_fwd_stream_receive(fs, pkts_burst, nb_pkt_per_burst);
277 : 0 : if (unlikely(nb_rx == 0))
278 : : return false;
279 : :
280 : : nb_replies = 0;
281 : 0 : for (i = 0; i < nb_rx; i++) {
282 : 0 : if (likely(i < nb_rx - 1))
283 : 0 : rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
284 : : void *));
285 : 0 : pkt = pkts_burst[i];
286 : 0 : eth_h = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
287 : 0 : eth_type = RTE_BE_TO_CPU_16(eth_h->ether_type);
288 : : l2_len = sizeof(struct rte_ether_hdr);
289 : 0 : if (verbose_level > 0) {
290 : 0 : printf("\nPort %d pkt-len=%u nb-segs=%u\n",
291 : 0 : fs->rx_port, pkt->pkt_len, pkt->nb_segs);
292 : 0 : ether_addr_dump(" ETH: src=", ð_h->src_addr);
293 : 0 : ether_addr_dump(" dst=", ð_h->dst_addr);
294 : : }
295 : 0 : 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 : 0 : eth_type = rte_be_to_cpu_16(vlan_h->eth_proto);
300 : 0 : if (verbose_level > 0) {
301 : 0 : vlan_id = rte_be_to_cpu_16(vlan_h->vlan_tci)
302 : : & 0xFFF;
303 : 0 : printf(" [vlan id=%u]", vlan_id);
304 : : }
305 : : }
306 : 0 : if (verbose_level > 0) {
307 : 0 : printf(" type=0x%04x\n", eth_type);
308 : : }
309 : :
310 : : /* Reply to ARP requests */
311 : 0 : if (eth_type == RTE_ETHER_TYPE_ARP) {
312 : 0 : arp_h = (struct rte_arp_hdr *) ((char *)eth_h + l2_len);
313 : 0 : arp_op = RTE_BE_TO_CPU_16(arp_h->arp_opcode);
314 : 0 : arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_protocol);
315 : 0 : if (verbose_level > 0) {
316 : 0 : printf(" ARP: hrd=%d proto=0x%04x hln=%d "
317 : : "pln=%d op=%u (%s)\n",
318 : 0 : RTE_BE_TO_CPU_16(arp_h->arp_hardware),
319 : 0 : arp_pro, arp_h->arp_hlen,
320 : 0 : arp_h->arp_plen, arp_op,
321 : : arp_op_name(arp_op));
322 : : }
323 : 0 : if ((RTE_BE_TO_CPU_16(arp_h->arp_hardware) !=
324 : 0 : RTE_ARP_HRD_ETHER) ||
325 : : (arp_pro != RTE_ETHER_TYPE_IPV4) ||
326 : 0 : (arp_h->arp_hlen != 6) ||
327 : : (arp_h->arp_plen != 4)
328 : : ) {
329 : 0 : rte_pktmbuf_free(pkt);
330 : 0 : if (verbose_level > 0)
331 : : printf("\n");
332 : 0 : continue;
333 : : }
334 : 0 : if (verbose_level > 0) {
335 : : rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
336 : : ð_addr);
337 : 0 : ether_addr_dump(" sha=", ð_addr);
338 : 0 : ip_addr = arp_h->arp_data.arp_sip;
339 : 0 : ipv4_addr_dump(" sip=", ip_addr);
340 : : printf("\n");
341 : : rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
342 : : ð_addr);
343 : 0 : ether_addr_dump(" tha=", ð_addr);
344 : 0 : ip_addr = arp_h->arp_data.arp_tip;
345 : 0 : ipv4_addr_dump(" tip=", ip_addr);
346 : : printf("\n");
347 : : }
348 : 0 : if (arp_op != RTE_ARP_OP_REQUEST) {
349 : 0 : rte_pktmbuf_free(pkt);
350 : 0 : continue;
351 : : }
352 : :
353 : : /*
354 : : * Build ARP reply.
355 : : */
356 : :
357 : : /* Use source MAC address as destination MAC address. */
358 : : rte_ether_addr_copy(ð_h->src_addr, ð_h->dst_addr);
359 : : /* Set source MAC address with MAC address of TX port */
360 : 0 : rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
361 : : ð_h->src_addr);
362 : :
363 : 0 : 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 : : ð_addr);
366 : : rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
367 : : &arp_h->arp_data.arp_tha);
368 : : rte_ether_addr_copy(ð_h->src_addr,
369 : : &arp_h->arp_data.arp_sha);
370 : :
371 : : /* Swap IP addresses in ARP payload */
372 : 0 : ip_addr = arp_h->arp_data.arp_sip;
373 : 0 : arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip;
374 : 0 : arp_h->arp_data.arp_tip = ip_addr;
375 : 0 : pkts_burst[nb_replies++] = pkt;
376 : 0 : continue;
377 : : }
378 : :
379 : 0 : if (eth_type != RTE_ETHER_TYPE_IPV4) {
380 : 0 : rte_pktmbuf_free(pkt);
381 : 0 : continue;
382 : : }
383 : 0 : ip_h = (struct rte_ipv4_hdr *) ((char *)eth_h + l2_len);
384 : 0 : if (verbose_level > 0) {
385 : 0 : ipv4_addr_dump(" IPV4: src=", ip_h->src_addr);
386 : 0 : ipv4_addr_dump(" dst=", ip_h->dst_addr);
387 : 0 : printf(" proto=%d (%s)\n",
388 : : ip_h->next_proto_id,
389 : 0 : 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 : 0 : if (! ((ip_h->next_proto_id == IPPROTO_ICMP) &&
398 : 0 : (icmp_h->icmp_type == RTE_ICMP_TYPE_ECHO_REQUEST) &&
399 : 0 : (icmp_h->icmp_code == 0))) {
400 : 0 : rte_pktmbuf_free(pkt);
401 : 0 : continue;
402 : : }
403 : :
404 : 0 : if (verbose_level > 0)
405 : 0 : printf(" ICMP: echo request seq id=%d\n",
406 : 0 : 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(ð_h->src_addr, ð_addr);
427 : : rte_ether_addr_copy(ð_h->dst_addr, ð_h->src_addr);
428 : : rte_ether_addr_copy(ð_addr, ð_h->dst_addr);
429 : 0 : ip_addr = ip_h->src_addr;
430 : 0 : if (is_multicast_ipv4_addr(ip_h->dst_addr)) {
431 : : uint32_t ip_src;
432 : :
433 : 0 : ip_src = rte_be_to_cpu_32(ip_addr);
434 : 0 : if ((ip_src & 0x00000003) == 1)
435 : 0 : ip_src = (ip_src & 0xFFFFFFFC) | 0x00000002;
436 : : else
437 : 0 : ip_src = (ip_src & 0xFFFFFFFC) | 0x00000001;
438 : 0 : ip_h->src_addr = rte_cpu_to_be_32(ip_src);
439 : 0 : ip_h->dst_addr = ip_addr;
440 : 0 : ip_h->hdr_checksum = rte_ipv4_cksum_simple(ip_h);
441 : : } else {
442 : 0 : ip_h->src_addr = ip_h->dst_addr;
443 : 0 : ip_h->dst_addr = ip_addr;
444 : : }
445 : 0 : icmp_h->icmp_type = RTE_ICMP_TYPE_ECHO_REPLY;
446 : 0 : cksum = ~icmp_h->icmp_cksum & 0xffff;
447 : 0 : cksum += ~RTE_BE16(RTE_ICMP_TYPE_ECHO_REQUEST << 8) & 0xffff;
448 : : cksum += RTE_BE16(RTE_ICMP_TYPE_ECHO_REPLY << 8);
449 : 0 : cksum = (cksum & 0xffff) + (cksum >> 16);
450 : 0 : cksum = (cksum & 0xffff) + (cksum >> 16);
451 : 0 : icmp_h->icmp_cksum = ~cksum;
452 : 0 : pkts_burst[nb_replies++] = pkt;
453 : : }
454 : :
455 : : /* Send back ICMP echo replies, if any. */
456 : 0 : if (nb_replies > 0)
457 : 0 : 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 : : };
|