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