1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2013 6WIND 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of 6WIND S.A. nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35 #include <stdarg.h> 36 #include <string.h> 37 #include <stdio.h> 38 #include <errno.h> 39 #include <stdint.h> 40 #include <unistd.h> 41 #include <inttypes.h> 42 43 #include <sys/queue.h> 44 #include <sys/stat.h> 45 46 #include <rte_common.h> 47 #include <rte_byteorder.h> 48 #include <rte_log.h> 49 #include <rte_debug.h> 50 #include <rte_cycles.h> 51 #include <rte_per_lcore.h> 52 #include <rte_lcore.h> 53 #include <rte_atomic.h> 54 #include <rte_branch_prediction.h> 55 #include <rte_ring.h> 56 #include <rte_memory.h> 57 #include <rte_mempool.h> 58 #include <rte_mbuf.h> 59 #include <rte_ether.h> 60 #include <rte_ethdev.h> 61 #include <rte_arp.h> 62 #include <rte_ip.h> 63 #include <rte_icmp.h> 64 #include <rte_string_fns.h> 65 66 #include "testpmd.h" 67 68 static const char * 69 arp_op_name(uint16_t arp_op) 70 { 71 switch (arp_op ) { 72 case ARP_OP_REQUEST: 73 return "ARP Request"; 74 case ARP_OP_REPLY: 75 return "ARP Reply"; 76 case ARP_OP_REVREQUEST: 77 return "Reverse ARP Request"; 78 case ARP_OP_REVREPLY: 79 return "Reverse ARP Reply"; 80 case ARP_OP_INVREQUEST: 81 return "Peer Identify Request"; 82 case ARP_OP_INVREPLY: 83 return "Peer Identify Reply"; 84 default: 85 break; 86 } 87 return "Unkwown ARP op"; 88 } 89 90 static const char * 91 ip_proto_name(uint8_t ip_proto) 92 { 93 static const char * ip_proto_names[] = { 94 "IP6HOPOPTS", /**< IP6 hop-by-hop options */ 95 "ICMP", /**< control message protocol */ 96 "IGMP", /**< group mgmt protocol */ 97 "GGP", /**< gateway^2 (deprecated) */ 98 "IPv4", /**< IPv4 encapsulation */ 99 100 "UNASSIGNED", 101 "TCP", /**< transport control protocol */ 102 "ST", /**< Stream protocol II */ 103 "EGP", /**< exterior gateway protocol */ 104 "PIGP", /**< private interior gateway */ 105 106 "RCC_MON", /**< BBN RCC Monitoring */ 107 "NVPII", /**< network voice protocol*/ 108 "PUP", /**< pup */ 109 "ARGUS", /**< Argus */ 110 "EMCON", /**< EMCON */ 111 112 "XNET", /**< Cross Net Debugger */ 113 "CHAOS", /**< Chaos*/ 114 "UDP", /**< user datagram protocol */ 115 "MUX", /**< Multiplexing */ 116 "DCN_MEAS", /**< DCN Measurement Subsystems */ 117 118 "HMP", /**< Host Monitoring */ 119 "PRM", /**< Packet Radio Measurement */ 120 "XNS_IDP", /**< xns idp */ 121 "TRUNK1", /**< Trunk-1 */ 122 "TRUNK2", /**< Trunk-2 */ 123 124 "LEAF1", /**< Leaf-1 */ 125 "LEAF2", /**< Leaf-2 */ 126 "RDP", /**< Reliable Data */ 127 "IRTP", /**< Reliable Transaction */ 128 "TP4", /**< tp-4 w/ class negotiation */ 129 130 "BLT", /**< Bulk Data Transfer */ 131 "NSP", /**< Network Services */ 132 "INP", /**< Merit Internodal */ 133 "SEP", /**< Sequential Exchange */ 134 "3PC", /**< Third Party Connect */ 135 136 "IDPR", /**< InterDomain Policy Routing */ 137 "XTP", /**< XTP */ 138 "DDP", /**< Datagram Delivery */ 139 "CMTP", /**< Control Message Transport */ 140 "TPXX", /**< TP++ Transport */ 141 142 "ILTP", /**< IL transport protocol */ 143 "IPv6_HDR", /**< IP6 header */ 144 "SDRP", /**< Source Demand Routing */ 145 "IPv6_RTG", /**< IP6 routing header */ 146 "IPv6_FRAG", /**< IP6 fragmentation header */ 147 148 "IDRP", /**< InterDomain Routing*/ 149 "RSVP", /**< resource reservation */ 150 "GRE", /**< General Routing Encap. */ 151 "MHRP", /**< Mobile Host Routing */ 152 "BHA", /**< BHA */ 153 154 "ESP", /**< IP6 Encap Sec. Payload */ 155 "AH", /**< IP6 Auth Header */ 156 "INLSP", /**< Integ. Net Layer Security */ 157 "SWIPE", /**< IP with encryption */ 158 "NHRP", /**< Next Hop Resolution */ 159 160 "UNASSIGNED", 161 "UNASSIGNED", 162 "UNASSIGNED", 163 "ICMPv6", /**< ICMP6 */ 164 "IPv6NONEXT", /**< IP6 no next header */ 165 166 "Ipv6DSTOPTS",/**< IP6 destination option */ 167 "AHIP", /**< any host internal protocol */ 168 "CFTP", /**< CFTP */ 169 "HELLO", /**< "hello" routing protocol */ 170 "SATEXPAK", /**< SATNET/Backroom EXPAK */ 171 172 "KRYPTOLAN", /**< Kryptolan */ 173 "RVD", /**< Remote Virtual Disk */ 174 "IPPC", /**< Pluribus Packet Core */ 175 "ADFS", /**< Any distributed FS */ 176 "SATMON", /**< Satnet Monitoring */ 177 178 "VISA", /**< VISA Protocol */ 179 "IPCV", /**< Packet Core Utility */ 180 "CPNX", /**< Comp. Prot. Net. Executive */ 181 "CPHB", /**< Comp. Prot. HeartBeat */ 182 "WSN", /**< Wang Span Network */ 183 184 "PVP", /**< Packet Video Protocol */ 185 "BRSATMON", /**< BackRoom SATNET Monitoring */ 186 "ND", /**< Sun net disk proto (temp.) */ 187 "WBMON", /**< WIDEBAND Monitoring */ 188 "WBEXPAK", /**< WIDEBAND EXPAK */ 189 190 "EON", /**< ISO cnlp */ 191 "VMTP", /**< VMTP */ 192 "SVMTP", /**< Secure VMTP */ 193 "VINES", /**< Banyon VINES */ 194 "TTP", /**< TTP */ 195 196 "IGP", /**< NSFNET-IGP */ 197 "DGP", /**< dissimilar gateway prot. */ 198 "TCF", /**< TCF */ 199 "IGRP", /**< Cisco/GXS IGRP */ 200 "OSPFIGP", /**< OSPFIGP */ 201 202 "SRPC", /**< Strite RPC protocol */ 203 "LARP", /**< Locus Address Resoloution */ 204 "MTP", /**< Multicast Transport */ 205 "AX25", /**< AX.25 Frames */ 206 "4IN4", /**< IP encapsulated in IP */ 207 208 "MICP", /**< Mobile Int.ing control */ 209 "SCCSP", /**< Semaphore Comm. security */ 210 "ETHERIP", /**< Ethernet IP encapsulation */ 211 "ENCAP", /**< encapsulation header */ 212 "AES", /**< any private encr. scheme */ 213 214 "GMTP", /**< GMTP */ 215 "IPCOMP", /**< payload compression (IPComp) */ 216 "UNASSIGNED", 217 "UNASSIGNED", 218 "PIM", /**< Protocol Independent Mcast */ 219 }; 220 221 if (ip_proto < sizeof(ip_proto_names) / sizeof(ip_proto_names[0])) 222 return ip_proto_names[ip_proto]; 223 switch (ip_proto) { 224 case IPPROTO_PGM: /**< PGM */ 225 return "PGM"; 226 case IPPROTO_SCTP: /**< Stream Control Transport Protocol */ 227 return "SCTP"; 228 case IPPROTO_DIVERT: /**< divert pseudo-protocol */ 229 return "DIVERT"; 230 case IPPROTO_RAW: /**< raw IP packet */ 231 return "RAW"; 232 default: 233 break; 234 } 235 return "UNASSIGNED"; 236 } 237 238 static void 239 ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf) 240 { 241 uint32_t ipv4_addr; 242 243 ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr); 244 sprintf(buf, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF, 245 (ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF, 246 ipv4_addr & 0xFF); 247 } 248 249 static void 250 ether_addr_dump(const char *what, const struct ether_addr *ea) 251 { 252 char buf[ETHER_ADDR_FMT_SIZE]; 253 254 ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, ea); 255 if (what) 256 printf("%s", what); 257 printf("%s", buf); 258 } 259 260 static void 261 ipv4_addr_dump(const char *what, uint32_t be_ipv4_addr) 262 { 263 char buf[16]; 264 265 ipv4_addr_to_dot(be_ipv4_addr, buf); 266 if (what) 267 printf("%s", what); 268 printf("%s", buf); 269 } 270 271 /* 272 * Receive a burst of packets, lookup for ICMP echo requets, and, if any, 273 * send back ICMP echo replies. 274 */ 275 static void 276 reply_to_icmp_echo_rqsts(struct fwd_stream *fs) 277 { 278 struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 279 struct rte_mbuf *pkt; 280 struct ether_hdr *eth_h; 281 struct vlan_hdr *vlan_h; 282 struct arp_hdr *arp_h; 283 struct ipv4_hdr *ip_h; 284 struct icmp_hdr *icmp_h; 285 struct ether_addr eth_addr; 286 uint32_t ip_addr; 287 uint16_t nb_rx; 288 uint16_t nb_tx; 289 uint16_t nb_replies; 290 uint16_t eth_type; 291 uint16_t vlan_id; 292 uint16_t arp_op; 293 uint16_t arp_pro; 294 uint8_t i; 295 int l2_len; 296 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES 297 uint64_t start_tsc; 298 uint64_t end_tsc; 299 uint64_t core_cycles; 300 #endif 301 302 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES 303 start_tsc = rte_rdtsc(); 304 #endif 305 306 /* 307 * First, receive a burst of packets. 308 */ 309 nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst, 310 nb_pkt_per_burst); 311 if (unlikely(nb_rx == 0)) 312 return; 313 314 #ifdef RTE_TEST_PMD_RECORD_BURST_STATS 315 fs->rx_burst_stats.pkt_burst_spread[nb_rx]++; 316 #endif 317 fs->rx_packets += nb_rx; 318 nb_replies = 0; 319 for (i = 0; i < nb_rx; i++) { 320 pkt = pkts_burst[i]; 321 eth_h = rte_pktmbuf_mtod(pkt, struct ether_hdr *); 322 eth_type = RTE_BE_TO_CPU_16(eth_h->ether_type); 323 l2_len = sizeof(struct ether_hdr); 324 if (verbose_level > 0) { 325 printf("\nPort %d pkt-len=%u nb-segs=%u\n", 326 fs->rx_port, pkt->pkt_len, pkt->nb_segs); 327 ether_addr_dump(" ETH: src=", ð_h->s_addr); 328 ether_addr_dump(" dst=", ð_h->d_addr); 329 } 330 if (eth_type == ETHER_TYPE_VLAN) { 331 vlan_h = (struct vlan_hdr *) 332 ((char *)eth_h + sizeof(struct ether_hdr)); 333 l2_len += sizeof(struct vlan_hdr); 334 eth_type = rte_be_to_cpu_16(vlan_h->eth_proto); 335 if (verbose_level > 0) { 336 vlan_id = rte_be_to_cpu_16(vlan_h->vlan_tci) 337 & 0xFFF; 338 printf(" [vlan id=%u]", vlan_id); 339 } 340 } 341 if (verbose_level > 0) { 342 printf(" type=0x%04x\n", eth_type); 343 } 344 345 /* Reply to ARP requests */ 346 if (eth_type == ETHER_TYPE_ARP) { 347 arp_h = (struct arp_hdr *) ((char *)eth_h + l2_len); 348 arp_op = RTE_BE_TO_CPU_16(arp_h->arp_op); 349 arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_pro); 350 if (verbose_level > 0) { 351 printf(" ARP: hrd=%d proto=0x%04x hln=%d " 352 "pln=%d op=%u (%s)\n", 353 RTE_BE_TO_CPU_16(arp_h->arp_hrd), 354 arp_pro, arp_h->arp_hln, 355 arp_h->arp_pln, arp_op, 356 arp_op_name(arp_op)); 357 } 358 if ((RTE_BE_TO_CPU_16(arp_h->arp_hrd) != 359 ARP_HRD_ETHER) || 360 (arp_pro != ETHER_TYPE_IPv4) || 361 (arp_h->arp_hln != 6) || 362 (arp_h->arp_pln != 4) 363 ) { 364 rte_pktmbuf_free(pkt); 365 if (verbose_level > 0) 366 printf("\n"); 367 continue; 368 } 369 if (verbose_level > 0) { 370 memcpy(ð_addr, 371 arp_h->arp_data.arp_ip.arp_sha, 6); 372 ether_addr_dump(" sha=", ð_addr); 373 memcpy(&ip_addr, 374 arp_h->arp_data.arp_ip.arp_sip, 4); 375 ipv4_addr_dump(" sip=", ip_addr); 376 printf("\n"); 377 memcpy(ð_addr, 378 arp_h->arp_data.arp_ip.arp_tha, 6); 379 ether_addr_dump(" tha=", ð_addr); 380 memcpy(&ip_addr, 381 arp_h->arp_data.arp_ip.arp_tip, 4); 382 ipv4_addr_dump(" tip=", ip_addr); 383 printf("\n"); 384 } 385 if (arp_op != ARP_OP_REQUEST) { 386 rte_pktmbuf_free(pkt); 387 continue; 388 } 389 390 /* 391 * Build ARP reply. 392 */ 393 394 /* Use source MAC address as destination MAC address. */ 395 ether_addr_copy(ð_h->s_addr, ð_h->d_addr); 396 /* Set source MAC address with MAC address of TX port */ 397 ether_addr_copy(&ports[fs->tx_port].eth_addr, 398 ð_h->s_addr); 399 400 arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY); 401 memcpy(ð_addr, arp_h->arp_data.arp_ip.arp_tha, 6); 402 memcpy(arp_h->arp_data.arp_ip.arp_tha, 403 arp_h->arp_data.arp_ip.arp_sha, 6); 404 memcpy(arp_h->arp_data.arp_ip.arp_sha, 405 ð_h->s_addr, 6); 406 407 /* Swap IP addresses in ARP payload */ 408 memcpy(&ip_addr, arp_h->arp_data.arp_ip.arp_sip, 4); 409 memcpy(arp_h->arp_data.arp_ip.arp_sip, 410 arp_h->arp_data.arp_ip.arp_tip, 4); 411 memcpy(arp_h->arp_data.arp_ip.arp_tip, &ip_addr, 4); 412 pkts_burst[nb_replies++] = pkt; 413 continue; 414 } 415 416 if (eth_type != ETHER_TYPE_IPv4) { 417 rte_pktmbuf_free(pkt); 418 continue; 419 } 420 ip_h = (struct ipv4_hdr *) ((char *)eth_h + l2_len); 421 if (verbose_level > 0) { 422 ipv4_addr_dump(" IPV4: src=", ip_h->src_addr); 423 ipv4_addr_dump(" dst=", ip_h->dst_addr); 424 printf(" proto=%d (%s)\n", 425 ip_h->next_proto_id, 426 ip_proto_name(ip_h->next_proto_id)); 427 } 428 429 /* 430 * Check if packet is a ICMP echo request. 431 */ 432 icmp_h = (struct icmp_hdr *) ((char *)ip_h + 433 sizeof(struct ipv4_hdr)); 434 if (! ((ip_h->next_proto_id == IPPROTO_ICMP) && 435 (icmp_h->icmp_type == IP_ICMP_ECHO_REQUEST) && 436 (icmp_h->icmp_code == 0))) { 437 rte_pktmbuf_free(pkt); 438 continue; 439 } 440 441 if (verbose_level > 0) 442 printf(" ICMP: echo request seq id=%d\n", 443 rte_be_to_cpu_16(icmp_h->icmp_seq_nb)); 444 445 /* 446 * Prepare ICMP echo reply to be sent back. 447 * - switch ethernet source and destinations addresses, 448 * - switch IPv4 source and destinations addresses, 449 * - set IP_ICMP_ECHO_REPLY in ICMP header. 450 * No need to re-compute the IP header checksum. 451 * Reset ICMP checksum. 452 */ 453 ether_addr_copy(ð_h->s_addr, ð_addr); 454 ether_addr_copy(ð_h->d_addr, ð_h->s_addr); 455 ether_addr_copy(ð_addr, ð_h->d_addr); 456 ip_addr = ip_h->src_addr; 457 ip_h->src_addr = ip_h->dst_addr; 458 ip_h->dst_addr = ip_addr; 459 icmp_h->icmp_type = IP_ICMP_ECHO_REPLY; 460 icmp_h->icmp_cksum = 0; 461 pkts_burst[nb_replies++] = pkt; 462 } 463 464 /* Send back ICMP echo replies, if any. */ 465 if (nb_replies > 0) { 466 nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, 467 nb_replies); 468 fs->tx_packets += nb_tx; 469 #ifdef RTE_TEST_PMD_RECORD_BURST_STATS 470 fs->tx_burst_stats.pkt_burst_spread[nb_tx]++; 471 #endif 472 if (unlikely(nb_tx < nb_replies)) { 473 fs->fwd_dropped += (nb_replies - nb_tx); 474 do { 475 rte_pktmbuf_free(pkts_burst[nb_tx]); 476 } while (++nb_tx < nb_replies); 477 } 478 } 479 480 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES 481 end_tsc = rte_rdtsc(); 482 core_cycles = (end_tsc - start_tsc); 483 fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles); 484 #endif 485 } 486 487 struct fwd_engine icmp_echo_engine = { 488 .fwd_mode_name = "icmpecho", 489 .port_fwd_begin = NULL, 490 .port_fwd_end = NULL, 491 .packet_fwd = reply_to_icmp_echo_rqsts, 492 }; 493