~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/xdp_features.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 #include <uapi/linux/bpf.h>
  3 #include <uapi/linux/netdev.h>
  4 #include <linux/if_link.h>
  5 #include <signal.h>
  6 #include <argp.h>
  7 #include <net/if.h>
  8 #include <sys/socket.h>
  9 #include <netinet/in.h>
 10 #include <netinet/tcp.h>
 11 #include <unistd.h>
 12 #include <arpa/inet.h>
 13 #include <bpf/bpf.h>
 14 #include <bpf/libbpf.h>
 15 #include <pthread.h>
 16 
 17 #include <network_helpers.h>
 18 
 19 #include "xdp_features.skel.h"
 20 #include "xdp_features.h"
 21 
 22 #define RED(str)        "\033[0;31m" str "\033[0m"
 23 #define GREEN(str)      "\033[0;32m" str "\033[0m"
 24 #define YELLOW(str)     "\033[0;33m" str "\033[0m"
 25 
 26 static struct env {
 27         bool verbosity;
 28         char ifname[IF_NAMESIZE];
 29         int ifindex;
 30         bool is_tester;
 31         struct {
 32                 enum netdev_xdp_act drv_feature;
 33                 enum xdp_action action;
 34         } feature;
 35         struct sockaddr_storage dut_ctrl_addr;
 36         struct sockaddr_storage dut_addr;
 37         struct sockaddr_storage tester_addr;
 38 } env;
 39 
 40 #define BUFSIZE         128
 41 
 42 void test__fail(void) { /* for network_helpers.c */ }
 43 
 44 static int libbpf_print_fn(enum libbpf_print_level level,
 45                            const char *format, va_list args)
 46 {
 47         if (level == LIBBPF_DEBUG && !env.verbosity)
 48                 return 0;
 49         return vfprintf(stderr, format, args);
 50 }
 51 
 52 static volatile bool exiting;
 53 
 54 static void sig_handler(int sig)
 55 {
 56         exiting = true;
 57 }
 58 
 59 const char *argp_program_version = "xdp-features 0.0";
 60 const char argp_program_doc[] =
 61 "XDP features detection application.\n"
 62 "\n"
 63 "XDP features application checks the XDP advertised features match detected ones.\n"
 64 "\n"
 65 "USAGE: ./xdp-features [-vt] [-f <xdp-feature>] [-D <dut-data-ip>] [-T <tester-data-ip>] [-C <dut-ctrl-ip>] <iface-name>\n"
 66 "\n"
 67 "dut-data-ip, tester-data-ip, dut-ctrl-ip: IPv6 or IPv4-mapped-IPv6 addresses;\n"
 68 "\n"
 69 "XDP features\n:"
 70 "- XDP_PASS\n"
 71 "- XDP_DROP\n"
 72 "- XDP_ABORTED\n"
 73 "- XDP_REDIRECT\n"
 74 "- XDP_NDO_XMIT\n"
 75 "- XDP_TX\n";
 76 
 77 static const struct argp_option opts[] = {
 78         { "verbose", 'v', NULL, 0, "Verbose debug output" },
 79         { "tester", 't', NULL, 0, "Tester mode" },
 80         { "feature", 'f', "XDP-FEATURE", 0, "XDP feature to test" },
 81         { "dut_data_ip", 'D', "DUT-DATA-IP", 0, "DUT IP data channel" },
 82         { "dut_ctrl_ip", 'C', "DUT-CTRL-IP", 0, "DUT IP control channel" },
 83         { "tester_data_ip", 'T', "TESTER-DATA-IP", 0, "Tester IP data channel" },
 84         {},
 85 };
 86 
 87 static int get_xdp_feature(const char *arg)
 88 {
 89         if (!strcmp(arg, "XDP_PASS")) {
 90                 env.feature.action = XDP_PASS;
 91                 env.feature.drv_feature = NETDEV_XDP_ACT_BASIC;
 92         } else if (!strcmp(arg, "XDP_DROP")) {
 93                 env.feature.drv_feature = NETDEV_XDP_ACT_BASIC;
 94                 env.feature.action = XDP_DROP;
 95         } else if (!strcmp(arg, "XDP_ABORTED")) {
 96                 env.feature.drv_feature = NETDEV_XDP_ACT_BASIC;
 97                 env.feature.action = XDP_ABORTED;
 98         } else if (!strcmp(arg, "XDP_TX")) {
 99                 env.feature.drv_feature = NETDEV_XDP_ACT_BASIC;
100                 env.feature.action = XDP_TX;
101         } else if (!strcmp(arg, "XDP_REDIRECT")) {
102                 env.feature.drv_feature = NETDEV_XDP_ACT_REDIRECT;
103                 env.feature.action = XDP_REDIRECT;
104         } else if (!strcmp(arg, "XDP_NDO_XMIT")) {
105                 env.feature.drv_feature = NETDEV_XDP_ACT_NDO_XMIT;
106         } else {
107                 return -EINVAL;
108         }
109 
110         return 0;
111 }
112 
113 static char *get_xdp_feature_str(void)
114 {
115         switch (env.feature.action) {
116         case XDP_PASS:
117                 return YELLOW("XDP_PASS");
118         case XDP_DROP:
119                 return YELLOW("XDP_DROP");
120         case XDP_ABORTED:
121                 return YELLOW("XDP_ABORTED");
122         case XDP_TX:
123                 return YELLOW("XDP_TX");
124         case XDP_REDIRECT:
125                 return YELLOW("XDP_REDIRECT");
126         default:
127                 break;
128         }
129 
130         if (env.feature.drv_feature == NETDEV_XDP_ACT_NDO_XMIT)
131                 return YELLOW("XDP_NDO_XMIT");
132 
133         return "";
134 }
135 
136 static error_t parse_arg(int key, char *arg, struct argp_state *state)
137 {
138         switch (key) {
139         case 'v':
140                 env.verbosity = true;
141                 break;
142         case 't':
143                 env.is_tester = true;
144                 break;
145         case 'f':
146                 if (get_xdp_feature(arg) < 0) {
147                         fprintf(stderr, "Invalid xdp feature: %s\n", arg);
148                         argp_usage(state);
149                         return ARGP_ERR_UNKNOWN;
150                 }
151                 break;
152         case 'D':
153                 if (make_sockaddr(AF_INET6, arg, DUT_ECHO_PORT,
154                                   &env.dut_addr, NULL)) {
155                         fprintf(stderr,
156                                 "Invalid address assigned to the Device Under Test: %s\n",
157                                 arg);
158                         return ARGP_ERR_UNKNOWN;
159                 }
160                 break;
161         case 'C':
162                 if (make_sockaddr(AF_INET6, arg, DUT_CTRL_PORT,
163                                   &env.dut_ctrl_addr, NULL)) {
164                         fprintf(stderr,
165                                 "Invalid address assigned to the Device Under Test: %s\n",
166                                 arg);
167                         return ARGP_ERR_UNKNOWN;
168                 }
169                 break;
170         case 'T':
171                 if (make_sockaddr(AF_INET6, arg, 0, &env.tester_addr, NULL)) {
172                         fprintf(stderr,
173                                 "Invalid address assigned to the Tester device: %s\n",
174                                 arg);
175                         return ARGP_ERR_UNKNOWN;
176                 }
177                 break;
178         case ARGP_KEY_ARG:
179                 errno = 0;
180                 if (strlen(arg) >= IF_NAMESIZE) {
181                         fprintf(stderr, "Invalid device name: %s\n", arg);
182                         argp_usage(state);
183                         return ARGP_ERR_UNKNOWN;
184                 }
185 
186                 env.ifindex = if_nametoindex(arg);
187                 if (!env.ifindex)
188                         env.ifindex = strtoul(arg, NULL, 0);
189                 if (!env.ifindex || !if_indextoname(env.ifindex, env.ifname)) {
190                         fprintf(stderr,
191                                 "Bad interface index or name (%d): %s\n",
192                                 errno, strerror(errno));
193                         argp_usage(state);
194                         return ARGP_ERR_UNKNOWN;
195                 }
196                 break;
197         default:
198                 return ARGP_ERR_UNKNOWN;
199         }
200 
201         return 0;
202 }
203 
204 static const struct argp argp = {
205         .options = opts,
206         .parser = parse_arg,
207         .doc = argp_program_doc,
208 };
209 
210 static void set_env_default(void)
211 {
212         env.feature.drv_feature = NETDEV_XDP_ACT_NDO_XMIT;
213         env.feature.action = -EINVAL;
214         env.ifindex = -ENODEV;
215         strcpy(env.ifname, "unknown");
216         make_sockaddr(AF_INET6, "::ffff:127.0.0.1", DUT_CTRL_PORT,
217                       &env.dut_ctrl_addr, NULL);
218         make_sockaddr(AF_INET6, "::ffff:127.0.0.1", DUT_ECHO_PORT,
219                       &env.dut_addr, NULL);
220         make_sockaddr(AF_INET6, "::ffff:127.0.0.1", 0, &env.tester_addr, NULL);
221 }
222 
223 static void *dut_echo_thread(void *arg)
224 {
225         unsigned char buf[sizeof(struct tlv_hdr)];
226         int sockfd = *(int *)arg;
227 
228         while (!exiting) {
229                 struct tlv_hdr *tlv = (struct tlv_hdr *)buf;
230                 struct sockaddr_storage addr;
231                 socklen_t addrlen;
232                 size_t n;
233 
234                 n = recvfrom(sockfd, buf, sizeof(buf), MSG_WAITALL,
235                              (struct sockaddr *)&addr, &addrlen);
236                 if (n != ntohs(tlv->len))
237                         continue;
238 
239                 if (ntohs(tlv->type) != CMD_ECHO)
240                         continue;
241 
242                 sendto(sockfd, buf, sizeof(buf), MSG_NOSIGNAL | MSG_CONFIRM,
243                        (struct sockaddr *)&addr, addrlen);
244         }
245 
246         pthread_exit((void *)0);
247         close(sockfd);
248 
249         return NULL;
250 }
251 
252 static int dut_run_echo_thread(pthread_t *t, int *sockfd)
253 {
254         int err;
255 
256         sockfd = start_reuseport_server(AF_INET6, SOCK_DGRAM, NULL,
257                                         DUT_ECHO_PORT, 0, 1);
258         if (!sockfd) {
259                 fprintf(stderr,
260                         "Failed creating data UDP socket on device %s\n",
261                         env.ifname);
262                 return -errno;
263         }
264 
265         /* start echo channel */
266         err = pthread_create(t, NULL, dut_echo_thread, sockfd);
267         if (err) {
268                 fprintf(stderr,
269                         "Failed creating data UDP thread on device %s: %s\n",
270                         env.ifname, strerror(-err));
271                 free_fds(sockfd, 1);
272                 return -EINVAL;
273         }
274 
275         return 0;
276 }
277 
278 static int dut_attach_xdp_prog(struct xdp_features *skel, int flags)
279 {
280         enum xdp_action action = env.feature.action;
281         struct bpf_program *prog;
282         unsigned int key = 0;
283         int err, fd = 0;
284 
285         if (env.feature.drv_feature == NETDEV_XDP_ACT_NDO_XMIT) {
286                 struct bpf_devmap_val entry = {
287                         .ifindex = env.ifindex,
288                 };
289 
290                 err = bpf_map__update_elem(skel->maps.dev_map,
291                                            &key, sizeof(key),
292                                            &entry, sizeof(entry), 0);
293                 if (err < 0)
294                         return err;
295 
296                 fd = bpf_program__fd(skel->progs.xdp_do_redirect_cpumap);
297                 action = XDP_REDIRECT;
298         }
299 
300         switch (action) {
301         case XDP_TX:
302                 prog = skel->progs.xdp_do_tx;
303                 break;
304         case XDP_DROP:
305                 prog = skel->progs.xdp_do_drop;
306                 break;
307         case XDP_ABORTED:
308                 prog = skel->progs.xdp_do_aborted;
309                 break;
310         case XDP_PASS:
311                 prog = skel->progs.xdp_do_pass;
312                 break;
313         case XDP_REDIRECT: {
314                 struct bpf_cpumap_val entry = {
315                         .qsize = 2048,
316                         .bpf_prog.fd = fd,
317                 };
318 
319                 err = bpf_map__update_elem(skel->maps.cpu_map,
320                                            &key, sizeof(key),
321                                            &entry, sizeof(entry), 0);
322                 if (err < 0)
323                         return err;
324 
325                 prog = skel->progs.xdp_do_redirect;
326                 break;
327         }
328         default:
329                 return -EINVAL;
330         }
331 
332         err = bpf_xdp_attach(env.ifindex, bpf_program__fd(prog), flags, NULL);
333         if (err)
334                 fprintf(stderr, "Failed attaching XDP program to device %s\n",
335                         env.ifname);
336         return err;
337 }
338 
339 static int recv_msg(int sockfd, void *buf, size_t bufsize, void *val,
340                     size_t val_size)
341 {
342         struct tlv_hdr *tlv = (struct tlv_hdr *)buf;
343         size_t len;
344 
345         len = recv(sockfd, buf, bufsize, 0);
346         if (len != ntohs(tlv->len) || len < sizeof(*tlv))
347                 return -EINVAL;
348 
349         if (val) {
350                 len -= sizeof(*tlv);
351                 if (len > val_size)
352                         return -ENOMEM;
353 
354                 memcpy(val, tlv->data, len);
355         }
356 
357         return 0;
358 }
359 
360 static int dut_run(struct xdp_features *skel)
361 {
362         int flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE;
363         int state, err = 0, *sockfd, ctrl_sockfd, echo_sockfd;
364         struct sockaddr_storage ctrl_addr;
365         pthread_t dut_thread = 0;
366         socklen_t addrlen;
367 
368         sockfd = start_reuseport_server(AF_INET6, SOCK_STREAM, NULL,
369                                         DUT_CTRL_PORT, 0, 1);
370         if (!sockfd) {
371                 fprintf(stderr,
372                         "Failed creating control socket on device %s\n", env.ifname);
373                 return -errno;
374         }
375 
376         ctrl_sockfd = accept(*sockfd, (struct sockaddr *)&ctrl_addr, &addrlen);
377         if (ctrl_sockfd < 0) {
378                 fprintf(stderr,
379                         "Failed accepting connections on device %s control socket\n",
380                         env.ifname);
381                 free_fds(sockfd, 1);
382                 return -errno;
383         }
384 
385         /* CTRL loop */
386         while (!exiting) {
387                 unsigned char buf[BUFSIZE] = {};
388                 struct tlv_hdr *tlv = (struct tlv_hdr *)buf;
389 
390                 err = recv_msg(ctrl_sockfd, buf, BUFSIZE, NULL, 0);
391                 if (err)
392                         continue;
393 
394                 switch (ntohs(tlv->type)) {
395                 case CMD_START: {
396                         if (state == CMD_START)
397                                 continue;
398 
399                         state = CMD_START;
400                         /* Load the XDP program on the DUT */
401                         err = dut_attach_xdp_prog(skel, flags);
402                         if (err)
403                                 goto out;
404 
405                         err = dut_run_echo_thread(&dut_thread, &echo_sockfd);
406                         if (err < 0)
407                                 goto out;
408 
409                         tlv->type = htons(CMD_ACK);
410                         tlv->len = htons(sizeof(*tlv));
411                         err = send(ctrl_sockfd, buf, sizeof(*tlv), 0);
412                         if (err < 0)
413                                 goto end_thread;
414                         break;
415                 }
416                 case CMD_STOP:
417                         if (state != CMD_START)
418                                 break;
419 
420                         state = CMD_STOP;
421 
422                         exiting = true;
423                         bpf_xdp_detach(env.ifindex, flags, NULL);
424 
425                         tlv->type = htons(CMD_ACK);
426                         tlv->len = htons(sizeof(*tlv));
427                         err = send(ctrl_sockfd, buf, sizeof(*tlv), 0);
428                         goto end_thread;
429                 case CMD_GET_XDP_CAP: {
430                         LIBBPF_OPTS(bpf_xdp_query_opts, opts);
431                         unsigned long long val;
432                         size_t n;
433 
434                         err = bpf_xdp_query(env.ifindex, XDP_FLAGS_DRV_MODE,
435                                             &opts);
436                         if (err) {
437                                 fprintf(stderr,
438                                         "Failed querying XDP cap for device %s\n",
439                                         env.ifname);
440                                 goto end_thread;
441                         }
442 
443                         tlv->type = htons(CMD_ACK);
444                         n = sizeof(*tlv) + sizeof(opts.feature_flags);
445                         tlv->len = htons(n);
446 
447                         val = htobe64(opts.feature_flags);
448                         memcpy(tlv->data, &val, sizeof(val));
449 
450                         err = send(ctrl_sockfd, buf, n, 0);
451                         if (err < 0)
452                                 goto end_thread;
453                         break;
454                 }
455                 case CMD_GET_STATS: {
456                         unsigned int key = 0, val;
457                         size_t n;
458 
459                         err = bpf_map__lookup_elem(skel->maps.dut_stats,
460                                                    &key, sizeof(key),
461                                                    &val, sizeof(val), 0);
462                         if (err) {
463                                 fprintf(stderr,
464                                         "bpf_map_lookup_elem failed (%d)\n", err);
465                                 goto end_thread;
466                         }
467 
468                         tlv->type = htons(CMD_ACK);
469                         n = sizeof(*tlv) + sizeof(val);
470                         tlv->len = htons(n);
471 
472                         val = htonl(val);
473                         memcpy(tlv->data, &val, sizeof(val));
474 
475                         err = send(ctrl_sockfd, buf, n, 0);
476                         if (err < 0)
477                                 goto end_thread;
478                         break;
479                 }
480                 default:
481                         break;
482                 }
483         }
484 
485 end_thread:
486         pthread_join(dut_thread, NULL);
487 out:
488         bpf_xdp_detach(env.ifindex, flags, NULL);
489         close(ctrl_sockfd);
490         free_fds(sockfd, 1);
491 
492         return err;
493 }
494 
495 static bool tester_collect_detected_cap(struct xdp_features *skel,
496                                         unsigned int dut_stats)
497 {
498         unsigned int err, key = 0, val;
499 
500         if (!dut_stats)
501                 return false;
502 
503         err = bpf_map__lookup_elem(skel->maps.stats, &key, sizeof(key),
504                                    &val, sizeof(val), 0);
505         if (err) {
506                 fprintf(stderr, "bpf_map_lookup_elem failed (%d)\n", err);
507                 return false;
508         }
509 
510         switch (env.feature.action) {
511         case XDP_PASS:
512         case XDP_TX:
513         case XDP_REDIRECT:
514                 return val > 0;
515         case XDP_DROP:
516         case XDP_ABORTED:
517                 return val == 0;
518         default:
519                 break;
520         }
521 
522         if (env.feature.drv_feature == NETDEV_XDP_ACT_NDO_XMIT)
523                 return val > 0;
524 
525         return false;
526 }
527 
528 static int send_and_recv_msg(int sockfd, enum test_commands cmd, void *val,
529                              size_t val_size)
530 {
531         unsigned char buf[BUFSIZE] = {};
532         struct tlv_hdr *tlv = (struct tlv_hdr *)buf;
533         int err;
534 
535         tlv->type = htons(cmd);
536         tlv->len = htons(sizeof(*tlv));
537 
538         err = send(sockfd, buf, sizeof(*tlv), 0);
539         if (err < 0)
540                 return err;
541 
542         err = recv_msg(sockfd, buf, BUFSIZE, val, val_size);
543         if (err < 0)
544                 return err;
545 
546         return ntohs(tlv->type) == CMD_ACK ? 0 : -EINVAL;
547 }
548 
549 static int send_echo_msg(void)
550 {
551         unsigned char buf[sizeof(struct tlv_hdr)];
552         struct tlv_hdr *tlv = (struct tlv_hdr *)buf;
553         int sockfd, n;
554 
555         sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
556         if (sockfd < 0) {
557                 fprintf(stderr,
558                         "Failed creating data UDP socket on device %s\n",
559                         env.ifname);
560                 return -errno;
561         }
562 
563         tlv->type = htons(CMD_ECHO);
564         tlv->len = htons(sizeof(*tlv));
565 
566         n = sendto(sockfd, buf, sizeof(*tlv), MSG_NOSIGNAL | MSG_CONFIRM,
567                    (struct sockaddr *)&env.dut_addr, sizeof(env.dut_addr));
568         close(sockfd);
569 
570         return n == ntohs(tlv->len) ? 0 : -EINVAL;
571 }
572 
573 static int tester_run(struct xdp_features *skel)
574 {
575         int flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE;
576         unsigned long long advertised_feature;
577         struct bpf_program *prog;
578         unsigned int stats;
579         int i, err, sockfd;
580         bool detected_cap;
581 
582         sockfd = socket(AF_INET6, SOCK_STREAM, 0);
583         if (sockfd < 0) {
584                 fprintf(stderr,
585                         "Failed creating tester service control socket\n");
586                 return -errno;
587         }
588 
589         if (settimeo(sockfd, 1000) < 0)
590                 return -EINVAL;
591 
592         err = connect(sockfd, (struct sockaddr *)&env.dut_ctrl_addr,
593                       sizeof(env.dut_ctrl_addr));
594         if (err) {
595                 fprintf(stderr,
596                         "Failed connecting to the Device Under Test control socket\n");
597                 return -errno;
598         }
599 
600         err = send_and_recv_msg(sockfd, CMD_GET_XDP_CAP, &advertised_feature,
601                                 sizeof(advertised_feature));
602         if (err < 0) {
603                 close(sockfd);
604                 return err;
605         }
606 
607         advertised_feature = be64toh(advertised_feature);
608 
609         if (env.feature.drv_feature == NETDEV_XDP_ACT_NDO_XMIT ||
610             env.feature.action == XDP_TX)
611                 prog = skel->progs.xdp_tester_check_tx;
612         else
613                 prog = skel->progs.xdp_tester_check_rx;
614 
615         err = bpf_xdp_attach(env.ifindex, bpf_program__fd(prog), flags, NULL);
616         if (err) {
617                 fprintf(stderr, "Failed attaching XDP program to device %s\n",
618                         env.ifname);
619                 goto out;
620         }
621 
622         err = send_and_recv_msg(sockfd, CMD_START, NULL, 0);
623         if (err)
624                 goto out;
625 
626         for (i = 0; i < 10 && !exiting; i++) {
627                 err = send_echo_msg();
628                 if (err < 0)
629                         goto out;
630 
631                 sleep(1);
632         }
633 
634         err = send_and_recv_msg(sockfd, CMD_GET_STATS, &stats, sizeof(stats));
635         if (err)
636                 goto out;
637 
638         /* stop the test */
639         err = send_and_recv_msg(sockfd, CMD_STOP, NULL, 0);
640         /* send a new echo message to wake echo thread of the dut */
641         send_echo_msg();
642 
643         detected_cap = tester_collect_detected_cap(skel, ntohl(stats));
644 
645         fprintf(stdout, "Feature %s: [%s][%s]\n", get_xdp_feature_str(),
646                 detected_cap ? GREEN("DETECTED") : RED("NOT DETECTED"),
647                 env.feature.drv_feature & advertised_feature ? GREEN("ADVERTISED")
648                                                              : RED("NOT ADVERTISED"));
649 out:
650         bpf_xdp_detach(env.ifindex, flags, NULL);
651         close(sockfd);
652         return err < 0 ? err : 0;
653 }
654 
655 int main(int argc, char **argv)
656 {
657         struct xdp_features *skel;
658         int err;
659 
660         libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
661         libbpf_set_print(libbpf_print_fn);
662 
663         signal(SIGINT, sig_handler);
664         signal(SIGTERM, sig_handler);
665 
666         set_env_default();
667 
668         /* Parse command line arguments */
669         err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
670         if (err)
671                 return err;
672 
673         if (env.ifindex < 0) {
674                 fprintf(stderr, "Invalid device name %s\n", env.ifname);
675                 return -ENODEV;
676         }
677 
678         /* Load and verify BPF application */
679         skel = xdp_features__open();
680         if (!skel) {
681                 fprintf(stderr, "Failed to open and load BPF skeleton\n");
682                 return -EINVAL;
683         }
684 
685         skel->rodata->tester_addr =
686                 ((struct sockaddr_in6 *)&env.tester_addr)->sin6_addr;
687         skel->rodata->dut_addr =
688                 ((struct sockaddr_in6 *)&env.dut_addr)->sin6_addr;
689 
690         /* Load & verify BPF programs */
691         err = xdp_features__load(skel);
692         if (err) {
693                 fprintf(stderr, "Failed to load and verify BPF skeleton\n");
694                 goto cleanup;
695         }
696 
697         err = xdp_features__attach(skel);
698         if (err) {
699                 fprintf(stderr, "Failed to attach BPF skeleton\n");
700                 goto cleanup;
701         }
702 
703         if (env.is_tester) {
704                 /* Tester */
705                 fprintf(stdout, "Starting tester service on device %s\n",
706                         env.ifname);
707                 err = tester_run(skel);
708         } else {
709                 /* DUT */
710                 fprintf(stdout, "Starting test on device %s\n", env.ifname);
711                 err = dut_run(skel);
712         }
713 
714 cleanup:
715         xdp_features__destroy(skel);
716 
717         return err < 0 ? -err : 0;
718 }
719 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php