1 /* 2 * Copyright 2013 Red Hat, Inc. 3 * Author: Daniel Borkmann <dborkman (at) redhat.com> 4 * Chetan Loke <loke.chetan (at) gmail.com> (TPACKET_V3 usage example) 5 * 6 * A basic test of packet socket's TPACKET_V1/TPACKET_V2/TPACKET_V3 behavior. 7 * 8 * Control: 9 * Test the setup of the TPACKET socket with different patterns that are 10 * known to fail (TODO) resp. succeed (OK). 11 * 12 * Datapath: 13 * Open a pair of packet sockets and send resp. receive an a priori known 14 * packet pattern accross the sockets and check if it was received resp. 15 * sent correctly. Fanout in combination with RX_RING is currently not 16 * tested here. 17 * 18 * The test currently runs for 19 * - TPACKET_V1: RX_RING, TX_RING 20 * - TPACKET_V2: RX_RING, TX_RING 21 * - TPACKET_V3: RX_RING 22 * 23 * License (GPLv2): 24 * 25 * This program is free software; you can redistribute it and/or modify it 26 * under the terms and conditions of the GNU General Public License, 27 * version 2, as published by the Free Software Foundation. 28 * 29 * This program is distributed in the hope it will be useful, but WITHOUT 30 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 31 * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for 32 * more details. 33 * 34 * You should have received a copy of the GNU General Public License along with 35 * this program; if not, write to the Free Software Foundation, Inc., 36 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 37 */ 38 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <sys/socket.h> 44 #include <sys/mman.h> 45 #include <sys/utsname.h> 46 #include <linux/if_packet.h> 47 #include <linux/filter.h> 48 #include <ctype.h> 49 #include <fcntl.h> 50 #include <unistd.h> 51 #ifndef __ANDROID__ 52 #include <bits/wordsize.h> 53 #endif 54 #include <net/ethernet.h> 55 #include <netinet/ip.h> 56 #include <arpa/inet.h> 57 #include <stdint.h> 58 #include <string.h> 59 #include <assert.h> 60 #include <net/if.h> 61 #include <inttypes.h> 62 #include <poll.h> 63 64 #include "psock_lib.h" 65 66 #include "../kselftest.h" 67 68 #ifndef bug_on 69 # define bug_on(cond) assert(!(cond)) 70 #endif 71 72 #ifndef __aligned_tpacket 73 # define __aligned_tpacket __attribute__((aligned(TPACKET_ALIGNMENT))) 74 #endif 75 76 #ifndef __align_tpacket 77 # define __align_tpacket(x) __attribute__((aligned(TPACKET_ALIGN(x)))) 78 #endif 79 80 #define NUM_PACKETS 100 81 #define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1)) 82 83 struct ring { 84 struct iovec *rd; 85 uint8_t *mm_space; 86 size_t mm_len, rd_len; 87 struct sockaddr_ll ll; 88 void (*walk)(int sock, struct ring *ring); 89 int type, rd_num, flen, version; 90 union { 91 struct tpacket_req req; 92 struct tpacket_req3 req3; 93 }; 94 }; 95 96 struct block_desc { 97 uint32_t version; 98 uint32_t offset_to_priv; 99 struct tpacket_hdr_v1 h1; 100 }; 101 102 union frame_map { 103 struct { 104 struct tpacket_hdr tp_h __aligned_tpacket; 105 struct sockaddr_ll s_ll __align_tpacket(sizeof(struct tpacket_hdr)); 106 } *v1; 107 struct { 108 struct tpacket2_hdr tp_h __aligned_tpacket; 109 struct sockaddr_ll s_ll __align_tpacket(sizeof(struct tpacket2_hdr)); 110 } *v2; 111 void *raw; 112 }; 113 114 static unsigned int total_packets, total_bytes; 115 116 static int pfsocket(int ver) 117 { 118 int ret, sock = socket(PF_PACKET, SOCK_RAW, 0); 119 if (sock == -1) { 120 perror("socket"); 121 exit(1); 122 } 123 124 ret = setsockopt(sock, SOL_PACKET, PACKET_VERSION, &ver, sizeof(ver)); 125 if (ret == -1) { 126 perror("setsockopt"); 127 exit(1); 128 } 129 130 return sock; 131 } 132 133 static void status_bar_update(void) 134 { 135 if (total_packets % 10 == 0) { 136 fprintf(stderr, "."); 137 fflush(stderr); 138 } 139 } 140 141 static void test_payload(void *pay, size_t len) 142 { 143 struct ethhdr *eth = pay; 144 145 if (len < sizeof(struct ethhdr)) { 146 fprintf(stderr, "test_payload: packet too " 147 "small: %zu bytes!\n", len); 148 exit(1); 149 } 150 151 if (eth->h_proto != htons(ETH_P_IP)) { 152 fprintf(stderr, "test_payload: wrong ethernet " 153 "type: 0x%x!\n", ntohs(eth->h_proto)); 154 exit(1); 155 } 156 } 157 158 static void create_payload(void *pay, size_t *len) 159 { 160 int i; 161 struct ethhdr *eth = pay; 162 struct iphdr *ip = pay + sizeof(*eth); 163 164 /* Lets create some broken crap, that still passes 165 * our BPF filter. 166 */ 167 168 *len = DATA_LEN + 42; 169 170 memset(pay, 0xff, ETH_ALEN * 2); 171 eth->h_proto = htons(ETH_P_IP); 172 173 for (i = 0; i < sizeof(*ip); ++i) 174 ((uint8_t *) pay)[i + sizeof(*eth)] = (uint8_t) rand(); 175 176 ip->ihl = 5; 177 ip->version = 4; 178 ip->protocol = 0x11; 179 ip->frag_off = 0; 180 ip->ttl = 64; 181 ip->tot_len = htons((uint16_t) *len - sizeof(*eth)); 182 183 ip->saddr = htonl(INADDR_LOOPBACK); 184 ip->daddr = htonl(INADDR_LOOPBACK); 185 186 memset(pay + sizeof(*eth) + sizeof(*ip), 187 DATA_CHAR, DATA_LEN); 188 } 189 190 static inline int __v1_rx_kernel_ready(struct tpacket_hdr *hdr) 191 { 192 return ((hdr->tp_status & TP_STATUS_USER) == TP_STATUS_USER); 193 } 194 195 static inline void __v1_rx_user_ready(struct tpacket_hdr *hdr) 196 { 197 hdr->tp_status = TP_STATUS_KERNEL; 198 __sync_synchronize(); 199 } 200 201 static inline int __v2_rx_kernel_ready(struct tpacket2_hdr *hdr) 202 { 203 return ((hdr->tp_status & TP_STATUS_USER) == TP_STATUS_USER); 204 } 205 206 static inline void __v2_rx_user_ready(struct tpacket2_hdr *hdr) 207 { 208 hdr->tp_status = TP_STATUS_KERNEL; 209 __sync_synchronize(); 210 } 211 212 static inline int __v1_v2_rx_kernel_ready(void *base, int version) 213 { 214 switch (version) { 215 case TPACKET_V1: 216 return __v1_rx_kernel_ready(base); 217 case TPACKET_V2: 218 return __v2_rx_kernel_ready(base); 219 default: 220 bug_on(1); 221 return 0; 222 } 223 } 224 225 static inline void __v1_v2_rx_user_ready(void *base, int version) 226 { 227 switch (version) { 228 case TPACKET_V1: 229 __v1_rx_user_ready(base); 230 break; 231 case TPACKET_V2: 232 __v2_rx_user_ready(base); 233 break; 234 } 235 } 236 237 static void walk_v1_v2_rx(int sock, struct ring *ring) 238 { 239 struct pollfd pfd; 240 int udp_sock[2]; 241 union frame_map ppd; 242 unsigned int frame_num = 0; 243 244 bug_on(ring->type != PACKET_RX_RING); 245 246 pair_udp_open(udp_sock, PORT_BASE); 247 248 memset(&pfd, 0, sizeof(pfd)); 249 pfd.fd = sock; 250 pfd.events = POLLIN | POLLERR; 251 pfd.revents = 0; 252 253 pair_udp_send(udp_sock, NUM_PACKETS); 254 255 while (total_packets < NUM_PACKETS * 2) { 256 while (__v1_v2_rx_kernel_ready(ring->rd[frame_num].iov_base, 257 ring->version)) { 258 ppd.raw = ring->rd[frame_num].iov_base; 259 260 switch (ring->version) { 261 case TPACKET_V1: 262 test_payload((uint8_t *) ppd.raw + ppd.v1->tp_h.tp_mac, 263 ppd.v1->tp_h.tp_snaplen); 264 total_bytes += ppd.v1->tp_h.tp_snaplen; 265 break; 266 267 case TPACKET_V2: 268 test_payload((uint8_t *) ppd.raw + ppd.v2->tp_h.tp_mac, 269 ppd.v2->tp_h.tp_snaplen); 270 total_bytes += ppd.v2->tp_h.tp_snaplen; 271 break; 272 } 273 274 status_bar_update(); 275 total_packets++; 276 277 __v1_v2_rx_user_ready(ppd.raw, ring->version); 278 279 frame_num = (frame_num + 1) % ring->rd_num; 280 } 281 282 poll(&pfd, 1, 1); 283 } 284 285 pair_udp_close(udp_sock); 286 287 if (total_packets != 2 * NUM_PACKETS) { 288 fprintf(stderr, "walk_v%d_rx: received %u out of %u pkts\n", 289 ring->version, total_packets, NUM_PACKETS); 290 exit(1); 291 } 292 293 fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, total_bytes >> 1); 294 } 295 296 static inline int __v1_tx_kernel_ready(struct tpacket_hdr *hdr) 297 { 298 return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING)); 299 } 300 301 static inline void __v1_tx_user_ready(struct tpacket_hdr *hdr) 302 { 303 hdr->tp_status = TP_STATUS_SEND_REQUEST; 304 __sync_synchronize(); 305 } 306 307 static inline int __v2_tx_kernel_ready(struct tpacket2_hdr *hdr) 308 { 309 return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING)); 310 } 311 312 static inline void __v2_tx_user_ready(struct tpacket2_hdr *hdr) 313 { 314 hdr->tp_status = TP_STATUS_SEND_REQUEST; 315 __sync_synchronize(); 316 } 317 318 static inline int __v3_tx_kernel_ready(struct tpacket3_hdr *hdr) 319 { 320 return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING)); 321 } 322 323 static inline void __v3_tx_user_ready(struct tpacket3_hdr *hdr) 324 { 325 hdr->tp_status = TP_STATUS_SEND_REQUEST; 326 __sync_synchronize(); 327 } 328 329 static inline int __tx_kernel_ready(void *base, int version) 330 { 331 switch (version) { 332 case TPACKET_V1: 333 return __v1_tx_kernel_ready(base); 334 case TPACKET_V2: 335 return __v2_tx_kernel_ready(base); 336 case TPACKET_V3: 337 return __v3_tx_kernel_ready(base); 338 default: 339 bug_on(1); 340 return 0; 341 } 342 } 343 344 static inline void __tx_user_ready(void *base, int version) 345 { 346 switch (version) { 347 case TPACKET_V1: 348 __v1_tx_user_ready(base); 349 break; 350 case TPACKET_V2: 351 __v2_tx_user_ready(base); 352 break; 353 case TPACKET_V3: 354 __v3_tx_user_ready(base); 355 break; 356 } 357 } 358 359 static void __v1_v2_set_packet_loss_discard(int sock) 360 { 361 int ret, discard = 1; 362 363 ret = setsockopt(sock, SOL_PACKET, PACKET_LOSS, (void *) &discard, 364 sizeof(discard)); 365 if (ret == -1) { 366 perror("setsockopt"); 367 exit(1); 368 } 369 } 370 371 static inline void *get_next_frame(struct ring *ring, int n) 372 { 373 uint8_t *f0 = ring->rd[0].iov_base; 374 375 switch (ring->version) { 376 case TPACKET_V1: 377 case TPACKET_V2: 378 return ring->rd[n].iov_base; 379 case TPACKET_V3: 380 return f0 + (n * ring->req3.tp_frame_size); 381 default: 382 bug_on(1); 383 return NULL; 384 } 385 } 386 387 static void walk_tx(int sock, struct ring *ring) 388 { 389 struct pollfd pfd; 390 int rcv_sock, ret; 391 size_t packet_len; 392 union frame_map ppd; 393 char packet[1024]; 394 unsigned int frame_num = 0, got = 0; 395 struct sockaddr_ll ll = { 396 .sll_family = PF_PACKET, 397 .sll_halen = ETH_ALEN, 398 }; 399 int nframes; 400 401 /* TPACKET_V{1,2} sets up the ring->rd* related variables based 402 * on frames (e.g., rd_num is tp_frame_nr) whereas V3 sets these 403 * up based on blocks (e.g, rd_num is tp_block_nr) 404 */ 405 if (ring->version <= TPACKET_V2) 406 nframes = ring->rd_num; 407 else 408 nframes = ring->req3.tp_frame_nr; 409 410 bug_on(ring->type != PACKET_TX_RING); 411 bug_on(nframes < NUM_PACKETS); 412 413 rcv_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 414 if (rcv_sock == -1) { 415 perror("socket"); 416 exit(1); 417 } 418 419 pair_udp_setfilter(rcv_sock); 420 421 ll.sll_ifindex = if_nametoindex("lo"); 422 ret = bind(rcv_sock, (struct sockaddr *) &ll, sizeof(ll)); 423 if (ret == -1) { 424 perror("bind"); 425 exit(1); 426 } 427 428 memset(&pfd, 0, sizeof(pfd)); 429 pfd.fd = sock; 430 pfd.events = POLLOUT | POLLERR; 431 pfd.revents = 0; 432 433 total_packets = NUM_PACKETS; 434 create_payload(packet, &packet_len); 435 436 while (total_packets > 0) { 437 void *next = get_next_frame(ring, frame_num); 438 439 while (__tx_kernel_ready(next, ring->version) && 440 total_packets > 0) { 441 ppd.raw = next; 442 443 switch (ring->version) { 444 case TPACKET_V1: 445 ppd.v1->tp_h.tp_snaplen = packet_len; 446 ppd.v1->tp_h.tp_len = packet_len; 447 448 memcpy((uint8_t *) ppd.raw + TPACKET_HDRLEN - 449 sizeof(struct sockaddr_ll), packet, 450 packet_len); 451 total_bytes += ppd.v1->tp_h.tp_snaplen; 452 break; 453 454 case TPACKET_V2: 455 ppd.v2->tp_h.tp_snaplen = packet_len; 456 ppd.v2->tp_h.tp_len = packet_len; 457 458 memcpy((uint8_t *) ppd.raw + TPACKET2_HDRLEN - 459 sizeof(struct sockaddr_ll), packet, 460 packet_len); 461 total_bytes += ppd.v2->tp_h.tp_snaplen; 462 break; 463 case TPACKET_V3: { 464 struct tpacket3_hdr *tx = next; 465 466 tx->tp_snaplen = packet_len; 467 tx->tp_len = packet_len; 468 tx->tp_next_offset = 0; 469 470 memcpy((uint8_t *)tx + TPACKET3_HDRLEN - 471 sizeof(struct sockaddr_ll), packet, 472 packet_len); 473 total_bytes += tx->tp_snaplen; 474 break; 475 } 476 } 477 478 status_bar_update(); 479 total_packets--; 480 481 __tx_user_ready(next, ring->version); 482 483 frame_num = (frame_num + 1) % nframes; 484 } 485 486 poll(&pfd, 1, 1); 487 } 488 489 bug_on(total_packets != 0); 490 491 ret = sendto(sock, NULL, 0, 0, NULL, 0); 492 if (ret == -1) { 493 perror("sendto"); 494 exit(1); 495 } 496 497 while ((ret = recvfrom(rcv_sock, packet, sizeof(packet), 498 0, NULL, NULL)) > 0 && 499 total_packets < NUM_PACKETS) { 500 got += ret; 501 test_payload(packet, ret); 502 503 status_bar_update(); 504 total_packets++; 505 } 506 507 close(rcv_sock); 508 509 if (total_packets != NUM_PACKETS) { 510 fprintf(stderr, "walk_v%d_rx: received %u out of %u pkts\n", 511 ring->version, total_packets, NUM_PACKETS); 512 exit(1); 513 } 514 515 fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, got); 516 } 517 518 static void walk_v1_v2(int sock, struct ring *ring) 519 { 520 if (ring->type == PACKET_RX_RING) 521 walk_v1_v2_rx(sock, ring); 522 else 523 walk_tx(sock, ring); 524 } 525 526 static uint64_t __v3_prev_block_seq_num = 0; 527 528 void __v3_test_block_seq_num(struct block_desc *pbd) 529 { 530 if (__v3_prev_block_seq_num + 1 != pbd->h1.seq_num) { 531 fprintf(stderr, "\nprev_block_seq_num:%"PRIu64", expected " 532 "seq:%"PRIu64" != actual seq:%"PRIu64"\n", 533 __v3_prev_block_seq_num, __v3_prev_block_seq_num + 1, 534 (uint64_t) pbd->h1.seq_num); 535 exit(1); 536 } 537 538 __v3_prev_block_seq_num = pbd->h1.seq_num; 539 } 540 541 static void __v3_test_block_len(struct block_desc *pbd, uint32_t bytes, int block_num) 542 { 543 if (pbd->h1.num_pkts && bytes != pbd->h1.blk_len) { 544 fprintf(stderr, "\nblock:%u with %upackets, expected " 545 "len:%u != actual len:%u\n", block_num, 546 pbd->h1.num_pkts, bytes, pbd->h1.blk_len); 547 exit(1); 548 } 549 } 550 551 static void __v3_test_block_header(struct block_desc *pbd, const int block_num) 552 { 553 if ((pbd->h1.block_status & TP_STATUS_USER) == 0) { 554 fprintf(stderr, "\nblock %u: not in TP_STATUS_USER\n", block_num); 555 exit(1); 556 } 557 558 __v3_test_block_seq_num(pbd); 559 } 560 561 static void __v3_walk_block(struct block_desc *pbd, const int block_num) 562 { 563 int num_pkts = pbd->h1.num_pkts, i; 564 unsigned long bytes = 0, bytes_with_padding = ALIGN_8(sizeof(*pbd)); 565 struct tpacket3_hdr *ppd; 566 567 __v3_test_block_header(pbd, block_num); 568 569 ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd + 570 pbd->h1.offset_to_first_pkt); 571 572 for (i = 0; i < num_pkts; ++i) { 573 bytes += ppd->tp_snaplen; 574 575 if (ppd->tp_next_offset) 576 bytes_with_padding += ppd->tp_next_offset; 577 else 578 bytes_with_padding += ALIGN_8(ppd->tp_snaplen + ppd->tp_mac); 579 580 test_payload((uint8_t *) ppd + ppd->tp_mac, ppd->tp_snaplen); 581 582 status_bar_update(); 583 total_packets++; 584 585 ppd = (struct tpacket3_hdr *) ((uint8_t *) ppd + ppd->tp_next_offset); 586 __sync_synchronize(); 587 } 588 589 __v3_test_block_len(pbd, bytes_with_padding, block_num); 590 total_bytes += bytes; 591 } 592 593 void __v3_flush_block(struct block_desc *pbd) 594 { 595 pbd->h1.block_status = TP_STATUS_KERNEL; 596 __sync_synchronize(); 597 } 598 599 static void walk_v3_rx(int sock, struct ring *ring) 600 { 601 unsigned int block_num = 0; 602 struct pollfd pfd; 603 struct block_desc *pbd; 604 int udp_sock[2]; 605 606 bug_on(ring->type != PACKET_RX_RING); 607 608 pair_udp_open(udp_sock, PORT_BASE); 609 610 memset(&pfd, 0, sizeof(pfd)); 611 pfd.fd = sock; 612 pfd.events = POLLIN | POLLERR; 613 pfd.revents = 0; 614 615 pair_udp_send(udp_sock, NUM_PACKETS); 616 617 while (total_packets < NUM_PACKETS * 2) { 618 pbd = (struct block_desc *) ring->rd[block_num].iov_base; 619 620 while ((pbd->h1.block_status & TP_STATUS_USER) == 0) 621 poll(&pfd, 1, 1); 622 623 __v3_walk_block(pbd, block_num); 624 __v3_flush_block(pbd); 625 626 block_num = (block_num + 1) % ring->rd_num; 627 } 628 629 pair_udp_close(udp_sock); 630 631 if (total_packets != 2 * NUM_PACKETS) { 632 fprintf(stderr, "walk_v3_rx: received %u out of %u pkts\n", 633 total_packets, NUM_PACKETS); 634 exit(1); 635 } 636 637 fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, total_bytes >> 1); 638 } 639 640 static void walk_v3(int sock, struct ring *ring) 641 { 642 if (ring->type == PACKET_RX_RING) 643 walk_v3_rx(sock, ring); 644 else 645 walk_tx(sock, ring); 646 } 647 648 static void __v1_v2_fill(struct ring *ring, unsigned int blocks) 649 { 650 ring->req.tp_block_size = getpagesize() << 2; 651 ring->req.tp_frame_size = TPACKET_ALIGNMENT << 7; 652 ring->req.tp_block_nr = blocks; 653 654 ring->req.tp_frame_nr = ring->req.tp_block_size / 655 ring->req.tp_frame_size * 656 ring->req.tp_block_nr; 657 658 ring->mm_len = ring->req.tp_block_size * ring->req.tp_block_nr; 659 ring->walk = walk_v1_v2; 660 ring->rd_num = ring->req.tp_frame_nr; 661 ring->flen = ring->req.tp_frame_size; 662 } 663 664 static void __v3_fill(struct ring *ring, unsigned int blocks, int type) 665 { 666 if (type == PACKET_RX_RING) { 667 ring->req3.tp_retire_blk_tov = 64; 668 ring->req3.tp_sizeof_priv = 0; 669 ring->req3.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH; 670 } 671 ring->req3.tp_block_size = getpagesize() << 2; 672 ring->req3.tp_frame_size = TPACKET_ALIGNMENT << 7; 673 ring->req3.tp_block_nr = blocks; 674 675 ring->req3.tp_frame_nr = ring->req3.tp_block_size / 676 ring->req3.tp_frame_size * 677 ring->req3.tp_block_nr; 678 679 ring->mm_len = ring->req3.tp_block_size * ring->req3.tp_block_nr; 680 ring->walk = walk_v3; 681 ring->rd_num = ring->req3.tp_block_nr; 682 ring->flen = ring->req3.tp_block_size; 683 } 684 685 static void setup_ring(int sock, struct ring *ring, int version, int type) 686 { 687 int ret = 0; 688 unsigned int blocks = 256; 689 690 ring->type = type; 691 ring->version = version; 692 693 switch (version) { 694 case TPACKET_V1: 695 case TPACKET_V2: 696 if (type == PACKET_TX_RING) 697 __v1_v2_set_packet_loss_discard(sock); 698 __v1_v2_fill(ring, blocks); 699 ret = setsockopt(sock, SOL_PACKET, type, &ring->req, 700 sizeof(ring->req)); 701 break; 702 703 case TPACKET_V3: 704 __v3_fill(ring, blocks, type); 705 ret = setsockopt(sock, SOL_PACKET, type, &ring->req3, 706 sizeof(ring->req3)); 707 break; 708 } 709 710 if (ret == -1) { 711 perror("setsockopt"); 712 exit(1); 713 } 714 715 ring->rd_len = ring->rd_num * sizeof(*ring->rd); 716 ring->rd = malloc(ring->rd_len); 717 if (ring->rd == NULL) { 718 perror("malloc"); 719 exit(1); 720 } 721 722 total_packets = 0; 723 total_bytes = 0; 724 } 725 726 static void mmap_ring(int sock, struct ring *ring) 727 { 728 int i; 729 730 ring->mm_space = mmap(0, ring->mm_len, PROT_READ | PROT_WRITE, 731 MAP_SHARED | MAP_LOCKED | MAP_POPULATE, sock, 0); 732 if (ring->mm_space == MAP_FAILED) { 733 perror("mmap"); 734 exit(1); 735 } 736 737 memset(ring->rd, 0, ring->rd_len); 738 for (i = 0; i < ring->rd_num; ++i) { 739 ring->rd[i].iov_base = ring->mm_space + (i * ring->flen); 740 ring->rd[i].iov_len = ring->flen; 741 } 742 } 743 744 static void bind_ring(int sock, struct ring *ring) 745 { 746 int ret; 747 748 pair_udp_setfilter(sock); 749 750 ring->ll.sll_family = PF_PACKET; 751 ring->ll.sll_protocol = htons(ETH_P_ALL); 752 ring->ll.sll_ifindex = if_nametoindex("lo"); 753 ring->ll.sll_hatype = 0; 754 ring->ll.sll_pkttype = 0; 755 ring->ll.sll_halen = 0; 756 757 ret = bind(sock, (struct sockaddr *) &ring->ll, sizeof(ring->ll)); 758 if (ret == -1) { 759 perror("bind"); 760 exit(1); 761 } 762 } 763 764 static void walk_ring(int sock, struct ring *ring) 765 { 766 ring->walk(sock, ring); 767 } 768 769 static void unmap_ring(int sock, struct ring *ring) 770 { 771 munmap(ring->mm_space, ring->mm_len); 772 free(ring->rd); 773 } 774 775 static int test_kernel_bit_width(void) 776 { 777 char in[512], *ptr; 778 int num = 0, fd; 779 ssize_t ret; 780 781 fd = open("/proc/kallsyms", O_RDONLY); 782 if (fd == -1) { 783 perror("open"); 784 exit(1); 785 } 786 787 ret = read(fd, in, sizeof(in)); 788 if (ret <= 0) { 789 perror("read"); 790 exit(1); 791 } 792 793 close(fd); 794 795 ptr = in; 796 while(!isspace(*ptr)) { 797 num++; 798 ptr++; 799 } 800 801 return num * 4; 802 } 803 804 static int test_user_bit_width(void) 805 { 806 return __WORDSIZE; 807 } 808 809 static const char *tpacket_str[] = { 810 [TPACKET_V1] = "TPACKET_V1", 811 [TPACKET_V2] = "TPACKET_V2", 812 [TPACKET_V3] = "TPACKET_V3", 813 }; 814 815 static const char *type_str[] = { 816 [PACKET_RX_RING] = "PACKET_RX_RING", 817 [PACKET_TX_RING] = "PACKET_TX_RING", 818 }; 819 820 static int test_tpacket(int version, int type) 821 { 822 int sock; 823 struct ring ring; 824 825 fprintf(stderr, "test: %s with %s ", tpacket_str[version], 826 type_str[type]); 827 fflush(stderr); 828 829 if (version == TPACKET_V1 && 830 test_kernel_bit_width() != test_user_bit_width()) { 831 fprintf(stderr, "test: skip %s %s since user and kernel " 832 "space have different bit width\n", 833 tpacket_str[version], type_str[type]); 834 return KSFT_SKIP; 835 } 836 837 sock = pfsocket(version); 838 memset(&ring, 0, sizeof(ring)); 839 setup_ring(sock, &ring, version, type); 840 mmap_ring(sock, &ring); 841 bind_ring(sock, &ring); 842 walk_ring(sock, &ring); 843 unmap_ring(sock, &ring); 844 close(sock); 845 846 fprintf(stderr, "\n"); 847 return 0; 848 } 849 850 void get_kernel_version(int *version, int *patchlevel) 851 { 852 int ret, sublevel; 853 struct utsname utsname; 854 855 ret = uname(&utsname); 856 if (ret) { 857 perror("uname"); 858 exit(1); 859 } 860 861 ret = sscanf(utsname.release, "%d.%d.%d", version, patchlevel, 862 &sublevel); 863 if (ret < 0) { 864 perror("sscanf"); 865 exit(1); 866 } else if (ret != 3) { 867 printf("Malformed kernel version %s\n", &utsname.release); 868 exit(1); 869 } 870 } 871 872 int main(void) 873 { 874 int ret = 0; 875 int version, patchlevel; 876 877 get_kernel_version(&version, &patchlevel); 878 879 ret |= test_tpacket(TPACKET_V1, PACKET_RX_RING); 880 ret |= test_tpacket(TPACKET_V1, PACKET_TX_RING); 881 882 ret |= test_tpacket(TPACKET_V2, PACKET_RX_RING); 883 ret |= test_tpacket(TPACKET_V2, PACKET_TX_RING); 884 885 ret |= test_tpacket(TPACKET_V3, PACKET_RX_RING); 886 if (version > 4 || (version == 4 && patchlevel >= 11)) 887 ret |= test_tpacket(TPACKET_V3, PACKET_TX_RING); 888 889 if (ret) 890 return 1; 891 892 printf("OK. All tests passed\n"); 893 return 0; 894 } 895