0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include <stdio.h>
0026 #include <stdlib.h>
0027 #include <sys/types.h>
0028 #include <sys/stat.h>
0029 #include <sys/socket.h>
0030 #include <sys/mman.h>
0031 #include <linux/if_packet.h>
0032 #include <linux/filter.h>
0033 #include <ctype.h>
0034 #include <fcntl.h>
0035 #include <unistd.h>
0036 #include <bits/wordsize.h>
0037 #include <net/ethernet.h>
0038 #include <netinet/ip.h>
0039 #include <arpa/inet.h>
0040 #include <stdint.h>
0041 #include <string.h>
0042 #include <assert.h>
0043 #include <net/if.h>
0044 #include <inttypes.h>
0045 #include <poll.h>
0046
0047 #include "psock_lib.h"
0048
0049 #include "../kselftest.h"
0050
0051 #ifndef bug_on
0052 # define bug_on(cond) assert(!(cond))
0053 #endif
0054
0055 #ifndef __aligned_tpacket
0056 # define __aligned_tpacket __attribute__((aligned(TPACKET_ALIGNMENT)))
0057 #endif
0058
0059 #ifndef __align_tpacket
0060 # define __align_tpacket(x) __attribute__((aligned(TPACKET_ALIGN(x))))
0061 #endif
0062
0063 #define NUM_PACKETS 100
0064 #define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1))
0065
0066 struct ring {
0067 struct iovec *rd;
0068 uint8_t *mm_space;
0069 size_t mm_len, rd_len;
0070 struct sockaddr_ll ll;
0071 void (*walk)(int sock, struct ring *ring);
0072 int type, rd_num, flen, version;
0073 union {
0074 struct tpacket_req req;
0075 struct tpacket_req3 req3;
0076 };
0077 };
0078
0079 struct block_desc {
0080 uint32_t version;
0081 uint32_t offset_to_priv;
0082 struct tpacket_hdr_v1 h1;
0083 };
0084
0085 union frame_map {
0086 struct {
0087 struct tpacket_hdr tp_h __aligned_tpacket;
0088 struct sockaddr_ll s_ll __align_tpacket(sizeof(struct tpacket_hdr));
0089 } *v1;
0090 struct {
0091 struct tpacket2_hdr tp_h __aligned_tpacket;
0092 struct sockaddr_ll s_ll __align_tpacket(sizeof(struct tpacket2_hdr));
0093 } *v2;
0094 void *raw;
0095 };
0096
0097 static unsigned int total_packets, total_bytes;
0098
0099 static int pfsocket(int ver)
0100 {
0101 int ret, sock = socket(PF_PACKET, SOCK_RAW, 0);
0102 if (sock == -1) {
0103 perror("socket");
0104 exit(1);
0105 }
0106
0107 ret = setsockopt(sock, SOL_PACKET, PACKET_VERSION, &ver, sizeof(ver));
0108 if (ret == -1) {
0109 perror("setsockopt");
0110 exit(1);
0111 }
0112
0113 return sock;
0114 }
0115
0116 static void status_bar_update(void)
0117 {
0118 if (total_packets % 10 == 0) {
0119 fprintf(stderr, ".");
0120 fflush(stderr);
0121 }
0122 }
0123
0124 static void test_payload(void *pay, size_t len)
0125 {
0126 struct ethhdr *eth = pay;
0127
0128 if (len < sizeof(struct ethhdr)) {
0129 fprintf(stderr, "test_payload: packet too "
0130 "small: %zu bytes!\n", len);
0131 exit(1);
0132 }
0133
0134 if (eth->h_proto != htons(ETH_P_IP)) {
0135 fprintf(stderr, "test_payload: wrong ethernet "
0136 "type: 0x%x!\n", ntohs(eth->h_proto));
0137 exit(1);
0138 }
0139 }
0140
0141 static void create_payload(void *pay, size_t *len)
0142 {
0143 int i;
0144 struct ethhdr *eth = pay;
0145 struct iphdr *ip = pay + sizeof(*eth);
0146
0147
0148
0149
0150
0151 *len = DATA_LEN + 42;
0152
0153 memset(pay, 0xff, ETH_ALEN * 2);
0154 eth->h_proto = htons(ETH_P_IP);
0155
0156 for (i = 0; i < sizeof(*ip); ++i)
0157 ((uint8_t *) pay)[i + sizeof(*eth)] = (uint8_t) rand();
0158
0159 ip->ihl = 5;
0160 ip->version = 4;
0161 ip->protocol = 0x11;
0162 ip->frag_off = 0;
0163 ip->ttl = 64;
0164 ip->tot_len = htons((uint16_t) *len - sizeof(*eth));
0165
0166 ip->saddr = htonl(INADDR_LOOPBACK);
0167 ip->daddr = htonl(INADDR_LOOPBACK);
0168
0169 memset(pay + sizeof(*eth) + sizeof(*ip),
0170 DATA_CHAR, DATA_LEN);
0171 }
0172
0173 static inline int __v1_rx_kernel_ready(struct tpacket_hdr *hdr)
0174 {
0175 return ((hdr->tp_status & TP_STATUS_USER) == TP_STATUS_USER);
0176 }
0177
0178 static inline void __v1_rx_user_ready(struct tpacket_hdr *hdr)
0179 {
0180 hdr->tp_status = TP_STATUS_KERNEL;
0181 __sync_synchronize();
0182 }
0183
0184 static inline int __v2_rx_kernel_ready(struct tpacket2_hdr *hdr)
0185 {
0186 return ((hdr->tp_status & TP_STATUS_USER) == TP_STATUS_USER);
0187 }
0188
0189 static inline void __v2_rx_user_ready(struct tpacket2_hdr *hdr)
0190 {
0191 hdr->tp_status = TP_STATUS_KERNEL;
0192 __sync_synchronize();
0193 }
0194
0195 static inline int __v1_v2_rx_kernel_ready(void *base, int version)
0196 {
0197 switch (version) {
0198 case TPACKET_V1:
0199 return __v1_rx_kernel_ready(base);
0200 case TPACKET_V2:
0201 return __v2_rx_kernel_ready(base);
0202 default:
0203 bug_on(1);
0204 return 0;
0205 }
0206 }
0207
0208 static inline void __v1_v2_rx_user_ready(void *base, int version)
0209 {
0210 switch (version) {
0211 case TPACKET_V1:
0212 __v1_rx_user_ready(base);
0213 break;
0214 case TPACKET_V2:
0215 __v2_rx_user_ready(base);
0216 break;
0217 }
0218 }
0219
0220 static void walk_v1_v2_rx(int sock, struct ring *ring)
0221 {
0222 struct pollfd pfd;
0223 int udp_sock[2];
0224 union frame_map ppd;
0225 unsigned int frame_num = 0;
0226
0227 bug_on(ring->type != PACKET_RX_RING);
0228
0229 pair_udp_open(udp_sock, PORT_BASE);
0230
0231 memset(&pfd, 0, sizeof(pfd));
0232 pfd.fd = sock;
0233 pfd.events = POLLIN | POLLERR;
0234 pfd.revents = 0;
0235
0236 pair_udp_send(udp_sock, NUM_PACKETS);
0237
0238 while (total_packets < NUM_PACKETS * 2) {
0239 while (__v1_v2_rx_kernel_ready(ring->rd[frame_num].iov_base,
0240 ring->version)) {
0241 ppd.raw = ring->rd[frame_num].iov_base;
0242
0243 switch (ring->version) {
0244 case TPACKET_V1:
0245 test_payload((uint8_t *) ppd.raw + ppd.v1->tp_h.tp_mac,
0246 ppd.v1->tp_h.tp_snaplen);
0247 total_bytes += ppd.v1->tp_h.tp_snaplen;
0248 break;
0249
0250 case TPACKET_V2:
0251 test_payload((uint8_t *) ppd.raw + ppd.v2->tp_h.tp_mac,
0252 ppd.v2->tp_h.tp_snaplen);
0253 total_bytes += ppd.v2->tp_h.tp_snaplen;
0254 break;
0255 }
0256
0257 status_bar_update();
0258 total_packets++;
0259
0260 __v1_v2_rx_user_ready(ppd.raw, ring->version);
0261
0262 frame_num = (frame_num + 1) % ring->rd_num;
0263 }
0264
0265 poll(&pfd, 1, 1);
0266 }
0267
0268 pair_udp_close(udp_sock);
0269
0270 if (total_packets != 2 * NUM_PACKETS) {
0271 fprintf(stderr, "walk_v%d_rx: received %u out of %u pkts\n",
0272 ring->version, total_packets, NUM_PACKETS);
0273 exit(1);
0274 }
0275
0276 fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, total_bytes >> 1);
0277 }
0278
0279 static inline int __v1_tx_kernel_ready(struct tpacket_hdr *hdr)
0280 {
0281 return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING));
0282 }
0283
0284 static inline void __v1_tx_user_ready(struct tpacket_hdr *hdr)
0285 {
0286 hdr->tp_status = TP_STATUS_SEND_REQUEST;
0287 __sync_synchronize();
0288 }
0289
0290 static inline int __v2_tx_kernel_ready(struct tpacket2_hdr *hdr)
0291 {
0292 return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING));
0293 }
0294
0295 static inline void __v2_tx_user_ready(struct tpacket2_hdr *hdr)
0296 {
0297 hdr->tp_status = TP_STATUS_SEND_REQUEST;
0298 __sync_synchronize();
0299 }
0300
0301 static inline int __v3_tx_kernel_ready(struct tpacket3_hdr *hdr)
0302 {
0303 return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING));
0304 }
0305
0306 static inline void __v3_tx_user_ready(struct tpacket3_hdr *hdr)
0307 {
0308 hdr->tp_status = TP_STATUS_SEND_REQUEST;
0309 __sync_synchronize();
0310 }
0311
0312 static inline int __tx_kernel_ready(void *base, int version)
0313 {
0314 switch (version) {
0315 case TPACKET_V1:
0316 return __v1_tx_kernel_ready(base);
0317 case TPACKET_V2:
0318 return __v2_tx_kernel_ready(base);
0319 case TPACKET_V3:
0320 return __v3_tx_kernel_ready(base);
0321 default:
0322 bug_on(1);
0323 return 0;
0324 }
0325 }
0326
0327 static inline void __tx_user_ready(void *base, int version)
0328 {
0329 switch (version) {
0330 case TPACKET_V1:
0331 __v1_tx_user_ready(base);
0332 break;
0333 case TPACKET_V2:
0334 __v2_tx_user_ready(base);
0335 break;
0336 case TPACKET_V3:
0337 __v3_tx_user_ready(base);
0338 break;
0339 }
0340 }
0341
0342 static void __v1_v2_set_packet_loss_discard(int sock)
0343 {
0344 int ret, discard = 1;
0345
0346 ret = setsockopt(sock, SOL_PACKET, PACKET_LOSS, (void *) &discard,
0347 sizeof(discard));
0348 if (ret == -1) {
0349 perror("setsockopt");
0350 exit(1);
0351 }
0352 }
0353
0354 static inline void *get_next_frame(struct ring *ring, int n)
0355 {
0356 uint8_t *f0 = ring->rd[0].iov_base;
0357
0358 switch (ring->version) {
0359 case TPACKET_V1:
0360 case TPACKET_V2:
0361 return ring->rd[n].iov_base;
0362 case TPACKET_V3:
0363 return f0 + (n * ring->req3.tp_frame_size);
0364 default:
0365 bug_on(1);
0366 }
0367 }
0368
0369 static void walk_tx(int sock, struct ring *ring)
0370 {
0371 struct pollfd pfd;
0372 int rcv_sock, ret;
0373 size_t packet_len;
0374 union frame_map ppd;
0375 char packet[1024];
0376 unsigned int frame_num = 0, got = 0;
0377 struct sockaddr_ll ll = {
0378 .sll_family = PF_PACKET,
0379 .sll_halen = ETH_ALEN,
0380 };
0381 int nframes;
0382
0383
0384
0385
0386
0387 if (ring->version <= TPACKET_V2)
0388 nframes = ring->rd_num;
0389 else
0390 nframes = ring->req3.tp_frame_nr;
0391
0392 bug_on(ring->type != PACKET_TX_RING);
0393 bug_on(nframes < NUM_PACKETS);
0394
0395 rcv_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
0396 if (rcv_sock == -1) {
0397 perror("socket");
0398 exit(1);
0399 }
0400
0401 pair_udp_setfilter(rcv_sock);
0402
0403 ll.sll_ifindex = if_nametoindex("lo");
0404 ret = bind(rcv_sock, (struct sockaddr *) &ll, sizeof(ll));
0405 if (ret == -1) {
0406 perror("bind");
0407 exit(1);
0408 }
0409
0410 memset(&pfd, 0, sizeof(pfd));
0411 pfd.fd = sock;
0412 pfd.events = POLLOUT | POLLERR;
0413 pfd.revents = 0;
0414
0415 total_packets = NUM_PACKETS;
0416 create_payload(packet, &packet_len);
0417
0418 while (total_packets > 0) {
0419 void *next = get_next_frame(ring, frame_num);
0420
0421 while (__tx_kernel_ready(next, ring->version) &&
0422 total_packets > 0) {
0423 ppd.raw = next;
0424
0425 switch (ring->version) {
0426 case TPACKET_V1:
0427 ppd.v1->tp_h.tp_snaplen = packet_len;
0428 ppd.v1->tp_h.tp_len = packet_len;
0429
0430 memcpy((uint8_t *) ppd.raw + TPACKET_HDRLEN -
0431 sizeof(struct sockaddr_ll), packet,
0432 packet_len);
0433 total_bytes += ppd.v1->tp_h.tp_snaplen;
0434 break;
0435
0436 case TPACKET_V2:
0437 ppd.v2->tp_h.tp_snaplen = packet_len;
0438 ppd.v2->tp_h.tp_len = packet_len;
0439
0440 memcpy((uint8_t *) ppd.raw + TPACKET2_HDRLEN -
0441 sizeof(struct sockaddr_ll), packet,
0442 packet_len);
0443 total_bytes += ppd.v2->tp_h.tp_snaplen;
0444 break;
0445 case TPACKET_V3: {
0446 struct tpacket3_hdr *tx = next;
0447
0448 tx->tp_snaplen = packet_len;
0449 tx->tp_len = packet_len;
0450 tx->tp_next_offset = 0;
0451
0452 memcpy((uint8_t *)tx + TPACKET3_HDRLEN -
0453 sizeof(struct sockaddr_ll), packet,
0454 packet_len);
0455 total_bytes += tx->tp_snaplen;
0456 break;
0457 }
0458 }
0459
0460 status_bar_update();
0461 total_packets--;
0462
0463 __tx_user_ready(next, ring->version);
0464
0465 frame_num = (frame_num + 1) % nframes;
0466 }
0467
0468 poll(&pfd, 1, 1);
0469 }
0470
0471 bug_on(total_packets != 0);
0472
0473 ret = sendto(sock, NULL, 0, 0, NULL, 0);
0474 if (ret == -1) {
0475 perror("sendto");
0476 exit(1);
0477 }
0478
0479 while ((ret = recvfrom(rcv_sock, packet, sizeof(packet),
0480 0, NULL, NULL)) > 0 &&
0481 total_packets < NUM_PACKETS) {
0482 got += ret;
0483 test_payload(packet, ret);
0484
0485 status_bar_update();
0486 total_packets++;
0487 }
0488
0489 close(rcv_sock);
0490
0491 if (total_packets != NUM_PACKETS) {
0492 fprintf(stderr, "walk_v%d_rx: received %u out of %u pkts\n",
0493 ring->version, total_packets, NUM_PACKETS);
0494 exit(1);
0495 }
0496
0497 fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, got);
0498 }
0499
0500 static void walk_v1_v2(int sock, struct ring *ring)
0501 {
0502 if (ring->type == PACKET_RX_RING)
0503 walk_v1_v2_rx(sock, ring);
0504 else
0505 walk_tx(sock, ring);
0506 }
0507
0508 static uint64_t __v3_prev_block_seq_num = 0;
0509
0510 void __v3_test_block_seq_num(struct block_desc *pbd)
0511 {
0512 if (__v3_prev_block_seq_num + 1 != pbd->h1.seq_num) {
0513 fprintf(stderr, "\nprev_block_seq_num:%"PRIu64", expected "
0514 "seq:%"PRIu64" != actual seq:%"PRIu64"\n",
0515 __v3_prev_block_seq_num, __v3_prev_block_seq_num + 1,
0516 (uint64_t) pbd->h1.seq_num);
0517 exit(1);
0518 }
0519
0520 __v3_prev_block_seq_num = pbd->h1.seq_num;
0521 }
0522
0523 static void __v3_test_block_len(struct block_desc *pbd, uint32_t bytes, int block_num)
0524 {
0525 if (pbd->h1.num_pkts && bytes != pbd->h1.blk_len) {
0526 fprintf(stderr, "\nblock:%u with %upackets, expected "
0527 "len:%u != actual len:%u\n", block_num,
0528 pbd->h1.num_pkts, bytes, pbd->h1.blk_len);
0529 exit(1);
0530 }
0531 }
0532
0533 static void __v3_test_block_header(struct block_desc *pbd, const int block_num)
0534 {
0535 if ((pbd->h1.block_status & TP_STATUS_USER) == 0) {
0536 fprintf(stderr, "\nblock %u: not in TP_STATUS_USER\n", block_num);
0537 exit(1);
0538 }
0539
0540 __v3_test_block_seq_num(pbd);
0541 }
0542
0543 static void __v3_walk_block(struct block_desc *pbd, const int block_num)
0544 {
0545 int num_pkts = pbd->h1.num_pkts, i;
0546 unsigned long bytes = 0, bytes_with_padding = ALIGN_8(sizeof(*pbd));
0547 struct tpacket3_hdr *ppd;
0548
0549 __v3_test_block_header(pbd, block_num);
0550
0551 ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd +
0552 pbd->h1.offset_to_first_pkt);
0553
0554 for (i = 0; i < num_pkts; ++i) {
0555 bytes += ppd->tp_snaplen;
0556
0557 if (ppd->tp_next_offset)
0558 bytes_with_padding += ppd->tp_next_offset;
0559 else
0560 bytes_with_padding += ALIGN_8(ppd->tp_snaplen + ppd->tp_mac);
0561
0562 test_payload((uint8_t *) ppd + ppd->tp_mac, ppd->tp_snaplen);
0563
0564 status_bar_update();
0565 total_packets++;
0566
0567 ppd = (struct tpacket3_hdr *) ((uint8_t *) ppd + ppd->tp_next_offset);
0568 __sync_synchronize();
0569 }
0570
0571 __v3_test_block_len(pbd, bytes_with_padding, block_num);
0572 total_bytes += bytes;
0573 }
0574
0575 void __v3_flush_block(struct block_desc *pbd)
0576 {
0577 pbd->h1.block_status = TP_STATUS_KERNEL;
0578 __sync_synchronize();
0579 }
0580
0581 static void walk_v3_rx(int sock, struct ring *ring)
0582 {
0583 unsigned int block_num = 0;
0584 struct pollfd pfd;
0585 struct block_desc *pbd;
0586 int udp_sock[2];
0587
0588 bug_on(ring->type != PACKET_RX_RING);
0589
0590 pair_udp_open(udp_sock, PORT_BASE);
0591
0592 memset(&pfd, 0, sizeof(pfd));
0593 pfd.fd = sock;
0594 pfd.events = POLLIN | POLLERR;
0595 pfd.revents = 0;
0596
0597 pair_udp_send(udp_sock, NUM_PACKETS);
0598
0599 while (total_packets < NUM_PACKETS * 2) {
0600 pbd = (struct block_desc *) ring->rd[block_num].iov_base;
0601
0602 while ((pbd->h1.block_status & TP_STATUS_USER) == 0)
0603 poll(&pfd, 1, 1);
0604
0605 __v3_walk_block(pbd, block_num);
0606 __v3_flush_block(pbd);
0607
0608 block_num = (block_num + 1) % ring->rd_num;
0609 }
0610
0611 pair_udp_close(udp_sock);
0612
0613 if (total_packets != 2 * NUM_PACKETS) {
0614 fprintf(stderr, "walk_v3_rx: received %u out of %u pkts\n",
0615 total_packets, NUM_PACKETS);
0616 exit(1);
0617 }
0618
0619 fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, total_bytes >> 1);
0620 }
0621
0622 static void walk_v3(int sock, struct ring *ring)
0623 {
0624 if (ring->type == PACKET_RX_RING)
0625 walk_v3_rx(sock, ring);
0626 else
0627 walk_tx(sock, ring);
0628 }
0629
0630 static void __v1_v2_fill(struct ring *ring, unsigned int blocks)
0631 {
0632 ring->req.tp_block_size = getpagesize() << 2;
0633 ring->req.tp_frame_size = TPACKET_ALIGNMENT << 7;
0634 ring->req.tp_block_nr = blocks;
0635
0636 ring->req.tp_frame_nr = ring->req.tp_block_size /
0637 ring->req.tp_frame_size *
0638 ring->req.tp_block_nr;
0639
0640 ring->mm_len = ring->req.tp_block_size * ring->req.tp_block_nr;
0641 ring->walk = walk_v1_v2;
0642 ring->rd_num = ring->req.tp_frame_nr;
0643 ring->flen = ring->req.tp_frame_size;
0644 }
0645
0646 static void __v3_fill(struct ring *ring, unsigned int blocks, int type)
0647 {
0648 if (type == PACKET_RX_RING) {
0649 ring->req3.tp_retire_blk_tov = 64;
0650 ring->req3.tp_sizeof_priv = 0;
0651 ring->req3.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH;
0652 }
0653 ring->req3.tp_block_size = getpagesize() << 2;
0654 ring->req3.tp_frame_size = TPACKET_ALIGNMENT << 7;
0655 ring->req3.tp_block_nr = blocks;
0656
0657 ring->req3.tp_frame_nr = ring->req3.tp_block_size /
0658 ring->req3.tp_frame_size *
0659 ring->req3.tp_block_nr;
0660
0661 ring->mm_len = ring->req3.tp_block_size * ring->req3.tp_block_nr;
0662 ring->walk = walk_v3;
0663 ring->rd_num = ring->req3.tp_block_nr;
0664 ring->flen = ring->req3.tp_block_size;
0665 }
0666
0667 static void setup_ring(int sock, struct ring *ring, int version, int type)
0668 {
0669 int ret = 0;
0670 unsigned int blocks = 256;
0671
0672 ring->type = type;
0673 ring->version = version;
0674
0675 switch (version) {
0676 case TPACKET_V1:
0677 case TPACKET_V2:
0678 if (type == PACKET_TX_RING)
0679 __v1_v2_set_packet_loss_discard(sock);
0680 __v1_v2_fill(ring, blocks);
0681 ret = setsockopt(sock, SOL_PACKET, type, &ring->req,
0682 sizeof(ring->req));
0683 break;
0684
0685 case TPACKET_V3:
0686 __v3_fill(ring, blocks, type);
0687 ret = setsockopt(sock, SOL_PACKET, type, &ring->req3,
0688 sizeof(ring->req3));
0689 break;
0690 }
0691
0692 if (ret == -1) {
0693 perror("setsockopt");
0694 exit(1);
0695 }
0696
0697 ring->rd_len = ring->rd_num * sizeof(*ring->rd);
0698 ring->rd = malloc(ring->rd_len);
0699 if (ring->rd == NULL) {
0700 perror("malloc");
0701 exit(1);
0702 }
0703
0704 total_packets = 0;
0705 total_bytes = 0;
0706 }
0707
0708 static void mmap_ring(int sock, struct ring *ring)
0709 {
0710 int i;
0711
0712 ring->mm_space = mmap(0, ring->mm_len, PROT_READ | PROT_WRITE,
0713 MAP_SHARED | MAP_LOCKED | MAP_POPULATE, sock, 0);
0714 if (ring->mm_space == MAP_FAILED) {
0715 perror("mmap");
0716 exit(1);
0717 }
0718
0719 memset(ring->rd, 0, ring->rd_len);
0720 for (i = 0; i < ring->rd_num; ++i) {
0721 ring->rd[i].iov_base = ring->mm_space + (i * ring->flen);
0722 ring->rd[i].iov_len = ring->flen;
0723 }
0724 }
0725
0726 static void bind_ring(int sock, struct ring *ring)
0727 {
0728 int ret;
0729
0730 pair_udp_setfilter(sock);
0731
0732 ring->ll.sll_family = PF_PACKET;
0733 ring->ll.sll_protocol = htons(ETH_P_ALL);
0734 ring->ll.sll_ifindex = if_nametoindex("lo");
0735 ring->ll.sll_hatype = 0;
0736 ring->ll.sll_pkttype = 0;
0737 ring->ll.sll_halen = 0;
0738
0739 ret = bind(sock, (struct sockaddr *) &ring->ll, sizeof(ring->ll));
0740 if (ret == -1) {
0741 perror("bind");
0742 exit(1);
0743 }
0744 }
0745
0746 static void walk_ring(int sock, struct ring *ring)
0747 {
0748 ring->walk(sock, ring);
0749 }
0750
0751 static void unmap_ring(int sock, struct ring *ring)
0752 {
0753 munmap(ring->mm_space, ring->mm_len);
0754 free(ring->rd);
0755 }
0756
0757 static int test_kernel_bit_width(void)
0758 {
0759 char in[512], *ptr;
0760 int num = 0, fd;
0761 ssize_t ret;
0762
0763 fd = open("/proc/kallsyms", O_RDONLY);
0764 if (fd == -1) {
0765 perror("open");
0766 exit(1);
0767 }
0768
0769 ret = read(fd, in, sizeof(in));
0770 if (ret <= 0) {
0771 perror("read");
0772 exit(1);
0773 }
0774
0775 close(fd);
0776
0777 ptr = in;
0778 while(!isspace(*ptr)) {
0779 num++;
0780 ptr++;
0781 }
0782
0783 return num * 4;
0784 }
0785
0786 static int test_user_bit_width(void)
0787 {
0788 return __WORDSIZE;
0789 }
0790
0791 static const char *tpacket_str[] = {
0792 [TPACKET_V1] = "TPACKET_V1",
0793 [TPACKET_V2] = "TPACKET_V2",
0794 [TPACKET_V3] = "TPACKET_V3",
0795 };
0796
0797 static const char *type_str[] = {
0798 [PACKET_RX_RING] = "PACKET_RX_RING",
0799 [PACKET_TX_RING] = "PACKET_TX_RING",
0800 };
0801
0802 static int test_tpacket(int version, int type)
0803 {
0804 int sock;
0805 struct ring ring;
0806
0807 fprintf(stderr, "test: %s with %s ", tpacket_str[version],
0808 type_str[type]);
0809 fflush(stderr);
0810
0811 if (version == TPACKET_V1 &&
0812 test_kernel_bit_width() != test_user_bit_width()) {
0813 fprintf(stderr, "test: skip %s %s since user and kernel "
0814 "space have different bit width\n",
0815 tpacket_str[version], type_str[type]);
0816 return KSFT_SKIP;
0817 }
0818
0819 sock = pfsocket(version);
0820 memset(&ring, 0, sizeof(ring));
0821 setup_ring(sock, &ring, version, type);
0822 mmap_ring(sock, &ring);
0823 bind_ring(sock, &ring);
0824 walk_ring(sock, &ring);
0825 unmap_ring(sock, &ring);
0826 close(sock);
0827
0828 fprintf(stderr, "\n");
0829 return 0;
0830 }
0831
0832 int main(void)
0833 {
0834 int ret = 0;
0835
0836 ret |= test_tpacket(TPACKET_V1, PACKET_RX_RING);
0837 ret |= test_tpacket(TPACKET_V1, PACKET_TX_RING);
0838
0839 ret |= test_tpacket(TPACKET_V2, PACKET_RX_RING);
0840 ret |= test_tpacket(TPACKET_V2, PACKET_TX_RING);
0841
0842 ret |= test_tpacket(TPACKET_V3, PACKET_RX_RING);
0843 ret |= test_tpacket(TPACKET_V3, PACKET_TX_RING);
0844
0845 if (ret)
0846 return 1;
0847
0848 printf("OK. All tests passed\n");
0849 return 0;
0850 }