root/tools/testing/selftests/net/reuseport_bpf_numa.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. build_rcv_group
  2. attach_bpf
  3. send_from_node
  4. receive_on_node
  5. test
  6. main

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Test functionality of BPF filters with SO_REUSEPORT. Same test as
   4  * in reuseport_bpf_cpu, only as one socket per NUMA node.
   5  */
   6 
   7 #define _GNU_SOURCE
   8 
   9 #include <arpa/inet.h>
  10 #include <errno.h>
  11 #include <error.h>
  12 #include <linux/filter.h>
  13 #include <linux/bpf.h>
  14 #include <linux/in.h>
  15 #include <linux/unistd.h>
  16 #include <sched.h>
  17 #include <stdio.h>
  18 #include <stdlib.h>
  19 #include <string.h>
  20 #include <sys/epoll.h>
  21 #include <sys/types.h>
  22 #include <sys/socket.h>
  23 #include <unistd.h>
  24 #include <numa.h>
  25 
  26 #include "../kselftest.h"
  27 
  28 static const int PORT = 8888;
  29 
  30 static void build_rcv_group(int *rcv_fd, size_t len, int family, int proto)
  31 {
  32         struct sockaddr_storage addr;
  33         struct sockaddr_in  *addr4;
  34         struct sockaddr_in6 *addr6;
  35         size_t i;
  36         int opt;
  37 
  38         switch (family) {
  39         case AF_INET:
  40                 addr4 = (struct sockaddr_in *)&addr;
  41                 addr4->sin_family = AF_INET;
  42                 addr4->sin_addr.s_addr = htonl(INADDR_ANY);
  43                 addr4->sin_port = htons(PORT);
  44                 break;
  45         case AF_INET6:
  46                 addr6 = (struct sockaddr_in6 *)&addr;
  47                 addr6->sin6_family = AF_INET6;
  48                 addr6->sin6_addr = in6addr_any;
  49                 addr6->sin6_port = htons(PORT);
  50                 break;
  51         default:
  52                 error(1, 0, "Unsupported family %d", family);
  53         }
  54 
  55         for (i = 0; i < len; ++i) {
  56                 rcv_fd[i] = socket(family, proto, 0);
  57                 if (rcv_fd[i] < 0)
  58                         error(1, errno, "failed to create receive socket");
  59 
  60                 opt = 1;
  61                 if (setsockopt(rcv_fd[i], SOL_SOCKET, SO_REUSEPORT, &opt,
  62                                sizeof(opt)))
  63                         error(1, errno, "failed to set SO_REUSEPORT");
  64 
  65                 if (bind(rcv_fd[i], (struct sockaddr *)&addr, sizeof(addr)))
  66                         error(1, errno, "failed to bind receive socket");
  67 
  68                 if (proto == SOCK_STREAM && listen(rcv_fd[i], len * 10))
  69                         error(1, errno, "failed to listen on receive port");
  70         }
  71 }
  72 
  73 static void attach_bpf(int fd)
  74 {
  75         static char bpf_log_buf[65536];
  76         static const char bpf_license[] = "";
  77 
  78         int bpf_fd;
  79         const struct bpf_insn prog[] = {
  80                 /* R0 = bpf_get_numa_node_id() */
  81                 { BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_numa_node_id },
  82                 /* return R0 */
  83                 { BPF_JMP | BPF_EXIT, 0, 0, 0, 0 }
  84         };
  85         union bpf_attr attr;
  86 
  87         memset(&attr, 0, sizeof(attr));
  88         attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
  89         attr.insn_cnt = sizeof(prog) / sizeof(prog[0]);
  90         attr.insns = (unsigned long) &prog;
  91         attr.license = (unsigned long) &bpf_license;
  92         attr.log_buf = (unsigned long) &bpf_log_buf;
  93         attr.log_size = sizeof(bpf_log_buf);
  94         attr.log_level = 1;
  95 
  96         bpf_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
  97         if (bpf_fd < 0)
  98                 error(1, errno, "ebpf error. log:\n%s\n", bpf_log_buf);
  99 
 100         if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &bpf_fd,
 101                         sizeof(bpf_fd)))
 102                 error(1, errno, "failed to set SO_ATTACH_REUSEPORT_EBPF");
 103 
 104         close(bpf_fd);
 105 }
 106 
 107 static void send_from_node(int node_id, int family, int proto)
 108 {
 109         struct sockaddr_storage saddr, daddr;
 110         struct sockaddr_in  *saddr4, *daddr4;
 111         struct sockaddr_in6 *saddr6, *daddr6;
 112         int fd;
 113 
 114         switch (family) {
 115         case AF_INET:
 116                 saddr4 = (struct sockaddr_in *)&saddr;
 117                 saddr4->sin_family = AF_INET;
 118                 saddr4->sin_addr.s_addr = htonl(INADDR_ANY);
 119                 saddr4->sin_port = 0;
 120 
 121                 daddr4 = (struct sockaddr_in *)&daddr;
 122                 daddr4->sin_family = AF_INET;
 123                 daddr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 124                 daddr4->sin_port = htons(PORT);
 125                 break;
 126         case AF_INET6:
 127                 saddr6 = (struct sockaddr_in6 *)&saddr;
 128                 saddr6->sin6_family = AF_INET6;
 129                 saddr6->sin6_addr = in6addr_any;
 130                 saddr6->sin6_port = 0;
 131 
 132                 daddr6 = (struct sockaddr_in6 *)&daddr;
 133                 daddr6->sin6_family = AF_INET6;
 134                 daddr6->sin6_addr = in6addr_loopback;
 135                 daddr6->sin6_port = htons(PORT);
 136                 break;
 137         default:
 138                 error(1, 0, "Unsupported family %d", family);
 139         }
 140 
 141         if (numa_run_on_node(node_id) < 0)
 142                 error(1, errno, "failed to pin to node");
 143 
 144         fd = socket(family, proto, 0);
 145         if (fd < 0)
 146                 error(1, errno, "failed to create send socket");
 147 
 148         if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)))
 149                 error(1, errno, "failed to bind send socket");
 150 
 151         if (connect(fd, (struct sockaddr *)&daddr, sizeof(daddr)))
 152                 error(1, errno, "failed to connect send socket");
 153 
 154         if (send(fd, "a", 1, 0) < 0)
 155                 error(1, errno, "failed to send message");
 156 
 157         close(fd);
 158 }
 159 
 160 static
 161 void receive_on_node(int *rcv_fd, int len, int epfd, int node_id, int proto)
 162 {
 163         struct epoll_event ev;
 164         int i, fd;
 165         char buf[8];
 166 
 167         i = epoll_wait(epfd, &ev, 1, -1);
 168         if (i < 0)
 169                 error(1, errno, "epoll_wait failed");
 170 
 171         if (proto == SOCK_STREAM) {
 172                 fd = accept(ev.data.fd, NULL, NULL);
 173                 if (fd < 0)
 174                         error(1, errno, "failed to accept");
 175                 i = recv(fd, buf, sizeof(buf), 0);
 176                 close(fd);
 177         } else {
 178                 i = recv(ev.data.fd, buf, sizeof(buf), 0);
 179         }
 180 
 181         if (i < 0)
 182                 error(1, errno, "failed to recv");
 183 
 184         for (i = 0; i < len; ++i)
 185                 if (ev.data.fd == rcv_fd[i])
 186                         break;
 187         if (i == len)
 188                 error(1, 0, "failed to find socket");
 189         fprintf(stderr, "send node %d, receive socket %d\n", node_id, i);
 190         if (node_id != i)
 191                 error(1, 0, "node id/receive socket mismatch");
 192 }
 193 
 194 static void test(int *rcv_fd, int len, int family, int proto)
 195 {
 196         struct epoll_event ev;
 197         int epfd, node;
 198 
 199         build_rcv_group(rcv_fd, len, family, proto);
 200         attach_bpf(rcv_fd[0]);
 201 
 202         epfd = epoll_create(1);
 203         if (epfd < 0)
 204                 error(1, errno, "failed to create epoll");
 205         for (node = 0; node < len; ++node) {
 206                 ev.events = EPOLLIN;
 207                 ev.data.fd = rcv_fd[node];
 208                 if (epoll_ctl(epfd, EPOLL_CTL_ADD, rcv_fd[node], &ev))
 209                         error(1, errno, "failed to register sock epoll");
 210         }
 211 
 212         /* Forward iterate */
 213         for (node = 0; node < len; ++node) {
 214                 send_from_node(node, family, proto);
 215                 receive_on_node(rcv_fd, len, epfd, node, proto);
 216         }
 217 
 218         /* Reverse iterate */
 219         for (node = len - 1; node >= 0; --node) {
 220                 send_from_node(node, family, proto);
 221                 receive_on_node(rcv_fd, len, epfd, node, proto);
 222         }
 223 
 224         close(epfd);
 225         for (node = 0; node < len; ++node)
 226                 close(rcv_fd[node]);
 227 }
 228 
 229 int main(void)
 230 {
 231         int *rcv_fd, nodes;
 232 
 233         if (numa_available() < 0)
 234                 ksft_exit_skip("no numa api support\n");
 235 
 236         nodes = numa_max_node() + 1;
 237 
 238         rcv_fd = calloc(nodes, sizeof(int));
 239         if (!rcv_fd)
 240                 error(1, 0, "failed to allocate array");
 241 
 242         fprintf(stderr, "---- IPv4 UDP ----\n");
 243         test(rcv_fd, nodes, AF_INET, SOCK_DGRAM);
 244 
 245         fprintf(stderr, "---- IPv6 UDP ----\n");
 246         test(rcv_fd, nodes, AF_INET6, SOCK_DGRAM);
 247 
 248         fprintf(stderr, "---- IPv4 TCP ----\n");
 249         test(rcv_fd, nodes, AF_INET, SOCK_STREAM);
 250 
 251         fprintf(stderr, "---- IPv6 TCP ----\n");
 252         test(rcv_fd, nodes, AF_INET6, SOCK_STREAM);
 253 
 254         free(rcv_fd);
 255 
 256         fprintf(stderr, "SUCCESS\n");
 257         return 0;
 258 }

/* [<][>][^][v][top][bottom][index][help] */