xref: /linux/tools/testing/selftests/net/lib/xdp_helper.c (revision 1b98f357dadd6ea613a435fbaef1a5dd7b35fd21)
159dd07dbSBui Quang Minh // SPDX-License-Identifier: GPL-2.0
259dd07dbSBui Quang Minh #include <errno.h>
359dd07dbSBui Quang Minh #include <stdio.h>
459dd07dbSBui Quang Minh #include <stdlib.h>
559dd07dbSBui Quang Minh #include <string.h>
659dd07dbSBui Quang Minh #include <unistd.h>
759dd07dbSBui Quang Minh #include <sys/mman.h>
859dd07dbSBui Quang Minh #include <sys/socket.h>
959dd07dbSBui Quang Minh #include <linux/if_xdp.h>
1059dd07dbSBui Quang Minh #include <linux/if_link.h>
1159dd07dbSBui Quang Minh #include <net/if.h>
1259dd07dbSBui Quang Minh #include <inttypes.h>
1359dd07dbSBui Quang Minh 
1459dd07dbSBui Quang Minh #include "ksft.h"
1559dd07dbSBui Quang Minh 
1659dd07dbSBui Quang Minh #define UMEM_SZ (1U << 16)
1759dd07dbSBui Quang Minh #define NUM_DESC (UMEM_SZ / 2048)
1859dd07dbSBui Quang Minh 
1959dd07dbSBui Quang Minh 
205d346179SBui Quang Minh static void print_usage(const char *bin)
215d346179SBui Quang Minh {
225d346179SBui Quang Minh 	fprintf(stderr, "Usage: %s ifindex queue_id [-z]\n\n"
235d346179SBui Quang Minh 		"where:\n\t-z: force zerocopy mode", bin);
245d346179SBui Quang Minh }
255d346179SBui Quang Minh 
2659dd07dbSBui Quang Minh /* this is a simple helper program that creates an XDP socket and does the
2759dd07dbSBui Quang Minh  * minimum necessary to get bind() to succeed.
2859dd07dbSBui Quang Minh  *
2959dd07dbSBui Quang Minh  * this test program is not intended to actually process packets, but could be
3059dd07dbSBui Quang Minh  * extended in the future if that is actually needed.
3159dd07dbSBui Quang Minh  *
3259dd07dbSBui Quang Minh  * it is used by queues.py to ensure the xsk netlinux attribute is set
3359dd07dbSBui Quang Minh  * correctly.
3459dd07dbSBui Quang Minh  */
3559dd07dbSBui Quang Minh int main(int argc, char **argv)
3659dd07dbSBui Quang Minh {
3759dd07dbSBui Quang Minh 	struct xdp_umem_reg umem_reg = { 0 };
3859dd07dbSBui Quang Minh 	struct sockaddr_xdp sxdp = { 0 };
3959dd07dbSBui Quang Minh 	int num_desc = NUM_DESC;
4059dd07dbSBui Quang Minh 	void *umem_area;
41*b2b4555cSBui Quang Minh 	int retry = 0;
4259dd07dbSBui Quang Minh 	int ifindex;
4359dd07dbSBui Quang Minh 	int sock_fd;
4459dd07dbSBui Quang Minh 	int queue;
4559dd07dbSBui Quang Minh 
465d346179SBui Quang Minh 	if (argc != 3 && argc != 4) {
475d346179SBui Quang Minh 		print_usage(argv[0]);
4859dd07dbSBui Quang Minh 		return 1;
4959dd07dbSBui Quang Minh 	}
5059dd07dbSBui Quang Minh 
5159dd07dbSBui Quang Minh 	sock_fd = socket(AF_XDP, SOCK_RAW, 0);
5259dd07dbSBui Quang Minh 	if (sock_fd < 0) {
5359dd07dbSBui Quang Minh 		perror("socket creation failed");
5459dd07dbSBui Quang Minh 		/* if the kernel doesn't support AF_XDP, let the test program
5559dd07dbSBui Quang Minh 		 * know with -1. All other error paths return 1.
5659dd07dbSBui Quang Minh 		 */
5759dd07dbSBui Quang Minh 		if (errno == EAFNOSUPPORT)
5859dd07dbSBui Quang Minh 			return -1;
5959dd07dbSBui Quang Minh 		return 1;
6059dd07dbSBui Quang Minh 	}
6159dd07dbSBui Quang Minh 
6259dd07dbSBui Quang Minh 	/* "Probing mode", just checking if AF_XDP sockets are supported */
6359dd07dbSBui Quang Minh 	if (!strcmp(argv[1], "-") && !strcmp(argv[2], "-")) {
6459dd07dbSBui Quang Minh 		printf("AF_XDP support detected\n");
6559dd07dbSBui Quang Minh 		close(sock_fd);
6659dd07dbSBui Quang Minh 		return 0;
6759dd07dbSBui Quang Minh 	}
6859dd07dbSBui Quang Minh 
6959dd07dbSBui Quang Minh 	ifindex = atoi(argv[1]);
7059dd07dbSBui Quang Minh 	queue = atoi(argv[2]);
7159dd07dbSBui Quang Minh 
7259dd07dbSBui Quang Minh 	umem_area = mmap(NULL, UMEM_SZ, PROT_READ | PROT_WRITE, MAP_PRIVATE |
7359dd07dbSBui Quang Minh 			MAP_ANONYMOUS, -1, 0);
7459dd07dbSBui Quang Minh 	if (umem_area == MAP_FAILED) {
7559dd07dbSBui Quang Minh 		perror("mmap failed");
7659dd07dbSBui Quang Minh 		return 1;
7759dd07dbSBui Quang Minh 	}
7859dd07dbSBui Quang Minh 
7959dd07dbSBui Quang Minh 	umem_reg.addr = (uintptr_t)umem_area;
8059dd07dbSBui Quang Minh 	umem_reg.len = UMEM_SZ;
8159dd07dbSBui Quang Minh 	umem_reg.chunk_size = 2048;
8259dd07dbSBui Quang Minh 	umem_reg.headroom = 0;
8359dd07dbSBui Quang Minh 
8459dd07dbSBui Quang Minh 	setsockopt(sock_fd, SOL_XDP, XDP_UMEM_REG, &umem_reg,
8559dd07dbSBui Quang Minh 		   sizeof(umem_reg));
8659dd07dbSBui Quang Minh 	setsockopt(sock_fd, SOL_XDP, XDP_UMEM_FILL_RING, &num_desc,
8759dd07dbSBui Quang Minh 		   sizeof(num_desc));
8859dd07dbSBui Quang Minh 	setsockopt(sock_fd, SOL_XDP, XDP_UMEM_COMPLETION_RING, &num_desc,
8959dd07dbSBui Quang Minh 		   sizeof(num_desc));
9059dd07dbSBui Quang Minh 	setsockopt(sock_fd, SOL_XDP, XDP_RX_RING, &num_desc, sizeof(num_desc));
9159dd07dbSBui Quang Minh 
9259dd07dbSBui Quang Minh 	sxdp.sxdp_family = AF_XDP;
9359dd07dbSBui Quang Minh 	sxdp.sxdp_ifindex = ifindex;
9459dd07dbSBui Quang Minh 	sxdp.sxdp_queue_id = queue;
9559dd07dbSBui Quang Minh 	sxdp.sxdp_flags = 0;
9659dd07dbSBui Quang Minh 
975d346179SBui Quang Minh 	if (argc > 3) {
985d346179SBui Quang Minh 		if (!strcmp(argv[3], "-z")) {
995d346179SBui Quang Minh 			sxdp.sxdp_flags = XDP_ZEROCOPY;
1005d346179SBui Quang Minh 		} else {
1015d346179SBui Quang Minh 			print_usage(argv[0]);
1025d346179SBui Quang Minh 			return 1;
1035d346179SBui Quang Minh 		}
1045d346179SBui Quang Minh 	}
1055d346179SBui Quang Minh 
106*b2b4555cSBui Quang Minh 	while (1) {
107*b2b4555cSBui Quang Minh 		if (bind(sock_fd, (struct sockaddr *)&sxdp, sizeof(sxdp)) == 0)
108*b2b4555cSBui Quang Minh 			break;
109*b2b4555cSBui Quang Minh 
110*b2b4555cSBui Quang Minh 		if (errno == EBUSY && retry < 3) {
111*b2b4555cSBui Quang Minh 			retry++;
112*b2b4555cSBui Quang Minh 			sleep(1);
113*b2b4555cSBui Quang Minh 			continue;
114*b2b4555cSBui Quang Minh 		} else {
11559dd07dbSBui Quang Minh 			perror("bind failed");
116*b2b4555cSBui Quang Minh 			munmap(umem_area, UMEM_SZ);
11759dd07dbSBui Quang Minh 			close(sock_fd);
11859dd07dbSBui Quang Minh 			return 1;
11959dd07dbSBui Quang Minh 		}
120*b2b4555cSBui Quang Minh 	}
12159dd07dbSBui Quang Minh 
12259dd07dbSBui Quang Minh 	ksft_ready();
12359dd07dbSBui Quang Minh 	ksft_wait();
12459dd07dbSBui Quang Minh 
12559dd07dbSBui Quang Minh 	/* parent program will write a byte to stdin when its ready for this
12659dd07dbSBui Quang Minh 	 * helper to exit
12759dd07dbSBui Quang Minh 	 */
12859dd07dbSBui Quang Minh 
12959dd07dbSBui Quang Minh 	close(sock_fd);
13059dd07dbSBui Quang Minh 	return 0;
13159dd07dbSBui Quang Minh }
132