linux/tools/testing/selftests/bpf/test_sockmap.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (c) 2017-2018 Covalent IO, Inc. http://covalent.io
   3#include <stdio.h>
   4#include <stdlib.h>
   5#include <sys/socket.h>
   6#include <sys/ioctl.h>
   7#include <sys/select.h>
   8#include <netinet/in.h>
   9#include <arpa/inet.h>
  10#include <unistd.h>
  11#include <string.h>
  12#include <errno.h>
  13#include <sys/ioctl.h>
  14#include <stdbool.h>
  15#include <signal.h>
  16#include <fcntl.h>
  17#include <sys/wait.h>
  18#include <time.h>
  19#include <sched.h>
  20
  21#include <sys/time.h>
  22#include <sys/resource.h>
  23#include <sys/types.h>
  24#include <sys/sendfile.h>
  25
  26#include <linux/netlink.h>
  27#include <linux/socket.h>
  28#include <linux/sock_diag.h>
  29#include <linux/bpf.h>
  30#include <linux/if_link.h>
  31#include <assert.h>
  32#include <libgen.h>
  33
  34#include <getopt.h>
  35
  36#include <bpf/bpf.h>
  37#include <bpf/libbpf.h>
  38
  39#include "bpf_util.h"
  40#include "bpf_rlimit.h"
  41#include "cgroup_helpers.h"
  42
  43int running;
  44static void running_handler(int a);
  45
  46/* randomly selected ports for testing on lo */
  47#define S1_PORT 10000
  48#define S2_PORT 10001
  49
  50#define BPF_SOCKMAP_FILENAME "test_sockmap_kern.o"
  51#define BPF_SOCKHASH_FILENAME "test_sockhash_kern.o"
  52#define CG_PATH "/sockmap"
  53
  54/* global sockets */
  55int s1, s2, c1, c2, p1, p2;
  56int test_cnt;
  57int passed;
  58int failed;
  59int map_fd[8];
  60struct bpf_map *maps[8];
  61int prog_fd[11];
  62
  63int txmsg_pass;
  64int txmsg_noisy;
  65int txmsg_redir;
  66int txmsg_redir_noisy;
  67int txmsg_drop;
  68int txmsg_apply;
  69int txmsg_cork;
  70int txmsg_start;
  71int txmsg_end;
  72int txmsg_ingress;
  73int txmsg_skb;
  74
  75static const struct option long_options[] = {
  76        {"help",        no_argument,            NULL, 'h' },
  77        {"cgroup",      required_argument,      NULL, 'c' },
  78        {"rate",        required_argument,      NULL, 'r' },
  79        {"verbose",     no_argument,            NULL, 'v' },
  80        {"iov_count",   required_argument,      NULL, 'i' },
  81        {"length",      required_argument,      NULL, 'l' },
  82        {"test",        required_argument,      NULL, 't' },
  83        {"data_test",   no_argument,            NULL, 'd' },
  84        {"txmsg",               no_argument,    &txmsg_pass,  1  },
  85        {"txmsg_noisy",         no_argument,    &txmsg_noisy, 1  },
  86        {"txmsg_redir",         no_argument,    &txmsg_redir, 1  },
  87        {"txmsg_redir_noisy",   no_argument,    &txmsg_redir_noisy, 1},
  88        {"txmsg_drop",          no_argument,    &txmsg_drop, 1 },
  89        {"txmsg_apply", required_argument,      NULL, 'a'},
  90        {"txmsg_cork",  required_argument,      NULL, 'k'},
  91        {"txmsg_start", required_argument,      NULL, 's'},
  92        {"txmsg_end",   required_argument,      NULL, 'e'},
  93        {"txmsg_ingress", no_argument,          &txmsg_ingress, 1 },
  94        {"txmsg_skb", no_argument,              &txmsg_skb, 1 },
  95        {0, 0, NULL, 0 }
  96};
  97
  98static void usage(char *argv[])
  99{
 100        int i;
 101
 102        printf(" Usage: %s --cgroup <cgroup_path>\n", argv[0]);
 103        printf(" options:\n");
 104        for (i = 0; long_options[i].name != 0; i++) {
 105                printf(" --%-12s", long_options[i].name);
 106                if (long_options[i].flag != NULL)
 107                        printf(" flag (internal value:%d)\n",
 108                                *long_options[i].flag);
 109                else
 110                        printf(" -%c\n", long_options[i].val);
 111        }
 112        printf("\n");
 113}
 114
 115static int sockmap_init_sockets(int verbose)
 116{
 117        int i, err, one = 1;
 118        struct sockaddr_in addr;
 119        int *fds[4] = {&s1, &s2, &c1, &c2};
 120
 121        s1 = s2 = p1 = p2 = c1 = c2 = 0;
 122
 123        /* Init sockets */
 124        for (i = 0; i < 4; i++) {
 125                *fds[i] = socket(AF_INET, SOCK_STREAM, 0);
 126                if (*fds[i] < 0) {
 127                        perror("socket s1 failed()");
 128                        return errno;
 129                }
 130        }
 131
 132        /* Allow reuse */
 133        for (i = 0; i < 2; i++) {
 134                err = setsockopt(*fds[i], SOL_SOCKET, SO_REUSEADDR,
 135                                 (char *)&one, sizeof(one));
 136                if (err) {
 137                        perror("setsockopt failed()");
 138                        return errno;
 139                }
 140        }
 141
 142        /* Non-blocking sockets */
 143        for (i = 0; i < 2; i++) {
 144                err = ioctl(*fds[i], FIONBIO, (char *)&one);
 145                if (err < 0) {
 146                        perror("ioctl s1 failed()");
 147                        return errno;
 148                }
 149        }
 150
 151        /* Bind server sockets */
 152        memset(&addr, 0, sizeof(struct sockaddr_in));
 153        addr.sin_family = AF_INET;
 154        addr.sin_addr.s_addr = inet_addr("127.0.0.1");
 155
 156        addr.sin_port = htons(S1_PORT);
 157        err = bind(s1, (struct sockaddr *)&addr, sizeof(addr));
 158        if (err < 0) {
 159                perror("bind s1 failed()\n");
 160                return errno;
 161        }
 162
 163        addr.sin_port = htons(S2_PORT);
 164        err = bind(s2, (struct sockaddr *)&addr, sizeof(addr));
 165        if (err < 0) {
 166                perror("bind s2 failed()\n");
 167                return errno;
 168        }
 169
 170        /* Listen server sockets */
 171        addr.sin_port = htons(S1_PORT);
 172        err = listen(s1, 32);
 173        if (err < 0) {
 174                perror("listen s1 failed()\n");
 175                return errno;
 176        }
 177
 178        addr.sin_port = htons(S2_PORT);
 179        err = listen(s2, 32);
 180        if (err < 0) {
 181                perror("listen s1 failed()\n");
 182                return errno;
 183        }
 184
 185        /* Initiate Connect */
 186        addr.sin_port = htons(S1_PORT);
 187        err = connect(c1, (struct sockaddr *)&addr, sizeof(addr));
 188        if (err < 0 && errno != EINPROGRESS) {
 189                perror("connect c1 failed()\n");
 190                return errno;
 191        }
 192
 193        addr.sin_port = htons(S2_PORT);
 194        err = connect(c2, (struct sockaddr *)&addr, sizeof(addr));
 195        if (err < 0 && errno != EINPROGRESS) {
 196                perror("connect c2 failed()\n");
 197                return errno;
 198        } else if (err < 0) {
 199                err = 0;
 200        }
 201
 202        /* Accept Connecrtions */
 203        p1 = accept(s1, NULL, NULL);
 204        if (p1 < 0) {
 205                perror("accept s1 failed()\n");
 206                return errno;
 207        }
 208
 209        p2 = accept(s2, NULL, NULL);
 210        if (p2 < 0) {
 211                perror("accept s1 failed()\n");
 212                return errno;
 213        }
 214
 215        if (verbose) {
 216                printf("connected sockets: c1 <-> p1, c2 <-> p2\n");
 217                printf("cgroups binding: c1(%i) <-> s1(%i) - - - c2(%i) <-> s2(%i)\n",
 218                        c1, s1, c2, s2);
 219        }
 220        return 0;
 221}
 222
 223struct msg_stats {
 224        size_t bytes_sent;
 225        size_t bytes_recvd;
 226        struct timespec start;
 227        struct timespec end;
 228};
 229
 230struct sockmap_options {
 231        int verbose;
 232        bool base;
 233        bool sendpage;
 234        bool data_test;
 235        bool drop_expected;
 236        int iov_count;
 237        int iov_length;
 238        int rate;
 239};
 240
 241static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 242                             struct msg_stats *s,
 243                             struct sockmap_options *opt)
 244{
 245        bool drop = opt->drop_expected;
 246        unsigned char k = 0;
 247        FILE *file;
 248        int i, fp;
 249
 250        file = fopen(".sendpage_tst.tmp", "w+");
 251        for (i = 0; i < iov_length * cnt; i++, k++)
 252                fwrite(&k, sizeof(char), 1, file);
 253        fflush(file);
 254        fseek(file, 0, SEEK_SET);
 255        fclose(file);
 256
 257        fp = open(".sendpage_tst.tmp", O_RDONLY);
 258        clock_gettime(CLOCK_MONOTONIC, &s->start);
 259        for (i = 0; i < cnt; i++) {
 260                int sent = sendfile(fd, fp, NULL, iov_length);
 261
 262                if (!drop && sent < 0) {
 263                        perror("send loop error:");
 264                        close(fp);
 265                        return sent;
 266                } else if (drop && sent >= 0) {
 267                        printf("sendpage loop error expected: %i\n", sent);
 268                        close(fp);
 269                        return -EIO;
 270                }
 271
 272                if (sent > 0)
 273                        s->bytes_sent += sent;
 274        }
 275        clock_gettime(CLOCK_MONOTONIC, &s->end);
 276        close(fp);
 277        return 0;
 278}
 279
 280static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
 281                    struct msg_stats *s, bool tx,
 282                    struct sockmap_options *opt)
 283{
 284        struct msghdr msg = {0};
 285        int err, i, flags = MSG_NOSIGNAL;
 286        struct iovec *iov;
 287        unsigned char k;
 288        bool data_test = opt->data_test;
 289        bool drop = opt->drop_expected;
 290
 291        iov = calloc(iov_count, sizeof(struct iovec));
 292        if (!iov)
 293                return errno;
 294
 295        k = 0;
 296        for (i = 0; i < iov_count; i++) {
 297                unsigned char *d = calloc(iov_length, sizeof(char));
 298
 299                if (!d) {
 300                        fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count);
 301                        goto out_errno;
 302                }
 303                iov[i].iov_base = d;
 304                iov[i].iov_len = iov_length;
 305
 306                if (data_test && tx) {
 307                        int j;
 308
 309                        for (j = 0; j < iov_length; j++)
 310                                d[j] = k++;
 311                }
 312        }
 313
 314        msg.msg_iov = iov;
 315        msg.msg_iovlen = iov_count;
 316        k = 0;
 317
 318        if (tx) {
 319                clock_gettime(CLOCK_MONOTONIC, &s->start);
 320                for (i = 0; i < cnt; i++) {
 321                        int sent = sendmsg(fd, &msg, flags);
 322
 323                        if (!drop && sent < 0) {
 324                                perror("send loop error:");
 325                                goto out_errno;
 326                        } else if (drop && sent >= 0) {
 327                                printf("send loop error expected: %i\n", sent);
 328                                errno = -EIO;
 329                                goto out_errno;
 330                        }
 331                        if (sent > 0)
 332                                s->bytes_sent += sent;
 333                }
 334                clock_gettime(CLOCK_MONOTONIC, &s->end);
 335        } else {
 336                int slct, recv, max_fd = fd;
 337                int fd_flags = O_NONBLOCK;
 338                struct timeval timeout;
 339                float total_bytes;
 340                int bytes_cnt = 0;
 341                int chunk_sz;
 342                fd_set w;
 343
 344                if (opt->sendpage)
 345                        chunk_sz = iov_length * cnt;
 346                else
 347                        chunk_sz = iov_length * iov_count;
 348
 349                fcntl(fd, fd_flags);
 350                total_bytes = (float)iov_count * (float)iov_length * (float)cnt;
 351                err = clock_gettime(CLOCK_MONOTONIC, &s->start);
 352                if (err < 0)
 353                        perror("recv start time: ");
 354                while (s->bytes_recvd < total_bytes) {
 355                        if (txmsg_cork) {
 356                                timeout.tv_sec = 0;
 357                                timeout.tv_usec = 300000;
 358                        } else {
 359                                timeout.tv_sec = 1;
 360                                timeout.tv_usec = 0;
 361                        }
 362
 363                        /* FD sets */
 364                        FD_ZERO(&w);
 365                        FD_SET(fd, &w);
 366
 367                        slct = select(max_fd + 1, &w, NULL, NULL, &timeout);
 368                        if (slct == -1) {
 369                                perror("select()");
 370                                clock_gettime(CLOCK_MONOTONIC, &s->end);
 371                                goto out_errno;
 372                        } else if (!slct) {
 373                                if (opt->verbose)
 374                                        fprintf(stderr, "unexpected timeout\n");
 375                                errno = -EIO;
 376                                clock_gettime(CLOCK_MONOTONIC, &s->end);
 377                                goto out_errno;
 378                        }
 379
 380                        recv = recvmsg(fd, &msg, flags);
 381                        if (recv < 0) {
 382                                if (errno != EWOULDBLOCK) {
 383                                        clock_gettime(CLOCK_MONOTONIC, &s->end);
 384                                        perror("recv failed()\n");
 385                                        goto out_errno;
 386                                }
 387                        }
 388
 389                        s->bytes_recvd += recv;
 390
 391                        if (data_test) {
 392                                int j;
 393
 394                                for (i = 0; i < msg.msg_iovlen; i++) {
 395                                        unsigned char *d = iov[i].iov_base;
 396
 397                                        for (j = 0;
 398                                             j < iov[i].iov_len && recv; j++) {
 399                                                if (d[j] != k++) {
 400                                                        errno = -EIO;
 401                                                        fprintf(stderr,
 402                                                                "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n",
 403                                                                i, j, d[j], k - 1, d[j+1], k);
 404                                                        goto out_errno;
 405                                                }
 406                                                bytes_cnt++;
 407                                                if (bytes_cnt == chunk_sz) {
 408                                                        k = 0;
 409                                                        bytes_cnt = 0;
 410                                                }
 411                                                recv--;
 412                                        }
 413                                }
 414                        }
 415                }
 416                clock_gettime(CLOCK_MONOTONIC, &s->end);
 417        }
 418
 419        for (i = 0; i < iov_count; i++)
 420                free(iov[i].iov_base);
 421        free(iov);
 422        return 0;
 423out_errno:
 424        for (i = 0; i < iov_count; i++)
 425                free(iov[i].iov_base);
 426        free(iov);
 427        return errno;
 428}
 429
 430static float giga = 1000000000;
 431
 432static inline float sentBps(struct msg_stats s)
 433{
 434        return s.bytes_sent / (s.end.tv_sec - s.start.tv_sec);
 435}
 436
 437static inline float recvdBps(struct msg_stats s)
 438{
 439        return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec);
 440}
 441
 442static int sendmsg_test(struct sockmap_options *opt)
 443{
 444        float sent_Bps = 0, recvd_Bps = 0;
 445        int rx_fd, txpid, rxpid, err = 0;
 446        struct msg_stats s = {0};
 447        int iov_count = opt->iov_count;
 448        int iov_buf = opt->iov_length;
 449        int rx_status, tx_status;
 450        int cnt = opt->rate;
 451
 452        errno = 0;
 453
 454        if (opt->base)
 455                rx_fd = p1;
 456        else
 457                rx_fd = p2;
 458
 459        rxpid = fork();
 460        if (rxpid == 0) {
 461                if (opt->drop_expected)
 462                        exit(0);
 463
 464                if (opt->sendpage)
 465                        iov_count = 1;
 466                err = msg_loop(rx_fd, iov_count, iov_buf,
 467                               cnt, &s, false, opt);
 468                if (err && opt->verbose)
 469                        fprintf(stderr,
 470                                "msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n",
 471                                iov_count, iov_buf, cnt, err);
 472                shutdown(p2, SHUT_RDWR);
 473                shutdown(p1, SHUT_RDWR);
 474                if (s.end.tv_sec - s.start.tv_sec) {
 475                        sent_Bps = sentBps(s);
 476                        recvd_Bps = recvdBps(s);
 477                }
 478                if (opt->verbose)
 479                        fprintf(stdout,
 480                                "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s\n",
 481                                s.bytes_sent, sent_Bps, sent_Bps/giga,
 482                                s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
 483                if (err && txmsg_cork)
 484                        err = 0;
 485                exit(err ? 1 : 0);
 486        } else if (rxpid == -1) {
 487                perror("msg_loop_rx: ");
 488                return errno;
 489        }
 490
 491        txpid = fork();
 492        if (txpid == 0) {
 493                if (opt->sendpage)
 494                        err = msg_loop_sendpage(c1, iov_buf, cnt, &s, opt);
 495                else
 496                        err = msg_loop(c1, iov_count, iov_buf,
 497                                       cnt, &s, true, opt);
 498
 499                if (err)
 500                        fprintf(stderr,
 501                                "msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n",
 502                                iov_count, iov_buf, cnt, err);
 503                shutdown(c1, SHUT_RDWR);
 504                if (s.end.tv_sec - s.start.tv_sec) {
 505                        sent_Bps = sentBps(s);
 506                        recvd_Bps = recvdBps(s);
 507                }
 508                if (opt->verbose)
 509                        fprintf(stdout,
 510                                "tx_sendmsg: TX: %zuB %fB/s %f GB/s RX: %zuB %fB/s %fGB/s\n",
 511                                s.bytes_sent, sent_Bps, sent_Bps/giga,
 512                                s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
 513                exit(err ? 1 : 0);
 514        } else if (txpid == -1) {
 515                perror("msg_loop_tx: ");
 516                return errno;
 517        }
 518
 519        assert(waitpid(rxpid, &rx_status, 0) == rxpid);
 520        assert(waitpid(txpid, &tx_status, 0) == txpid);
 521        if (WIFEXITED(rx_status)) {
 522                err = WEXITSTATUS(rx_status);
 523                if (err) {
 524                        fprintf(stderr, "rx thread exited with err %d. ", err);
 525                        goto out;
 526                }
 527        }
 528        if (WIFEXITED(tx_status)) {
 529                err = WEXITSTATUS(tx_status);
 530                if (err)
 531                        fprintf(stderr, "tx thread exited with err %d. ", err);
 532        }
 533out:
 534        return err;
 535}
 536
 537static int forever_ping_pong(int rate, struct sockmap_options *opt)
 538{
 539        struct timeval timeout;
 540        char buf[1024] = {0};
 541        int sc;
 542
 543        timeout.tv_sec = 10;
 544        timeout.tv_usec = 0;
 545
 546        /* Ping/Pong data from client to server */
 547        sc = send(c1, buf, sizeof(buf), 0);
 548        if (sc < 0) {
 549                perror("send failed()\n");
 550                return sc;
 551        }
 552
 553        do {
 554                int s, rc, i, max_fd = p2;
 555                fd_set w;
 556
 557                /* FD sets */
 558                FD_ZERO(&w);
 559                FD_SET(c1, &w);
 560                FD_SET(c2, &w);
 561                FD_SET(p1, &w);
 562                FD_SET(p2, &w);
 563
 564                s = select(max_fd + 1, &w, NULL, NULL, &timeout);
 565                if (s == -1) {
 566                        perror("select()");
 567                        break;
 568                } else if (!s) {
 569                        fprintf(stderr, "unexpected timeout\n");
 570                        break;
 571                }
 572
 573                for (i = 0; i <= max_fd && s > 0; ++i) {
 574                        if (!FD_ISSET(i, &w))
 575                                continue;
 576
 577                        s--;
 578
 579                        rc = recv(i, buf, sizeof(buf), 0);
 580                        if (rc < 0) {
 581                                if (errno != EWOULDBLOCK) {
 582                                        perror("recv failed()\n");
 583                                        return rc;
 584                                }
 585                        }
 586
 587                        if (rc == 0) {
 588                                close(i);
 589                                break;
 590                        }
 591
 592                        sc = send(i, buf, rc, 0);
 593                        if (sc < 0) {
 594                                perror("send failed()\n");
 595                                return sc;
 596                        }
 597                }
 598
 599                if (rate)
 600                        sleep(rate);
 601
 602                if (opt->verbose) {
 603                        printf(".");
 604                        fflush(stdout);
 605
 606                }
 607        } while (running);
 608
 609        return 0;
 610}
 611
 612enum {
 613        PING_PONG,
 614        SENDMSG,
 615        BASE,
 616        BASE_SENDPAGE,
 617        SENDPAGE,
 618};
 619
 620static int run_options(struct sockmap_options *options, int cg_fd,  int test)
 621{
 622        int i, key, next_key, err, tx_prog_fd = -1, zero = 0;
 623
 624        /* If base test skip BPF setup */
 625        if (test == BASE || test == BASE_SENDPAGE)
 626                goto run;
 627
 628        /* Attach programs to sockmap */
 629        err = bpf_prog_attach(prog_fd[0], map_fd[0],
 630                                BPF_SK_SKB_STREAM_PARSER, 0);
 631        if (err) {
 632                fprintf(stderr,
 633                        "ERROR: bpf_prog_attach (sockmap %i->%i): %d (%s)\n",
 634                        prog_fd[0], map_fd[0], err, strerror(errno));
 635                return err;
 636        }
 637
 638        err = bpf_prog_attach(prog_fd[1], map_fd[0],
 639                                BPF_SK_SKB_STREAM_VERDICT, 0);
 640        if (err) {
 641                fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n",
 642                        err, strerror(errno));
 643                return err;
 644        }
 645
 646        /* Attach to cgroups */
 647        err = bpf_prog_attach(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS, 0);
 648        if (err) {
 649                fprintf(stderr, "ERROR: bpf_prog_attach (groups): %d (%s)\n",
 650                        err, strerror(errno));
 651                return err;
 652        }
 653
 654run:
 655        err = sockmap_init_sockets(options->verbose);
 656        if (err) {
 657                fprintf(stderr, "ERROR: test socket failed: %d\n", err);
 658                goto out;
 659        }
 660
 661        /* Attach txmsg program to sockmap */
 662        if (txmsg_pass)
 663                tx_prog_fd = prog_fd[3];
 664        else if (txmsg_noisy)
 665                tx_prog_fd = prog_fd[4];
 666        else if (txmsg_redir)
 667                tx_prog_fd = prog_fd[5];
 668        else if (txmsg_redir_noisy)
 669                tx_prog_fd = prog_fd[6];
 670        else if (txmsg_drop)
 671                tx_prog_fd = prog_fd[9];
 672        /* apply and cork must be last */
 673        else if (txmsg_apply)
 674                tx_prog_fd = prog_fd[7];
 675        else if (txmsg_cork)
 676                tx_prog_fd = prog_fd[8];
 677        else
 678                tx_prog_fd = 0;
 679
 680        if (tx_prog_fd) {
 681                int redir_fd, i = 0;
 682
 683                err = bpf_prog_attach(tx_prog_fd,
 684                                      map_fd[1], BPF_SK_MSG_VERDICT, 0);
 685                if (err) {
 686                        fprintf(stderr,
 687                                "ERROR: bpf_prog_attach (txmsg): %d (%s)\n",
 688                                err, strerror(errno));
 689                        goto out;
 690                }
 691
 692                err = bpf_map_update_elem(map_fd[1], &i, &c1, BPF_ANY);
 693                if (err) {
 694                        fprintf(stderr,
 695                                "ERROR: bpf_map_update_elem (txmsg):  %d (%s\n",
 696                                err, strerror(errno));
 697                        goto out;
 698                }
 699
 700                if (txmsg_redir || txmsg_redir_noisy)
 701                        redir_fd = c2;
 702                else
 703                        redir_fd = c1;
 704
 705                err = bpf_map_update_elem(map_fd[2], &i, &redir_fd, BPF_ANY);
 706                if (err) {
 707                        fprintf(stderr,
 708                                "ERROR: bpf_map_update_elem (txmsg):  %d (%s\n",
 709                                err, strerror(errno));
 710                        goto out;
 711                }
 712
 713                if (txmsg_apply) {
 714                        err = bpf_map_update_elem(map_fd[3],
 715                                                  &i, &txmsg_apply, BPF_ANY);
 716                        if (err) {
 717                                fprintf(stderr,
 718                                        "ERROR: bpf_map_update_elem (apply_bytes):  %d (%s\n",
 719                                        err, strerror(errno));
 720                                goto out;
 721                        }
 722                }
 723
 724                if (txmsg_cork) {
 725                        err = bpf_map_update_elem(map_fd[4],
 726                                                  &i, &txmsg_cork, BPF_ANY);
 727                        if (err) {
 728                                fprintf(stderr,
 729                                        "ERROR: bpf_map_update_elem (cork_bytes):  %d (%s\n",
 730                                        err, strerror(errno));
 731                                goto out;
 732                        }
 733                }
 734
 735                if (txmsg_start) {
 736                        err = bpf_map_update_elem(map_fd[5],
 737                                                  &i, &txmsg_start, BPF_ANY);
 738                        if (err) {
 739                                fprintf(stderr,
 740                                        "ERROR: bpf_map_update_elem (txmsg_start):  %d (%s)\n",
 741                                        err, strerror(errno));
 742                                goto out;
 743                        }
 744                }
 745
 746                if (txmsg_end) {
 747                        i = 1;
 748                        err = bpf_map_update_elem(map_fd[5],
 749                                                  &i, &txmsg_end, BPF_ANY);
 750                        if (err) {
 751                                fprintf(stderr,
 752                                        "ERROR: bpf_map_update_elem (txmsg_end):  %d (%s)\n",
 753                                        err, strerror(errno));
 754                                goto out;
 755                        }
 756                }
 757
 758                if (txmsg_ingress) {
 759                        int in = BPF_F_INGRESS;
 760
 761                        i = 0;
 762                        err = bpf_map_update_elem(map_fd[6], &i, &in, BPF_ANY);
 763                        if (err) {
 764                                fprintf(stderr,
 765                                        "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
 766                                        err, strerror(errno));
 767                        }
 768                        i = 1;
 769                        err = bpf_map_update_elem(map_fd[1], &i, &p1, BPF_ANY);
 770                        if (err) {
 771                                fprintf(stderr,
 772                                        "ERROR: bpf_map_update_elem (p1 txmsg): %d (%s)\n",
 773                                        err, strerror(errno));
 774                        }
 775                        err = bpf_map_update_elem(map_fd[2], &i, &p1, BPF_ANY);
 776                        if (err) {
 777                                fprintf(stderr,
 778                                        "ERROR: bpf_map_update_elem (p1 redir): %d (%s)\n",
 779                                        err, strerror(errno));
 780                        }
 781
 782                        i = 2;
 783                        err = bpf_map_update_elem(map_fd[2], &i, &p2, BPF_ANY);
 784                        if (err) {
 785                                fprintf(stderr,
 786                                        "ERROR: bpf_map_update_elem (p2 txmsg): %d (%s)\n",
 787                                        err, strerror(errno));
 788                        }
 789                }
 790
 791                if (txmsg_skb) {
 792                        int skb_fd = (test == SENDMSG || test == SENDPAGE) ?
 793                                        p2 : p1;
 794                        int ingress = BPF_F_INGRESS;
 795
 796                        i = 0;
 797                        err = bpf_map_update_elem(map_fd[7],
 798                                                  &i, &ingress, BPF_ANY);
 799                        if (err) {
 800                                fprintf(stderr,
 801                                        "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
 802                                        err, strerror(errno));
 803                        }
 804
 805                        i = 3;
 806                        err = bpf_map_update_elem(map_fd[0],
 807                                                  &i, &skb_fd, BPF_ANY);
 808                        if (err) {
 809                                fprintf(stderr,
 810                                        "ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n",
 811                                        err, strerror(errno));
 812                        }
 813                }
 814        }
 815
 816        if (txmsg_drop)
 817                options->drop_expected = true;
 818
 819        if (test == PING_PONG)
 820                err = forever_ping_pong(options->rate, options);
 821        else if (test == SENDMSG) {
 822                options->base = false;
 823                options->sendpage = false;
 824                err = sendmsg_test(options);
 825        } else if (test == SENDPAGE) {
 826                options->base = false;
 827                options->sendpage = true;
 828                err = sendmsg_test(options);
 829        } else if (test == BASE) {
 830                options->base = true;
 831                options->sendpage = false;
 832                err = sendmsg_test(options);
 833        } else if (test == BASE_SENDPAGE) {
 834                options->base = true;
 835                options->sendpage = true;
 836                err = sendmsg_test(options);
 837        } else
 838                fprintf(stderr, "unknown test\n");
 839out:
 840        /* Detatch and zero all the maps */
 841        bpf_prog_detach2(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS);
 842        bpf_prog_detach2(prog_fd[0], map_fd[0], BPF_SK_SKB_STREAM_PARSER);
 843        bpf_prog_detach2(prog_fd[1], map_fd[0], BPF_SK_SKB_STREAM_VERDICT);
 844        if (tx_prog_fd >= 0)
 845                bpf_prog_detach2(tx_prog_fd, map_fd[1], BPF_SK_MSG_VERDICT);
 846
 847        for (i = 0; i < 8; i++) {
 848                key = next_key = 0;
 849                bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
 850                while (bpf_map_get_next_key(map_fd[i], &key, &next_key) == 0) {
 851                        bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
 852                        key = next_key;
 853                }
 854        }
 855
 856        close(s1);
 857        close(s2);
 858        close(p1);
 859        close(p2);
 860        close(c1);
 861        close(c2);
 862        return err;
 863}
 864
 865static char *test_to_str(int test)
 866{
 867        switch (test) {
 868        case SENDMSG:
 869                return "sendmsg";
 870        case SENDPAGE:
 871                return "sendpage";
 872        }
 873        return "unknown";
 874}
 875
 876#define OPTSTRING 60
 877static void test_options(char *options)
 878{
 879        char tstr[OPTSTRING];
 880
 881        memset(options, 0, OPTSTRING);
 882
 883        if (txmsg_pass)
 884                strncat(options, "pass,", OPTSTRING);
 885        if (txmsg_noisy)
 886                strncat(options, "pass_noisy,", OPTSTRING);
 887        if (txmsg_redir)
 888                strncat(options, "redir,", OPTSTRING);
 889        if (txmsg_redir_noisy)
 890                strncat(options, "redir_noisy,", OPTSTRING);
 891        if (txmsg_drop)
 892                strncat(options, "drop,", OPTSTRING);
 893        if (txmsg_apply) {
 894                snprintf(tstr, OPTSTRING, "apply %d,", txmsg_apply);
 895                strncat(options, tstr, OPTSTRING);
 896        }
 897        if (txmsg_cork) {
 898                snprintf(tstr, OPTSTRING, "cork %d,", txmsg_cork);
 899                strncat(options, tstr, OPTSTRING);
 900        }
 901        if (txmsg_start) {
 902                snprintf(tstr, OPTSTRING, "start %d,", txmsg_start);
 903                strncat(options, tstr, OPTSTRING);
 904        }
 905        if (txmsg_end) {
 906                snprintf(tstr, OPTSTRING, "end %d,", txmsg_end);
 907                strncat(options, tstr, OPTSTRING);
 908        }
 909        if (txmsg_ingress)
 910                strncat(options, "ingress,", OPTSTRING);
 911        if (txmsg_skb)
 912                strncat(options, "skb,", OPTSTRING);
 913}
 914
 915static int __test_exec(int cgrp, int test, struct sockmap_options *opt)
 916{
 917        char *options = calloc(OPTSTRING, sizeof(char));
 918        int err;
 919
 920        if (test == SENDPAGE)
 921                opt->sendpage = true;
 922        else
 923                opt->sendpage = false;
 924
 925        if (txmsg_drop)
 926                opt->drop_expected = true;
 927        else
 928                opt->drop_expected = false;
 929
 930        test_options(options);
 931
 932        fprintf(stdout,
 933                "[TEST %i]: (%i, %i, %i, %s, %s): ",
 934                test_cnt, opt->rate, opt->iov_count, opt->iov_length,
 935                test_to_str(test), options);
 936        fflush(stdout);
 937        err = run_options(opt, cgrp, test);
 938        fprintf(stdout, "%s\n", !err ? "PASS" : "FAILED");
 939        test_cnt++;
 940        !err ? passed++ : failed++;
 941        free(options);
 942        return err;
 943}
 944
 945static int test_exec(int cgrp, struct sockmap_options *opt)
 946{
 947        int err = __test_exec(cgrp, SENDMSG, opt);
 948
 949        if (err)
 950                goto out;
 951
 952        err = __test_exec(cgrp, SENDPAGE, opt);
 953out:
 954        return err;
 955}
 956
 957static int test_loop(int cgrp)
 958{
 959        struct sockmap_options opt;
 960
 961        int err, i, l, r;
 962
 963        opt.verbose = 0;
 964        opt.base = false;
 965        opt.sendpage = false;
 966        opt.data_test = false;
 967        opt.drop_expected = false;
 968        opt.iov_count = 0;
 969        opt.iov_length = 0;
 970        opt.rate = 0;
 971
 972        r = 1;
 973        for (i = 1; i < 100; i += 33) {
 974                for (l = 1; l < 100; l += 33) {
 975                        opt.rate = r;
 976                        opt.iov_count = i;
 977                        opt.iov_length = l;
 978                        err = test_exec(cgrp, &opt);
 979                        if (err)
 980                                goto out;
 981                }
 982        }
 983        sched_yield();
 984out:
 985        return err;
 986}
 987
 988static int test_txmsg(int cgrp)
 989{
 990        int err;
 991
 992        txmsg_pass = txmsg_noisy = txmsg_redir_noisy = txmsg_drop = 0;
 993        txmsg_apply = txmsg_cork = 0;
 994        txmsg_ingress = txmsg_skb = 0;
 995
 996        txmsg_pass = 1;
 997        err = test_loop(cgrp);
 998        txmsg_pass = 0;
 999        if (err)
1000                goto out;
1001
1002        txmsg_redir = 1;
1003        err = test_loop(cgrp);
1004        txmsg_redir = 0;
1005        if (err)
1006                goto out;
1007
1008        txmsg_drop = 1;
1009        err = test_loop(cgrp);
1010        txmsg_drop = 0;
1011        if (err)
1012                goto out;
1013
1014        txmsg_redir = 1;
1015        txmsg_ingress = 1;
1016        err = test_loop(cgrp);
1017        txmsg_redir = 0;
1018        txmsg_ingress = 0;
1019        if (err)
1020                goto out;
1021out:
1022        txmsg_pass = 0;
1023        txmsg_redir = 0;
1024        txmsg_drop = 0;
1025        return err;
1026}
1027
1028static int test_send(struct sockmap_options *opt, int cgrp)
1029{
1030        int err;
1031
1032        opt->iov_length = 1;
1033        opt->iov_count = 1;
1034        opt->rate = 1;
1035        err = test_exec(cgrp, opt);
1036        if (err)
1037                goto out;
1038
1039        opt->iov_length = 1;
1040        opt->iov_count = 1024;
1041        opt->rate = 1;
1042        err = test_exec(cgrp, opt);
1043        if (err)
1044                goto out;
1045
1046        opt->iov_length = 1024;
1047        opt->iov_count = 1;
1048        opt->rate = 1;
1049        err = test_exec(cgrp, opt);
1050        if (err)
1051                goto out;
1052
1053        opt->iov_length = 1;
1054        opt->iov_count = 1;
1055        opt->rate = 512;
1056        err = test_exec(cgrp, opt);
1057        if (err)
1058                goto out;
1059
1060        opt->iov_length = 256;
1061        opt->iov_count = 1024;
1062        opt->rate = 2;
1063        err = test_exec(cgrp, opt);
1064        if (err)
1065                goto out;
1066
1067        opt->rate = 100;
1068        opt->iov_count = 1;
1069        opt->iov_length = 5;
1070        err = test_exec(cgrp, opt);
1071        if (err)
1072                goto out;
1073out:
1074        sched_yield();
1075        return err;
1076}
1077
1078static int test_mixed(int cgrp)
1079{
1080        struct sockmap_options opt = {0};
1081        int err;
1082
1083        txmsg_pass = txmsg_noisy = txmsg_redir_noisy = txmsg_drop = 0;
1084        txmsg_apply = txmsg_cork = 0;
1085        txmsg_start = txmsg_end = 0;
1086        /* Test small and large iov_count values with pass/redir/apply/cork */
1087        txmsg_pass = 1;
1088        txmsg_redir = 0;
1089        txmsg_apply = 1;
1090        txmsg_cork = 0;
1091        err = test_send(&opt, cgrp);
1092        if (err)
1093                goto out;
1094
1095        txmsg_pass = 1;
1096        txmsg_redir = 0;
1097        txmsg_apply = 0;
1098        txmsg_cork = 1;
1099        err = test_send(&opt, cgrp);
1100        if (err)
1101                goto out;
1102
1103        txmsg_pass = 1;
1104        txmsg_redir = 0;
1105        txmsg_apply = 1;
1106        txmsg_cork = 1;
1107        err = test_send(&opt, cgrp);
1108        if (err)
1109                goto out;
1110
1111        txmsg_pass = 1;
1112        txmsg_redir = 0;
1113        txmsg_apply = 1024;
1114        txmsg_cork = 0;
1115        err = test_send(&opt, cgrp);
1116        if (err)
1117                goto out;
1118
1119        txmsg_pass = 1;
1120        txmsg_redir = 0;
1121        txmsg_apply = 0;
1122        txmsg_cork = 1024;
1123        err = test_send(&opt, cgrp);
1124        if (err)
1125                goto out;
1126
1127        txmsg_pass = 1;
1128        txmsg_redir = 0;
1129        txmsg_apply = 1024;
1130        txmsg_cork = 1024;
1131        err = test_send(&opt, cgrp);
1132        if (err)
1133                goto out;
1134
1135        txmsg_pass = 1;
1136        txmsg_redir = 0;
1137        txmsg_cork = 4096;
1138        txmsg_apply = 4096;
1139        err = test_send(&opt, cgrp);
1140        if (err)
1141                goto out;
1142
1143        txmsg_pass = 0;
1144        txmsg_redir = 1;
1145        txmsg_apply = 1;
1146        txmsg_cork = 0;
1147        err = test_send(&opt, cgrp);
1148        if (err)
1149                goto out;
1150
1151        txmsg_pass = 0;
1152        txmsg_redir = 1;
1153        txmsg_apply = 0;
1154        txmsg_cork = 1;
1155        err = test_send(&opt, cgrp);
1156        if (err)
1157                goto out;
1158
1159        txmsg_pass = 0;
1160        txmsg_redir = 1;
1161        txmsg_apply = 1024;
1162        txmsg_cork = 0;
1163        err = test_send(&opt, cgrp);
1164        if (err)
1165                goto out;
1166
1167        txmsg_pass = 0;
1168        txmsg_redir = 1;
1169        txmsg_apply = 0;
1170        txmsg_cork = 1024;
1171        err = test_send(&opt, cgrp);
1172        if (err)
1173                goto out;
1174
1175        txmsg_pass = 0;
1176        txmsg_redir = 1;
1177        txmsg_apply = 1024;
1178        txmsg_cork = 1024;
1179        err = test_send(&opt, cgrp);
1180        if (err)
1181                goto out;
1182
1183        txmsg_pass = 0;
1184        txmsg_redir = 1;
1185        txmsg_cork = 4096;
1186        txmsg_apply = 4096;
1187        err = test_send(&opt, cgrp);
1188        if (err)
1189                goto out;
1190out:
1191        return err;
1192}
1193
1194static int test_start_end(int cgrp)
1195{
1196        struct sockmap_options opt = {0};
1197        int err, i;
1198
1199        /* Test basic start/end with lots of iov_count and iov_lengths */
1200        txmsg_start = 1;
1201        txmsg_end = 2;
1202        err = test_txmsg(cgrp);
1203        if (err)
1204                goto out;
1205
1206        /* Test start/end with cork */
1207        opt.rate = 16;
1208        opt.iov_count = 1;
1209        opt.iov_length = 100;
1210        txmsg_cork = 1600;
1211
1212        for (i = 99; i <= 1600; i += 500) {
1213                txmsg_start = 0;
1214                txmsg_end = i;
1215                err = test_exec(cgrp, &opt);
1216                if (err)
1217                        goto out;
1218        }
1219
1220        /* Test start/end with cork but pull data in middle */
1221        for (i = 199; i <= 1600; i += 500) {
1222                txmsg_start = 100;
1223                txmsg_end = i;
1224                err = test_exec(cgrp, &opt);
1225                if (err)
1226                        goto out;
1227        }
1228
1229        /* Test start/end with cork pulling last sg entry */
1230        txmsg_start = 1500;
1231        txmsg_end = 1600;
1232        err = test_exec(cgrp, &opt);
1233        if (err)
1234                goto out;
1235
1236        /* Test start/end pull of single byte in last page */
1237        txmsg_start = 1111;
1238        txmsg_end = 1112;
1239        err = test_exec(cgrp, &opt);
1240        if (err)
1241                goto out;
1242
1243        /* Test start/end with end < start */
1244        txmsg_start = 1111;
1245        txmsg_end = 0;
1246        err = test_exec(cgrp, &opt);
1247        if (err)
1248                goto out;
1249
1250        /* Test start/end with end > data */
1251        txmsg_start = 0;
1252        txmsg_end = 1601;
1253        err = test_exec(cgrp, &opt);
1254        if (err)
1255                goto out;
1256
1257        /* Test start/end with start > data */
1258        txmsg_start = 1601;
1259        txmsg_end = 1600;
1260        err = test_exec(cgrp, &opt);
1261
1262out:
1263        txmsg_start = 0;
1264        txmsg_end = 0;
1265        sched_yield();
1266        return err;
1267}
1268
1269char *map_names[] = {
1270        "sock_map",
1271        "sock_map_txmsg",
1272        "sock_map_redir",
1273        "sock_apply_bytes",
1274        "sock_cork_bytes",
1275        "sock_pull_bytes",
1276        "sock_redir_flags",
1277        "sock_skb_opts",
1278};
1279
1280int prog_attach_type[] = {
1281        BPF_SK_SKB_STREAM_PARSER,
1282        BPF_SK_SKB_STREAM_VERDICT,
1283        BPF_CGROUP_SOCK_OPS,
1284        BPF_SK_MSG_VERDICT,
1285        BPF_SK_MSG_VERDICT,
1286        BPF_SK_MSG_VERDICT,
1287        BPF_SK_MSG_VERDICT,
1288        BPF_SK_MSG_VERDICT,
1289        BPF_SK_MSG_VERDICT,
1290        BPF_SK_MSG_VERDICT,
1291};
1292
1293int prog_type[] = {
1294        BPF_PROG_TYPE_SK_SKB,
1295        BPF_PROG_TYPE_SK_SKB,
1296        BPF_PROG_TYPE_SOCK_OPS,
1297        BPF_PROG_TYPE_SK_MSG,
1298        BPF_PROG_TYPE_SK_MSG,
1299        BPF_PROG_TYPE_SK_MSG,
1300        BPF_PROG_TYPE_SK_MSG,
1301        BPF_PROG_TYPE_SK_MSG,
1302        BPF_PROG_TYPE_SK_MSG,
1303        BPF_PROG_TYPE_SK_MSG,
1304};
1305
1306static int populate_progs(char *bpf_file)
1307{
1308        struct bpf_program *prog;
1309        struct bpf_object *obj;
1310        int i = 0;
1311        long err;
1312
1313        obj = bpf_object__open(bpf_file);
1314        err = libbpf_get_error(obj);
1315        if (err) {
1316                char err_buf[256];
1317
1318                libbpf_strerror(err, err_buf, sizeof(err_buf));
1319                printf("Unable to load eBPF objects in file '%s' : %s\n",
1320                       bpf_file, err_buf);
1321                return -1;
1322        }
1323
1324        bpf_object__for_each_program(prog, obj) {
1325                bpf_program__set_type(prog, prog_type[i]);
1326                bpf_program__set_expected_attach_type(prog,
1327                                                      prog_attach_type[i]);
1328                i++;
1329        }
1330
1331        i = bpf_object__load(obj);
1332        i = 0;
1333        bpf_object__for_each_program(prog, obj) {
1334                prog_fd[i] = bpf_program__fd(prog);
1335                i++;
1336        }
1337
1338        for (i = 0; i < sizeof(map_fd)/sizeof(int); i++) {
1339                maps[i] = bpf_object__find_map_by_name(obj, map_names[i]);
1340                map_fd[i] = bpf_map__fd(maps[i]);
1341                if (map_fd[i] < 0) {
1342                        fprintf(stderr, "load_bpf_file: (%i) %s\n",
1343                                map_fd[i], strerror(errno));
1344                        return -1;
1345                }
1346        }
1347
1348        return 0;
1349}
1350
1351static int __test_suite(char *bpf_file)
1352{
1353        int cg_fd, err;
1354
1355        err = populate_progs(bpf_file);
1356        if (err < 0) {
1357                fprintf(stderr, "ERROR: (%i) load bpf failed\n", err);
1358                return err;
1359        }
1360
1361        if (setup_cgroup_environment()) {
1362                fprintf(stderr, "ERROR: cgroup env failed\n");
1363                return -EINVAL;
1364        }
1365
1366        cg_fd = create_and_get_cgroup(CG_PATH);
1367        if (cg_fd < 0) {
1368                fprintf(stderr,
1369                        "ERROR: (%i) open cg path failed: %s\n",
1370                        cg_fd, optarg);
1371                return cg_fd;
1372        }
1373
1374        if (join_cgroup(CG_PATH)) {
1375                fprintf(stderr, "ERROR: failed to join cgroup\n");
1376                return -EINVAL;
1377        }
1378
1379        /* Tests basic commands and APIs with range of iov values */
1380        txmsg_start = txmsg_end = 0;
1381        err = test_txmsg(cg_fd);
1382        if (err)
1383                goto out;
1384
1385        /* Tests interesting combinations of APIs used together */
1386        err = test_mixed(cg_fd);
1387        if (err)
1388                goto out;
1389
1390        /* Tests pull_data API using start/end API */
1391        err = test_start_end(cg_fd);
1392        if (err)
1393                goto out;
1394
1395out:
1396        printf("Summary: %i PASSED %i FAILED\n", passed, failed);
1397        cleanup_cgroup_environment();
1398        close(cg_fd);
1399        return err;
1400}
1401
1402static int test_suite(void)
1403{
1404        int err;
1405
1406        err = __test_suite(BPF_SOCKMAP_FILENAME);
1407        if (err)
1408                goto out;
1409        err = __test_suite(BPF_SOCKHASH_FILENAME);
1410out:
1411        return err;
1412}
1413
1414int main(int argc, char **argv)
1415{
1416        int iov_count = 1, length = 1024, rate = 1;
1417        struct sockmap_options options = {0};
1418        int opt, longindex, err, cg_fd = 0;
1419        char *bpf_file = BPF_SOCKMAP_FILENAME;
1420        int test = PING_PONG;
1421
1422        if (argc < 2)
1423                return test_suite();
1424
1425        while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:",
1426                                  long_options, &longindex)) != -1) {
1427                switch (opt) {
1428                case 's':
1429                        txmsg_start = atoi(optarg);
1430                        break;
1431                case 'e':
1432                        txmsg_end = atoi(optarg);
1433                        break;
1434                case 'a':
1435                        txmsg_apply = atoi(optarg);
1436                        break;
1437                case 'k':
1438                        txmsg_cork = atoi(optarg);
1439                        break;
1440                case 'c':
1441                        cg_fd = open(optarg, O_DIRECTORY, O_RDONLY);
1442                        if (cg_fd < 0) {
1443                                fprintf(stderr,
1444                                        "ERROR: (%i) open cg path failed: %s\n",
1445                                        cg_fd, optarg);
1446                                return cg_fd;
1447                        }
1448                        break;
1449                case 'r':
1450                        rate = atoi(optarg);
1451                        break;
1452                case 'v':
1453                        options.verbose = 1;
1454                        break;
1455                case 'i':
1456                        iov_count = atoi(optarg);
1457                        break;
1458                case 'l':
1459                        length = atoi(optarg);
1460                        break;
1461                case 'd':
1462                        options.data_test = true;
1463                        break;
1464                case 't':
1465                        if (strcmp(optarg, "ping") == 0) {
1466                                test = PING_PONG;
1467                        } else if (strcmp(optarg, "sendmsg") == 0) {
1468                                test = SENDMSG;
1469                        } else if (strcmp(optarg, "base") == 0) {
1470                                test = BASE;
1471                        } else if (strcmp(optarg, "base_sendpage") == 0) {
1472                                test = BASE_SENDPAGE;
1473                        } else if (strcmp(optarg, "sendpage") == 0) {
1474                                test = SENDPAGE;
1475                        } else {
1476                                usage(argv);
1477                                return -1;
1478                        }
1479                        break;
1480                case 0:
1481                        break;
1482                case 'h':
1483                default:
1484                        usage(argv);
1485                        return -1;
1486                }
1487        }
1488
1489        if (!cg_fd) {
1490                fprintf(stderr, "%s requires cgroup option: --cgroup <path>\n",
1491                        argv[0]);
1492                return -1;
1493        }
1494
1495        err = populate_progs(bpf_file);
1496        if (err) {
1497                fprintf(stderr, "populate program: (%s) %s\n",
1498                        bpf_file, strerror(errno));
1499                return 1;
1500        }
1501        running = 1;
1502
1503        /* catch SIGINT */
1504        signal(SIGINT, running_handler);
1505
1506        options.iov_count = iov_count;
1507        options.iov_length = length;
1508        options.rate = rate;
1509
1510        err = run_options(&options, cg_fd, test);
1511        close(cg_fd);
1512        return err;
1513}
1514
1515void running_handler(int a)
1516{
1517        running = 0;
1518}
1519