brintos

brintos / linux-shallow public Read only

0
0
Text · 18.4 KiB · 404a2ce Raw
851 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 are11 *   known to fail (TODO) resp. succeed (OK).12 *13 * Datapath:14 *   Open a pair of packet sockets and send resp. receive an a priori known15 *   packet pattern accross the sockets and check if it was received resp.16 *   sent correctly. Fanout in combination with RX_RING is currently not17 *   tested here.18 *19 *   The test currently runs for20 *   - TPACKET_V1: RX_RING, TX_RING21 *   - TPACKET_V2: RX_RING, TX_RING22 *   - TPACKET_V3: RX_RING23 */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_on52# define bug_on(cond)		assert(!(cond))53#endif54 55#ifndef __aligned_tpacket56# define __aligned_tpacket	__attribute__((aligned(TPACKET_ALIGNMENT)))57#endif58 59#ifndef __align_tpacket60# define __align_tpacket(x)	__attribute__((aligned(TPACKET_ALIGN(x))))61#endif62 63#define NUM_PACKETS		10064#define ALIGN_8(x)		(((x) + 8 - 1) & ~(8 - 1))65 66struct 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 79struct block_desc {80	uint32_t version;81	uint32_t offset_to_priv;82	struct tpacket_hdr_v1 h1;83};84 85union 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 97static unsigned int total_packets, total_bytes;98 99static 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 116static void status_bar_update(void)117{118	if (total_packets % 10 == 0) {119		fprintf(stderr, ".");120		fflush(stderr);121	}122}123 124static 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 141static 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 passes148	 * 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 173static inline int __v1_rx_kernel_ready(struct tpacket_hdr *hdr)174{175	return ((hdr->tp_status & TP_STATUS_USER) == TP_STATUS_USER);176}177 178static inline void __v1_rx_user_ready(struct tpacket_hdr *hdr)179{180	hdr->tp_status = TP_STATUS_KERNEL;181	__sync_synchronize();182}183 184static inline int __v2_rx_kernel_ready(struct tpacket2_hdr *hdr)185{186	return ((hdr->tp_status & TP_STATUS_USER) == TP_STATUS_USER);187}188 189static inline void __v2_rx_user_ready(struct tpacket2_hdr *hdr)190{191	hdr->tp_status = TP_STATUS_KERNEL;192	__sync_synchronize();193}194 195static 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 208static 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 220static 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 279static 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 284static inline void __v1_tx_user_ready(struct tpacket_hdr *hdr)285{286	hdr->tp_status = TP_STATUS_SEND_REQUEST;287	__sync_synchronize();288}289 290static 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 295static inline void __v2_tx_user_ready(struct tpacket2_hdr *hdr)296{297	hdr->tp_status = TP_STATUS_SEND_REQUEST;298	__sync_synchronize();299}300 301static 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 306static inline void __v3_tx_user_ready(struct tpacket3_hdr *hdr)307{308	hdr->tp_status = TP_STATUS_SEND_REQUEST;309	__sync_synchronize();310}311 312static 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 327static 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 342static 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 354static 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 369static 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 based384	 * on frames (e.g., rd_num is tp_frame_nr) whereas V3 sets these385	 * 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	else390		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 500static 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	else505		walk_tx(sock, ring);506}507 508static uint64_t __v3_prev_block_seq_num = 0;509 510void __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 523static 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 533static 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 543static 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		else560			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 575void __v3_flush_block(struct block_desc *pbd)576{577	pbd->h1.block_status = TP_STATUS_KERNEL;578	__sync_synchronize();579}580 581static 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 622static void walk_v3(int sock, struct ring *ring)623{624	if (ring->type == PACKET_RX_RING)625		walk_v3_rx(sock, ring);626	else627		walk_tx(sock, ring);628}629 630static 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 646static 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 667static 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 708static 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 726static 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 746static void walk_ring(int sock, struct ring *ring)747{748	ring->walk(sock, ring);749}750 751static void unmap_ring(int sock, struct ring *ring)752{753	munmap(ring->mm_space, ring->mm_len);754	free(ring->rd);755}756 757static 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 786static int test_user_bit_width(void)787{788	return __WORDSIZE;789}790 791static const char *tpacket_str[] = {792	[TPACKET_V1] = "TPACKET_V1",793	[TPACKET_V2] = "TPACKET_V2",794	[TPACKET_V3] = "TPACKET_V3",795};796 797static const char *type_str[] = {798	[PACKET_RX_RING] = "PACKET_RX_RING",799	[PACKET_TX_RING] = "PACKET_TX_RING",800};801 802static 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 832int 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