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