18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2013 Red Hat, Inc. 48c2ecf20Sopenharmony_ci * Author: Daniel Borkmann <dborkman@redhat.com> 58c2ecf20Sopenharmony_ci * Chetan Loke <loke.chetan@gmail.com> (TPACKET_V3 usage example) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * A basic test of packet socket's TPACKET_V1/TPACKET_V2/TPACKET_V3 behavior. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Control: 108c2ecf20Sopenharmony_ci * Test the setup of the TPACKET socket with different patterns that are 118c2ecf20Sopenharmony_ci * known to fail (TODO) resp. succeed (OK). 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Datapath: 148c2ecf20Sopenharmony_ci * Open a pair of packet sockets and send resp. receive an a priori known 158c2ecf20Sopenharmony_ci * packet pattern accross the sockets and check if it was received resp. 168c2ecf20Sopenharmony_ci * sent correctly. Fanout in combination with RX_RING is currently not 178c2ecf20Sopenharmony_ci * tested here. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * The test currently runs for 208c2ecf20Sopenharmony_ci * - TPACKET_V1: RX_RING, TX_RING 218c2ecf20Sopenharmony_ci * - TPACKET_V2: RX_RING, TX_RING 228c2ecf20Sopenharmony_ci * - TPACKET_V3: RX_RING 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <stdio.h> 268c2ecf20Sopenharmony_ci#include <stdlib.h> 278c2ecf20Sopenharmony_ci#include <sys/types.h> 288c2ecf20Sopenharmony_ci#include <sys/stat.h> 298c2ecf20Sopenharmony_ci#include <sys/socket.h> 308c2ecf20Sopenharmony_ci#include <sys/mman.h> 318c2ecf20Sopenharmony_ci#include <linux/if_packet.h> 328c2ecf20Sopenharmony_ci#include <linux/filter.h> 338c2ecf20Sopenharmony_ci#include <ctype.h> 348c2ecf20Sopenharmony_ci#include <fcntl.h> 358c2ecf20Sopenharmony_ci#include <unistd.h> 368c2ecf20Sopenharmony_ci#include <bits/wordsize.h> 378c2ecf20Sopenharmony_ci#include <net/ethernet.h> 388c2ecf20Sopenharmony_ci#include <netinet/ip.h> 398c2ecf20Sopenharmony_ci#include <arpa/inet.h> 408c2ecf20Sopenharmony_ci#include <stdint.h> 418c2ecf20Sopenharmony_ci#include <string.h> 428c2ecf20Sopenharmony_ci#include <assert.h> 438c2ecf20Sopenharmony_ci#include <net/if.h> 448c2ecf20Sopenharmony_ci#include <inttypes.h> 458c2ecf20Sopenharmony_ci#include <poll.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include "psock_lib.h" 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include "../kselftest.h" 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#ifndef bug_on 528c2ecf20Sopenharmony_ci# define bug_on(cond) assert(!(cond)) 538c2ecf20Sopenharmony_ci#endif 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#ifndef __aligned_tpacket 568c2ecf20Sopenharmony_ci# define __aligned_tpacket __attribute__((aligned(TPACKET_ALIGNMENT))) 578c2ecf20Sopenharmony_ci#endif 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#ifndef __align_tpacket 608c2ecf20Sopenharmony_ci# define __align_tpacket(x) __attribute__((aligned(TPACKET_ALIGN(x)))) 618c2ecf20Sopenharmony_ci#endif 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define NUM_PACKETS 100 648c2ecf20Sopenharmony_ci#define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1)) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistruct ring { 678c2ecf20Sopenharmony_ci struct iovec *rd; 688c2ecf20Sopenharmony_ci uint8_t *mm_space; 698c2ecf20Sopenharmony_ci size_t mm_len, rd_len; 708c2ecf20Sopenharmony_ci struct sockaddr_ll ll; 718c2ecf20Sopenharmony_ci void (*walk)(int sock, struct ring *ring); 728c2ecf20Sopenharmony_ci int type, rd_num, flen, version; 738c2ecf20Sopenharmony_ci union { 748c2ecf20Sopenharmony_ci struct tpacket_req req; 758c2ecf20Sopenharmony_ci struct tpacket_req3 req3; 768c2ecf20Sopenharmony_ci }; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistruct block_desc { 808c2ecf20Sopenharmony_ci uint32_t version; 818c2ecf20Sopenharmony_ci uint32_t offset_to_priv; 828c2ecf20Sopenharmony_ci struct tpacket_hdr_v1 h1; 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ciunion frame_map { 868c2ecf20Sopenharmony_ci struct { 878c2ecf20Sopenharmony_ci struct tpacket_hdr tp_h __aligned_tpacket; 888c2ecf20Sopenharmony_ci struct sockaddr_ll s_ll __align_tpacket(sizeof(struct tpacket_hdr)); 898c2ecf20Sopenharmony_ci } *v1; 908c2ecf20Sopenharmony_ci struct { 918c2ecf20Sopenharmony_ci struct tpacket2_hdr tp_h __aligned_tpacket; 928c2ecf20Sopenharmony_ci struct sockaddr_ll s_ll __align_tpacket(sizeof(struct tpacket2_hdr)); 938c2ecf20Sopenharmony_ci } *v2; 948c2ecf20Sopenharmony_ci void *raw; 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic unsigned int total_packets, total_bytes; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int pfsocket(int ver) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci int ret, sock = socket(PF_PACKET, SOCK_RAW, 0); 1028c2ecf20Sopenharmony_ci if (sock == -1) { 1038c2ecf20Sopenharmony_ci perror("socket"); 1048c2ecf20Sopenharmony_ci exit(1); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci ret = setsockopt(sock, SOL_PACKET, PACKET_VERSION, &ver, sizeof(ver)); 1088c2ecf20Sopenharmony_ci if (ret == -1) { 1098c2ecf20Sopenharmony_ci perror("setsockopt"); 1108c2ecf20Sopenharmony_ci exit(1); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return sock; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void status_bar_update(void) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci if (total_packets % 10 == 0) { 1198c2ecf20Sopenharmony_ci fprintf(stderr, "."); 1208c2ecf20Sopenharmony_ci fflush(stderr); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void test_payload(void *pay, size_t len) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct ethhdr *eth = pay; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (len < sizeof(struct ethhdr)) { 1298c2ecf20Sopenharmony_ci fprintf(stderr, "test_payload: packet too " 1308c2ecf20Sopenharmony_ci "small: %zu bytes!\n", len); 1318c2ecf20Sopenharmony_ci exit(1); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (eth->h_proto != htons(ETH_P_IP)) { 1358c2ecf20Sopenharmony_ci fprintf(stderr, "test_payload: wrong ethernet " 1368c2ecf20Sopenharmony_ci "type: 0x%x!\n", ntohs(eth->h_proto)); 1378c2ecf20Sopenharmony_ci exit(1); 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic void create_payload(void *pay, size_t *len) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci int i; 1448c2ecf20Sopenharmony_ci struct ethhdr *eth = pay; 1458c2ecf20Sopenharmony_ci struct iphdr *ip = pay + sizeof(*eth); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* Lets create some broken crap, that still passes 1488c2ecf20Sopenharmony_ci * our BPF filter. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci *len = DATA_LEN + 42; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci memset(pay, 0xff, ETH_ALEN * 2); 1548c2ecf20Sopenharmony_ci eth->h_proto = htons(ETH_P_IP); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(*ip); ++i) 1578c2ecf20Sopenharmony_ci ((uint8_t *) pay)[i + sizeof(*eth)] = (uint8_t) rand(); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci ip->ihl = 5; 1608c2ecf20Sopenharmony_ci ip->version = 4; 1618c2ecf20Sopenharmony_ci ip->protocol = 0x11; 1628c2ecf20Sopenharmony_ci ip->frag_off = 0; 1638c2ecf20Sopenharmony_ci ip->ttl = 64; 1648c2ecf20Sopenharmony_ci ip->tot_len = htons((uint16_t) *len - sizeof(*eth)); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci ip->saddr = htonl(INADDR_LOOPBACK); 1678c2ecf20Sopenharmony_ci ip->daddr = htonl(INADDR_LOOPBACK); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci memset(pay + sizeof(*eth) + sizeof(*ip), 1708c2ecf20Sopenharmony_ci DATA_CHAR, DATA_LEN); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic inline int __v1_rx_kernel_ready(struct tpacket_hdr *hdr) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci return ((hdr->tp_status & TP_STATUS_USER) == TP_STATUS_USER); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic inline void __v1_rx_user_ready(struct tpacket_hdr *hdr) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci hdr->tp_status = TP_STATUS_KERNEL; 1818c2ecf20Sopenharmony_ci __sync_synchronize(); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic inline int __v2_rx_kernel_ready(struct tpacket2_hdr *hdr) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci return ((hdr->tp_status & TP_STATUS_USER) == TP_STATUS_USER); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic inline void __v2_rx_user_ready(struct tpacket2_hdr *hdr) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci hdr->tp_status = TP_STATUS_KERNEL; 1928c2ecf20Sopenharmony_ci __sync_synchronize(); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic inline int __v1_v2_rx_kernel_ready(void *base, int version) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci switch (version) { 1988c2ecf20Sopenharmony_ci case TPACKET_V1: 1998c2ecf20Sopenharmony_ci return __v1_rx_kernel_ready(base); 2008c2ecf20Sopenharmony_ci case TPACKET_V2: 2018c2ecf20Sopenharmony_ci return __v2_rx_kernel_ready(base); 2028c2ecf20Sopenharmony_ci default: 2038c2ecf20Sopenharmony_ci bug_on(1); 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic inline void __v1_v2_rx_user_ready(void *base, int version) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci switch (version) { 2118c2ecf20Sopenharmony_ci case TPACKET_V1: 2128c2ecf20Sopenharmony_ci __v1_rx_user_ready(base); 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci case TPACKET_V2: 2158c2ecf20Sopenharmony_ci __v2_rx_user_ready(base); 2168c2ecf20Sopenharmony_ci break; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void walk_v1_v2_rx(int sock, struct ring *ring) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct pollfd pfd; 2238c2ecf20Sopenharmony_ci int udp_sock[2]; 2248c2ecf20Sopenharmony_ci union frame_map ppd; 2258c2ecf20Sopenharmony_ci unsigned int frame_num = 0; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci bug_on(ring->type != PACKET_RX_RING); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci pair_udp_open(udp_sock, PORT_BASE); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci memset(&pfd, 0, sizeof(pfd)); 2328c2ecf20Sopenharmony_ci pfd.fd = sock; 2338c2ecf20Sopenharmony_ci pfd.events = POLLIN | POLLERR; 2348c2ecf20Sopenharmony_ci pfd.revents = 0; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci pair_udp_send(udp_sock, NUM_PACKETS); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci while (total_packets < NUM_PACKETS * 2) { 2398c2ecf20Sopenharmony_ci while (__v1_v2_rx_kernel_ready(ring->rd[frame_num].iov_base, 2408c2ecf20Sopenharmony_ci ring->version)) { 2418c2ecf20Sopenharmony_ci ppd.raw = ring->rd[frame_num].iov_base; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci switch (ring->version) { 2448c2ecf20Sopenharmony_ci case TPACKET_V1: 2458c2ecf20Sopenharmony_ci test_payload((uint8_t *) ppd.raw + ppd.v1->tp_h.tp_mac, 2468c2ecf20Sopenharmony_ci ppd.v1->tp_h.tp_snaplen); 2478c2ecf20Sopenharmony_ci total_bytes += ppd.v1->tp_h.tp_snaplen; 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci case TPACKET_V2: 2518c2ecf20Sopenharmony_ci test_payload((uint8_t *) ppd.raw + ppd.v2->tp_h.tp_mac, 2528c2ecf20Sopenharmony_ci ppd.v2->tp_h.tp_snaplen); 2538c2ecf20Sopenharmony_ci total_bytes += ppd.v2->tp_h.tp_snaplen; 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci status_bar_update(); 2588c2ecf20Sopenharmony_ci total_packets++; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci __v1_v2_rx_user_ready(ppd.raw, ring->version); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci frame_num = (frame_num + 1) % ring->rd_num; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci poll(&pfd, 1, 1); 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci pair_udp_close(udp_sock); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (total_packets != 2 * NUM_PACKETS) { 2718c2ecf20Sopenharmony_ci fprintf(stderr, "walk_v%d_rx: received %u out of %u pkts\n", 2728c2ecf20Sopenharmony_ci ring->version, total_packets, NUM_PACKETS); 2738c2ecf20Sopenharmony_ci exit(1); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, total_bytes >> 1); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic inline int __v1_tx_kernel_ready(struct tpacket_hdr *hdr) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING)); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic inline void __v1_tx_user_ready(struct tpacket_hdr *hdr) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci hdr->tp_status = TP_STATUS_SEND_REQUEST; 2878c2ecf20Sopenharmony_ci __sync_synchronize(); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic inline int __v2_tx_kernel_ready(struct tpacket2_hdr *hdr) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING)); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic inline void __v2_tx_user_ready(struct tpacket2_hdr *hdr) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci hdr->tp_status = TP_STATUS_SEND_REQUEST; 2988c2ecf20Sopenharmony_ci __sync_synchronize(); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic inline int __v3_tx_kernel_ready(struct tpacket3_hdr *hdr) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING)); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic inline void __v3_tx_user_ready(struct tpacket3_hdr *hdr) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci hdr->tp_status = TP_STATUS_SEND_REQUEST; 3098c2ecf20Sopenharmony_ci __sync_synchronize(); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic inline int __tx_kernel_ready(void *base, int version) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci switch (version) { 3158c2ecf20Sopenharmony_ci case TPACKET_V1: 3168c2ecf20Sopenharmony_ci return __v1_tx_kernel_ready(base); 3178c2ecf20Sopenharmony_ci case TPACKET_V2: 3188c2ecf20Sopenharmony_ci return __v2_tx_kernel_ready(base); 3198c2ecf20Sopenharmony_ci case TPACKET_V3: 3208c2ecf20Sopenharmony_ci return __v3_tx_kernel_ready(base); 3218c2ecf20Sopenharmony_ci default: 3228c2ecf20Sopenharmony_ci bug_on(1); 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic inline void __tx_user_ready(void *base, int version) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci switch (version) { 3308c2ecf20Sopenharmony_ci case TPACKET_V1: 3318c2ecf20Sopenharmony_ci __v1_tx_user_ready(base); 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci case TPACKET_V2: 3348c2ecf20Sopenharmony_ci __v2_tx_user_ready(base); 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci case TPACKET_V3: 3378c2ecf20Sopenharmony_ci __v3_tx_user_ready(base); 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic void __v1_v2_set_packet_loss_discard(int sock) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci int ret, discard = 1; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci ret = setsockopt(sock, SOL_PACKET, PACKET_LOSS, (void *) &discard, 3478c2ecf20Sopenharmony_ci sizeof(discard)); 3488c2ecf20Sopenharmony_ci if (ret == -1) { 3498c2ecf20Sopenharmony_ci perror("setsockopt"); 3508c2ecf20Sopenharmony_ci exit(1); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic inline void *get_next_frame(struct ring *ring, int n) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci uint8_t *f0 = ring->rd[0].iov_base; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci switch (ring->version) { 3598c2ecf20Sopenharmony_ci case TPACKET_V1: 3608c2ecf20Sopenharmony_ci case TPACKET_V2: 3618c2ecf20Sopenharmony_ci return ring->rd[n].iov_base; 3628c2ecf20Sopenharmony_ci case TPACKET_V3: 3638c2ecf20Sopenharmony_ci return f0 + (n * ring->req3.tp_frame_size); 3648c2ecf20Sopenharmony_ci default: 3658c2ecf20Sopenharmony_ci bug_on(1); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic void walk_tx(int sock, struct ring *ring) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct pollfd pfd; 3728c2ecf20Sopenharmony_ci int rcv_sock, ret; 3738c2ecf20Sopenharmony_ci size_t packet_len; 3748c2ecf20Sopenharmony_ci union frame_map ppd; 3758c2ecf20Sopenharmony_ci char packet[1024]; 3768c2ecf20Sopenharmony_ci unsigned int frame_num = 0, got = 0; 3778c2ecf20Sopenharmony_ci struct sockaddr_ll ll = { 3788c2ecf20Sopenharmony_ci .sll_family = PF_PACKET, 3798c2ecf20Sopenharmony_ci .sll_halen = ETH_ALEN, 3808c2ecf20Sopenharmony_ci }; 3818c2ecf20Sopenharmony_ci int nframes; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* TPACKET_V{1,2} sets up the ring->rd* related variables based 3848c2ecf20Sopenharmony_ci * on frames (e.g., rd_num is tp_frame_nr) whereas V3 sets these 3858c2ecf20Sopenharmony_ci * up based on blocks (e.g, rd_num is tp_block_nr) 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_ci if (ring->version <= TPACKET_V2) 3888c2ecf20Sopenharmony_ci nframes = ring->rd_num; 3898c2ecf20Sopenharmony_ci else 3908c2ecf20Sopenharmony_ci nframes = ring->req3.tp_frame_nr; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci bug_on(ring->type != PACKET_TX_RING); 3938c2ecf20Sopenharmony_ci bug_on(nframes < NUM_PACKETS); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci rcv_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 3968c2ecf20Sopenharmony_ci if (rcv_sock == -1) { 3978c2ecf20Sopenharmony_ci perror("socket"); 3988c2ecf20Sopenharmony_ci exit(1); 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci pair_udp_setfilter(rcv_sock); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci ll.sll_ifindex = if_nametoindex("lo"); 4048c2ecf20Sopenharmony_ci ret = bind(rcv_sock, (struct sockaddr *) &ll, sizeof(ll)); 4058c2ecf20Sopenharmony_ci if (ret == -1) { 4068c2ecf20Sopenharmony_ci perror("bind"); 4078c2ecf20Sopenharmony_ci exit(1); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci memset(&pfd, 0, sizeof(pfd)); 4118c2ecf20Sopenharmony_ci pfd.fd = sock; 4128c2ecf20Sopenharmony_ci pfd.events = POLLOUT | POLLERR; 4138c2ecf20Sopenharmony_ci pfd.revents = 0; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci total_packets = NUM_PACKETS; 4168c2ecf20Sopenharmony_ci create_payload(packet, &packet_len); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci while (total_packets > 0) { 4198c2ecf20Sopenharmony_ci void *next = get_next_frame(ring, frame_num); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci while (__tx_kernel_ready(next, ring->version) && 4228c2ecf20Sopenharmony_ci total_packets > 0) { 4238c2ecf20Sopenharmony_ci ppd.raw = next; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci switch (ring->version) { 4268c2ecf20Sopenharmony_ci case TPACKET_V1: 4278c2ecf20Sopenharmony_ci ppd.v1->tp_h.tp_snaplen = packet_len; 4288c2ecf20Sopenharmony_ci ppd.v1->tp_h.tp_len = packet_len; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci memcpy((uint8_t *) ppd.raw + TPACKET_HDRLEN - 4318c2ecf20Sopenharmony_ci sizeof(struct sockaddr_ll), packet, 4328c2ecf20Sopenharmony_ci packet_len); 4338c2ecf20Sopenharmony_ci total_bytes += ppd.v1->tp_h.tp_snaplen; 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci case TPACKET_V2: 4378c2ecf20Sopenharmony_ci ppd.v2->tp_h.tp_snaplen = packet_len; 4388c2ecf20Sopenharmony_ci ppd.v2->tp_h.tp_len = packet_len; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci memcpy((uint8_t *) ppd.raw + TPACKET2_HDRLEN - 4418c2ecf20Sopenharmony_ci sizeof(struct sockaddr_ll), packet, 4428c2ecf20Sopenharmony_ci packet_len); 4438c2ecf20Sopenharmony_ci total_bytes += ppd.v2->tp_h.tp_snaplen; 4448c2ecf20Sopenharmony_ci break; 4458c2ecf20Sopenharmony_ci case TPACKET_V3: { 4468c2ecf20Sopenharmony_ci struct tpacket3_hdr *tx = next; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci tx->tp_snaplen = packet_len; 4498c2ecf20Sopenharmony_ci tx->tp_len = packet_len; 4508c2ecf20Sopenharmony_ci tx->tp_next_offset = 0; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci memcpy((uint8_t *)tx + TPACKET3_HDRLEN - 4538c2ecf20Sopenharmony_ci sizeof(struct sockaddr_ll), packet, 4548c2ecf20Sopenharmony_ci packet_len); 4558c2ecf20Sopenharmony_ci total_bytes += tx->tp_snaplen; 4568c2ecf20Sopenharmony_ci break; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci status_bar_update(); 4618c2ecf20Sopenharmony_ci total_packets--; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci __tx_user_ready(next, ring->version); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci frame_num = (frame_num + 1) % nframes; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci poll(&pfd, 1, 1); 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci bug_on(total_packets != 0); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci ret = sendto(sock, NULL, 0, 0, NULL, 0); 4748c2ecf20Sopenharmony_ci if (ret == -1) { 4758c2ecf20Sopenharmony_ci perror("sendto"); 4768c2ecf20Sopenharmony_ci exit(1); 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci while ((ret = recvfrom(rcv_sock, packet, sizeof(packet), 4808c2ecf20Sopenharmony_ci 0, NULL, NULL)) > 0 && 4818c2ecf20Sopenharmony_ci total_packets < NUM_PACKETS) { 4828c2ecf20Sopenharmony_ci got += ret; 4838c2ecf20Sopenharmony_ci test_payload(packet, ret); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci status_bar_update(); 4868c2ecf20Sopenharmony_ci total_packets++; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci close(rcv_sock); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (total_packets != NUM_PACKETS) { 4928c2ecf20Sopenharmony_ci fprintf(stderr, "walk_v%d_rx: received %u out of %u pkts\n", 4938c2ecf20Sopenharmony_ci ring->version, total_packets, NUM_PACKETS); 4948c2ecf20Sopenharmony_ci exit(1); 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, got); 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic void walk_v1_v2(int sock, struct ring *ring) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci if (ring->type == PACKET_RX_RING) 5038c2ecf20Sopenharmony_ci walk_v1_v2_rx(sock, ring); 5048c2ecf20Sopenharmony_ci else 5058c2ecf20Sopenharmony_ci walk_tx(sock, ring); 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic uint64_t __v3_prev_block_seq_num = 0; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_civoid __v3_test_block_seq_num(struct block_desc *pbd) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci if (__v3_prev_block_seq_num + 1 != pbd->h1.seq_num) { 5138c2ecf20Sopenharmony_ci fprintf(stderr, "\nprev_block_seq_num:%"PRIu64", expected " 5148c2ecf20Sopenharmony_ci "seq:%"PRIu64" != actual seq:%"PRIu64"\n", 5158c2ecf20Sopenharmony_ci __v3_prev_block_seq_num, __v3_prev_block_seq_num + 1, 5168c2ecf20Sopenharmony_ci (uint64_t) pbd->h1.seq_num); 5178c2ecf20Sopenharmony_ci exit(1); 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci __v3_prev_block_seq_num = pbd->h1.seq_num; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic void __v3_test_block_len(struct block_desc *pbd, uint32_t bytes, int block_num) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci if (pbd->h1.num_pkts && bytes != pbd->h1.blk_len) { 5268c2ecf20Sopenharmony_ci fprintf(stderr, "\nblock:%u with %upackets, expected " 5278c2ecf20Sopenharmony_ci "len:%u != actual len:%u\n", block_num, 5288c2ecf20Sopenharmony_ci pbd->h1.num_pkts, bytes, pbd->h1.blk_len); 5298c2ecf20Sopenharmony_ci exit(1); 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic void __v3_test_block_header(struct block_desc *pbd, const int block_num) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci if ((pbd->h1.block_status & TP_STATUS_USER) == 0) { 5368c2ecf20Sopenharmony_ci fprintf(stderr, "\nblock %u: not in TP_STATUS_USER\n", block_num); 5378c2ecf20Sopenharmony_ci exit(1); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci __v3_test_block_seq_num(pbd); 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic void __v3_walk_block(struct block_desc *pbd, const int block_num) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci int num_pkts = pbd->h1.num_pkts, i; 5468c2ecf20Sopenharmony_ci unsigned long bytes = 0, bytes_with_padding = ALIGN_8(sizeof(*pbd)); 5478c2ecf20Sopenharmony_ci struct tpacket3_hdr *ppd; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci __v3_test_block_header(pbd, block_num); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd + 5528c2ecf20Sopenharmony_ci pbd->h1.offset_to_first_pkt); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci for (i = 0; i < num_pkts; ++i) { 5558c2ecf20Sopenharmony_ci bytes += ppd->tp_snaplen; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (ppd->tp_next_offset) 5588c2ecf20Sopenharmony_ci bytes_with_padding += ppd->tp_next_offset; 5598c2ecf20Sopenharmony_ci else 5608c2ecf20Sopenharmony_ci bytes_with_padding += ALIGN_8(ppd->tp_snaplen + ppd->tp_mac); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci test_payload((uint8_t *) ppd + ppd->tp_mac, ppd->tp_snaplen); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci status_bar_update(); 5658c2ecf20Sopenharmony_ci total_packets++; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci ppd = (struct tpacket3_hdr *) ((uint8_t *) ppd + ppd->tp_next_offset); 5688c2ecf20Sopenharmony_ci __sync_synchronize(); 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci __v3_test_block_len(pbd, bytes_with_padding, block_num); 5728c2ecf20Sopenharmony_ci total_bytes += bytes; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_civoid __v3_flush_block(struct block_desc *pbd) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci pbd->h1.block_status = TP_STATUS_KERNEL; 5788c2ecf20Sopenharmony_ci __sync_synchronize(); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic void walk_v3_rx(int sock, struct ring *ring) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci unsigned int block_num = 0; 5848c2ecf20Sopenharmony_ci struct pollfd pfd; 5858c2ecf20Sopenharmony_ci struct block_desc *pbd; 5868c2ecf20Sopenharmony_ci int udp_sock[2]; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci bug_on(ring->type != PACKET_RX_RING); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci pair_udp_open(udp_sock, PORT_BASE); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci memset(&pfd, 0, sizeof(pfd)); 5938c2ecf20Sopenharmony_ci pfd.fd = sock; 5948c2ecf20Sopenharmony_ci pfd.events = POLLIN | POLLERR; 5958c2ecf20Sopenharmony_ci pfd.revents = 0; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci pair_udp_send(udp_sock, NUM_PACKETS); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci while (total_packets < NUM_PACKETS * 2) { 6008c2ecf20Sopenharmony_ci pbd = (struct block_desc *) ring->rd[block_num].iov_base; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci while ((pbd->h1.block_status & TP_STATUS_USER) == 0) 6038c2ecf20Sopenharmony_ci poll(&pfd, 1, 1); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci __v3_walk_block(pbd, block_num); 6068c2ecf20Sopenharmony_ci __v3_flush_block(pbd); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci block_num = (block_num + 1) % ring->rd_num; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci pair_udp_close(udp_sock); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (total_packets != 2 * NUM_PACKETS) { 6148c2ecf20Sopenharmony_ci fprintf(stderr, "walk_v3_rx: received %u out of %u pkts\n", 6158c2ecf20Sopenharmony_ci total_packets, NUM_PACKETS); 6168c2ecf20Sopenharmony_ci exit(1); 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, total_bytes >> 1); 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic void walk_v3(int sock, struct ring *ring) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci if (ring->type == PACKET_RX_RING) 6258c2ecf20Sopenharmony_ci walk_v3_rx(sock, ring); 6268c2ecf20Sopenharmony_ci else 6278c2ecf20Sopenharmony_ci walk_tx(sock, ring); 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic void __v1_v2_fill(struct ring *ring, unsigned int blocks) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci ring->req.tp_block_size = getpagesize() << 2; 6338c2ecf20Sopenharmony_ci ring->req.tp_frame_size = TPACKET_ALIGNMENT << 7; 6348c2ecf20Sopenharmony_ci ring->req.tp_block_nr = blocks; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci ring->req.tp_frame_nr = ring->req.tp_block_size / 6378c2ecf20Sopenharmony_ci ring->req.tp_frame_size * 6388c2ecf20Sopenharmony_ci ring->req.tp_block_nr; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci ring->mm_len = ring->req.tp_block_size * ring->req.tp_block_nr; 6418c2ecf20Sopenharmony_ci ring->walk = walk_v1_v2; 6428c2ecf20Sopenharmony_ci ring->rd_num = ring->req.tp_frame_nr; 6438c2ecf20Sopenharmony_ci ring->flen = ring->req.tp_frame_size; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic void __v3_fill(struct ring *ring, unsigned int blocks, int type) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci if (type == PACKET_RX_RING) { 6498c2ecf20Sopenharmony_ci ring->req3.tp_retire_blk_tov = 64; 6508c2ecf20Sopenharmony_ci ring->req3.tp_sizeof_priv = 0; 6518c2ecf20Sopenharmony_ci ring->req3.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci ring->req3.tp_block_size = getpagesize() << 2; 6548c2ecf20Sopenharmony_ci ring->req3.tp_frame_size = TPACKET_ALIGNMENT << 7; 6558c2ecf20Sopenharmony_ci ring->req3.tp_block_nr = blocks; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci ring->req3.tp_frame_nr = ring->req3.tp_block_size / 6588c2ecf20Sopenharmony_ci ring->req3.tp_frame_size * 6598c2ecf20Sopenharmony_ci ring->req3.tp_block_nr; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci ring->mm_len = ring->req3.tp_block_size * ring->req3.tp_block_nr; 6628c2ecf20Sopenharmony_ci ring->walk = walk_v3; 6638c2ecf20Sopenharmony_ci ring->rd_num = ring->req3.tp_block_nr; 6648c2ecf20Sopenharmony_ci ring->flen = ring->req3.tp_block_size; 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic void setup_ring(int sock, struct ring *ring, int version, int type) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci int ret = 0; 6708c2ecf20Sopenharmony_ci unsigned int blocks = 256; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci ring->type = type; 6738c2ecf20Sopenharmony_ci ring->version = version; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci switch (version) { 6768c2ecf20Sopenharmony_ci case TPACKET_V1: 6778c2ecf20Sopenharmony_ci case TPACKET_V2: 6788c2ecf20Sopenharmony_ci if (type == PACKET_TX_RING) 6798c2ecf20Sopenharmony_ci __v1_v2_set_packet_loss_discard(sock); 6808c2ecf20Sopenharmony_ci __v1_v2_fill(ring, blocks); 6818c2ecf20Sopenharmony_ci ret = setsockopt(sock, SOL_PACKET, type, &ring->req, 6828c2ecf20Sopenharmony_ci sizeof(ring->req)); 6838c2ecf20Sopenharmony_ci break; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci case TPACKET_V3: 6868c2ecf20Sopenharmony_ci __v3_fill(ring, blocks, type); 6878c2ecf20Sopenharmony_ci ret = setsockopt(sock, SOL_PACKET, type, &ring->req3, 6888c2ecf20Sopenharmony_ci sizeof(ring->req3)); 6898c2ecf20Sopenharmony_ci break; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (ret == -1) { 6938c2ecf20Sopenharmony_ci perror("setsockopt"); 6948c2ecf20Sopenharmony_ci exit(1); 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci ring->rd_len = ring->rd_num * sizeof(*ring->rd); 6988c2ecf20Sopenharmony_ci ring->rd = malloc(ring->rd_len); 6998c2ecf20Sopenharmony_ci if (ring->rd == NULL) { 7008c2ecf20Sopenharmony_ci perror("malloc"); 7018c2ecf20Sopenharmony_ci exit(1); 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci total_packets = 0; 7058c2ecf20Sopenharmony_ci total_bytes = 0; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic void mmap_ring(int sock, struct ring *ring) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci int i; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci ring->mm_space = mmap(0, ring->mm_len, PROT_READ | PROT_WRITE, 7138c2ecf20Sopenharmony_ci MAP_SHARED | MAP_LOCKED | MAP_POPULATE, sock, 0); 7148c2ecf20Sopenharmony_ci if (ring->mm_space == MAP_FAILED) { 7158c2ecf20Sopenharmony_ci perror("mmap"); 7168c2ecf20Sopenharmony_ci exit(1); 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci memset(ring->rd, 0, ring->rd_len); 7208c2ecf20Sopenharmony_ci for (i = 0; i < ring->rd_num; ++i) { 7218c2ecf20Sopenharmony_ci ring->rd[i].iov_base = ring->mm_space + (i * ring->flen); 7228c2ecf20Sopenharmony_ci ring->rd[i].iov_len = ring->flen; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic void bind_ring(int sock, struct ring *ring) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci int ret; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci pair_udp_setfilter(sock); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci ring->ll.sll_family = PF_PACKET; 7338c2ecf20Sopenharmony_ci ring->ll.sll_protocol = htons(ETH_P_ALL); 7348c2ecf20Sopenharmony_ci ring->ll.sll_ifindex = if_nametoindex("lo"); 7358c2ecf20Sopenharmony_ci ring->ll.sll_hatype = 0; 7368c2ecf20Sopenharmony_ci ring->ll.sll_pkttype = 0; 7378c2ecf20Sopenharmony_ci ring->ll.sll_halen = 0; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci ret = bind(sock, (struct sockaddr *) &ring->ll, sizeof(ring->ll)); 7408c2ecf20Sopenharmony_ci if (ret == -1) { 7418c2ecf20Sopenharmony_ci perror("bind"); 7428c2ecf20Sopenharmony_ci exit(1); 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic void walk_ring(int sock, struct ring *ring) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci ring->walk(sock, ring); 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic void unmap_ring(int sock, struct ring *ring) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci munmap(ring->mm_space, ring->mm_len); 7548c2ecf20Sopenharmony_ci free(ring->rd); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int test_kernel_bit_width(void) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci char in[512], *ptr; 7608c2ecf20Sopenharmony_ci int num = 0, fd; 7618c2ecf20Sopenharmony_ci ssize_t ret; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci fd = open("/proc/kallsyms", O_RDONLY); 7648c2ecf20Sopenharmony_ci if (fd == -1) { 7658c2ecf20Sopenharmony_ci perror("open"); 7668c2ecf20Sopenharmony_ci exit(1); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci ret = read(fd, in, sizeof(in)); 7708c2ecf20Sopenharmony_ci if (ret <= 0) { 7718c2ecf20Sopenharmony_ci perror("read"); 7728c2ecf20Sopenharmony_ci exit(1); 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci close(fd); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci ptr = in; 7788c2ecf20Sopenharmony_ci while(!isspace(*ptr)) { 7798c2ecf20Sopenharmony_ci num++; 7808c2ecf20Sopenharmony_ci ptr++; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci return num * 4; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic int test_user_bit_width(void) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci return __WORDSIZE; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic const char *tpacket_str[] = { 7928c2ecf20Sopenharmony_ci [TPACKET_V1] = "TPACKET_V1", 7938c2ecf20Sopenharmony_ci [TPACKET_V2] = "TPACKET_V2", 7948c2ecf20Sopenharmony_ci [TPACKET_V3] = "TPACKET_V3", 7958c2ecf20Sopenharmony_ci}; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic const char *type_str[] = { 7988c2ecf20Sopenharmony_ci [PACKET_RX_RING] = "PACKET_RX_RING", 7998c2ecf20Sopenharmony_ci [PACKET_TX_RING] = "PACKET_TX_RING", 8008c2ecf20Sopenharmony_ci}; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic int test_tpacket(int version, int type) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci int sock; 8058c2ecf20Sopenharmony_ci struct ring ring; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci fprintf(stderr, "test: %s with %s ", tpacket_str[version], 8088c2ecf20Sopenharmony_ci type_str[type]); 8098c2ecf20Sopenharmony_ci fflush(stderr); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (version == TPACKET_V1 && 8128c2ecf20Sopenharmony_ci test_kernel_bit_width() != test_user_bit_width()) { 8138c2ecf20Sopenharmony_ci fprintf(stderr, "test: skip %s %s since user and kernel " 8148c2ecf20Sopenharmony_ci "space have different bit width\n", 8158c2ecf20Sopenharmony_ci tpacket_str[version], type_str[type]); 8168c2ecf20Sopenharmony_ci return KSFT_SKIP; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci sock = pfsocket(version); 8208c2ecf20Sopenharmony_ci memset(&ring, 0, sizeof(ring)); 8218c2ecf20Sopenharmony_ci setup_ring(sock, &ring, version, type); 8228c2ecf20Sopenharmony_ci mmap_ring(sock, &ring); 8238c2ecf20Sopenharmony_ci bind_ring(sock, &ring); 8248c2ecf20Sopenharmony_ci walk_ring(sock, &ring); 8258c2ecf20Sopenharmony_ci unmap_ring(sock, &ring); 8268c2ecf20Sopenharmony_ci close(sock); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci fprintf(stderr, "\n"); 8298c2ecf20Sopenharmony_ci return 0; 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ciint main(void) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci int ret = 0; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci ret |= test_tpacket(TPACKET_V1, PACKET_RX_RING); 8378c2ecf20Sopenharmony_ci ret |= test_tpacket(TPACKET_V1, PACKET_TX_RING); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci ret |= test_tpacket(TPACKET_V2, PACKET_RX_RING); 8408c2ecf20Sopenharmony_ci ret |= test_tpacket(TPACKET_V2, PACKET_TX_RING); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci ret |= test_tpacket(TPACKET_V3, PACKET_RX_RING); 8438c2ecf20Sopenharmony_ci ret |= test_tpacket(TPACKET_V3, PACKET_TX_RING); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (ret) 8468c2ecf20Sopenharmony_ci return 1; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci printf("OK. All tests passed\n"); 8498c2ecf20Sopenharmony_ci return 0; 8508c2ecf20Sopenharmony_ci} 851