File Index
Files and directories
Sign in
FILE

xdp_helper.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/net/lib/xdp_helper.c C
  1// SPDX-License-Identifier: GPL-2.0
  2#include <errno.h>
  3#include <stdio.h>
  4#include <stdlib.h>
  5#include <string.h>
  6#include <unistd.h>
  7#include <sys/mman.h>
  8#include <sys/socket.h>
  9#include <linux/if_xdp.h>
 10#include <linux/if_link.h>
 11#include <net/if.h>
 12#include <inttypes.h>
 13
 14#include "ksft.h"
 15
 16#define UMEM_SZ (1U << 16)
 17#define NUM_DESC (UMEM_SZ / 2048)
 18
 19
 20static void print_usage(const char *bin)
 21{
 22	fprintf(stderr, "Usage: %s ifindex queue_id [-z]\n\n"
 23		"where:\n\t-z: force zerocopy mode", bin);
 24}
 25
 26/* this is a simple helper program that creates an XDP socket and does the
 27 * minimum necessary to get bind() to succeed.
 28 *
 29 * this test program is not intended to actually process packets, but could be
 30 * extended in the future if that is actually needed.
 31 *
 32 * it is used by queues.py to ensure the xsk netlinux attribute is set
 33 * correctly.
 34 */
 35int main(int argc, char **argv)
 36{
 37	struct xdp_umem_reg umem_reg = { 0 };
 38	struct sockaddr_xdp sxdp = { 0 };
 39	int num_desc = NUM_DESC;
 40	void *umem_area;
 41	int retry = 0;
 42	int ifindex;
 43	int sock_fd;
 44	int queue;
 45
 46	if (argc != 3 && argc != 4) {
 47		print_usage(argv[0]);
 48		return 1;
 49	}
 50
 51	sock_fd = socket(AF_XDP, SOCK_RAW, 0);
 52	if (sock_fd < 0) {
 53		perror("socket creation failed");
 54		/* if the kernel doesn't support AF_XDP, let the test program
 55		 * know with -1. All other error paths return 1.
 56		 */
 57		if (errno == EAFNOSUPPORT)
 58			return -1;
 59		return 1;
 60	}
 61
 62	/* "Probing mode", just checking if AF_XDP sockets are supported */
 63	if (!strcmp(argv[1], "-") && !strcmp(argv[2], "-")) {
 64		printf("AF_XDP support detected\n");
 65		close(sock_fd);
 66		return 0;
 67	}
 68
 69	ifindex = atoi(argv[1]);
 70	queue = atoi(argv[2]);
 71
 72	umem_area = mmap(NULL, UMEM_SZ, PROT_READ | PROT_WRITE, MAP_PRIVATE |
 73			MAP_ANONYMOUS, -1, 0);
 74	if (umem_area == MAP_FAILED) {
 75		perror("mmap failed");
 76		return 1;
 77	}
 78
 79	umem_reg.addr = (uintptr_t)umem_area;
 80	umem_reg.len = UMEM_SZ;
 81	umem_reg.chunk_size = 2048;
 82	umem_reg.headroom = 0;
 83
 84	setsockopt(sock_fd, SOL_XDP, XDP_UMEM_REG, &umem_reg,
 85		   sizeof(umem_reg));
 86	setsockopt(sock_fd, SOL_XDP, XDP_UMEM_FILL_RING, &num_desc,
 87		   sizeof(num_desc));
 88	setsockopt(sock_fd, SOL_XDP, XDP_UMEM_COMPLETION_RING, &num_desc,
 89		   sizeof(num_desc));
 90	setsockopt(sock_fd, SOL_XDP, XDP_RX_RING, &num_desc, sizeof(num_desc));
 91
 92	sxdp.sxdp_family = AF_XDP;
 93	sxdp.sxdp_ifindex = ifindex;
 94	sxdp.sxdp_queue_id = queue;
 95	sxdp.sxdp_flags = 0;
 96
 97	if (argc > 3) {
 98		if (!strcmp(argv[3], "-z")) {
 99			sxdp.sxdp_flags = XDP_ZEROCOPY;
100		} else {
101			print_usage(argv[0]);
102			return 1;
103		}
104	}
105
106	while (1) {
107		if (bind(sock_fd, (struct sockaddr *)&sxdp, sizeof(sxdp)) == 0)
108			break;
109
110		if (errno == EBUSY && retry < 3) {
111			retry++;
112			sleep(1);
113			continue;
114		} else {
115			perror("bind failed");
116			munmap(umem_area, UMEM_SZ);
117			close(sock_fd);
118			return 1;
119		}
120	}
121
122	ksft_ready();
123	ksft_wait();
124
125	/* parent program will write a byte to stdin when its ready for this
126	 * helper to exit
127	 */
128
129	close(sock_fd);
130	return 0;
131}
~/ Read-only file preview.