1*7b2fa44dSJiayuan Chen // SPDX-License-Identifier: GPL-2.0 2*7b2fa44dSJiayuan Chen 3*7b2fa44dSJiayuan Chen #include <error.h> 4*7b2fa44dSJiayuan Chen #include <sys/types.h> 5*7b2fa44dSJiayuan Chen #include <sys/socket.h> 6*7b2fa44dSJiayuan Chen #include <netinet/in.h> 7*7b2fa44dSJiayuan Chen #include <sys/sendfile.h> 8*7b2fa44dSJiayuan Chen #include <arpa/inet.h> 9*7b2fa44dSJiayuan Chen #include <fcntl.h> 10*7b2fa44dSJiayuan Chen #include <argp.h> 11*7b2fa44dSJiayuan Chen #include "bench.h" 12*7b2fa44dSJiayuan Chen #include "bench_sockmap_prog.skel.h" 13*7b2fa44dSJiayuan Chen 14*7b2fa44dSJiayuan Chen #define FILE_SIZE (128 * 1024) 15*7b2fa44dSJiayuan Chen #define DATA_REPEAT_SIZE 10 16*7b2fa44dSJiayuan Chen 17*7b2fa44dSJiayuan Chen static const char snd_data[DATA_REPEAT_SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 18*7b2fa44dSJiayuan Chen 19*7b2fa44dSJiayuan Chen /* c1 <-> [p1, p2] <-> c2 20*7b2fa44dSJiayuan Chen * RX bench(BPF_SK_SKB_STREAM_VERDICT): 21*7b2fa44dSJiayuan Chen * ARG_FW_RX_PASS: 22*7b2fa44dSJiayuan Chen * send(p2) -> recv(c2) -> bpf skb passthrough -> recv(c2) 23*7b2fa44dSJiayuan Chen * ARG_FW_RX_VERDICT_EGRESS: 24*7b2fa44dSJiayuan Chen * send(c1) -> verdict skb to tx queuec of p2 -> recv(c2) 25*7b2fa44dSJiayuan Chen * ARG_FW_RX_VERDICT_INGRESS: 26*7b2fa44dSJiayuan Chen * send(c1) -> verdict skb to rx queuec of c2 -> recv(c2) 27*7b2fa44dSJiayuan Chen * 28*7b2fa44dSJiayuan Chen * TX bench(BPF_SK_MSG_VERDIC): 29*7b2fa44dSJiayuan Chen * ARG_FW_TX_PASS: 30*7b2fa44dSJiayuan Chen * send(p2) -> bpf msg passthrough -> send(p2) -> recv(c2) 31*7b2fa44dSJiayuan Chen * ARG_FW_TX_VERDICT_INGRESS: 32*7b2fa44dSJiayuan Chen * send(p2) -> verdict msg to rx queue of c2 -> recv(c2) 33*7b2fa44dSJiayuan Chen * ARG_FW_TX_VERDICT_EGRESS: 34*7b2fa44dSJiayuan Chen * send(p1) -> verdict msg to tx queue of p2 -> recv(c2) 35*7b2fa44dSJiayuan Chen */ 36*7b2fa44dSJiayuan Chen enum SOCKMAP_ARG_FLAG { 37*7b2fa44dSJiayuan Chen ARG_FW_RX_NORMAL = 11000, 38*7b2fa44dSJiayuan Chen ARG_FW_RX_PASS, 39*7b2fa44dSJiayuan Chen ARG_FW_RX_VERDICT_EGRESS, 40*7b2fa44dSJiayuan Chen ARG_FW_RX_VERDICT_INGRESS, 41*7b2fa44dSJiayuan Chen ARG_FW_TX_NORMAL, 42*7b2fa44dSJiayuan Chen ARG_FW_TX_PASS, 43*7b2fa44dSJiayuan Chen ARG_FW_TX_VERDICT_INGRESS, 44*7b2fa44dSJiayuan Chen ARG_FW_TX_VERDICT_EGRESS, 45*7b2fa44dSJiayuan Chen ARG_CTL_RX_STRP, 46*7b2fa44dSJiayuan Chen ARG_CONSUMER_DELAY_TIME, 47*7b2fa44dSJiayuan Chen ARG_PRODUCER_DURATION, 48*7b2fa44dSJiayuan Chen }; 49*7b2fa44dSJiayuan Chen 50*7b2fa44dSJiayuan Chen #define TXMODE_NORMAL() \ 51*7b2fa44dSJiayuan Chen ((ctx.mode) == ARG_FW_TX_NORMAL) 52*7b2fa44dSJiayuan Chen 53*7b2fa44dSJiayuan Chen #define TXMODE_BPF_INGRESS() \ 54*7b2fa44dSJiayuan Chen ((ctx.mode) == ARG_FW_TX_VERDICT_INGRESS) 55*7b2fa44dSJiayuan Chen 56*7b2fa44dSJiayuan Chen #define TXMODE_BPF_EGRESS() \ 57*7b2fa44dSJiayuan Chen ((ctx.mode) == ARG_FW_TX_VERDICT_EGRESS) 58*7b2fa44dSJiayuan Chen 59*7b2fa44dSJiayuan Chen #define TXMODE_BPF_PASS() \ 60*7b2fa44dSJiayuan Chen ((ctx.mode) == ARG_FW_TX_PASS) 61*7b2fa44dSJiayuan Chen 62*7b2fa44dSJiayuan Chen #define TXMODE_BPF() ( \ 63*7b2fa44dSJiayuan Chen TXMODE_BPF_PASS() || \ 64*7b2fa44dSJiayuan Chen TXMODE_BPF_INGRESS() || \ 65*7b2fa44dSJiayuan Chen TXMODE_BPF_EGRESS()) 66*7b2fa44dSJiayuan Chen 67*7b2fa44dSJiayuan Chen #define TXMODE() ( \ 68*7b2fa44dSJiayuan Chen TXMODE_NORMAL() || \ 69*7b2fa44dSJiayuan Chen TXMODE_BPF()) 70*7b2fa44dSJiayuan Chen 71*7b2fa44dSJiayuan Chen #define RXMODE_NORMAL() \ 72*7b2fa44dSJiayuan Chen ((ctx.mode) == ARG_FW_RX_NORMAL) 73*7b2fa44dSJiayuan Chen 74*7b2fa44dSJiayuan Chen #define RXMODE_BPF_PASS() \ 75*7b2fa44dSJiayuan Chen ((ctx.mode) == ARG_FW_RX_PASS) 76*7b2fa44dSJiayuan Chen 77*7b2fa44dSJiayuan Chen #define RXMODE_BPF_VERDICT_EGRESS() \ 78*7b2fa44dSJiayuan Chen ((ctx.mode) == ARG_FW_RX_VERDICT_EGRESS) 79*7b2fa44dSJiayuan Chen 80*7b2fa44dSJiayuan Chen #define RXMODE_BPF_VERDICT_INGRESS() \ 81*7b2fa44dSJiayuan Chen ((ctx.mode) == ARG_FW_RX_VERDICT_INGRESS) 82*7b2fa44dSJiayuan Chen 83*7b2fa44dSJiayuan Chen #define RXMODE_BPF_VERDICT() ( \ 84*7b2fa44dSJiayuan Chen RXMODE_BPF_VERDICT_INGRESS() || \ 85*7b2fa44dSJiayuan Chen RXMODE_BPF_VERDICT_EGRESS()) 86*7b2fa44dSJiayuan Chen 87*7b2fa44dSJiayuan Chen #define RXMODE_BPF() ( \ 88*7b2fa44dSJiayuan Chen RXMODE_BPF_PASS() || \ 89*7b2fa44dSJiayuan Chen RXMODE_BPF_VERDICT()) 90*7b2fa44dSJiayuan Chen 91*7b2fa44dSJiayuan Chen #define RXMODE() ( \ 92*7b2fa44dSJiayuan Chen RXMODE_NORMAL() || \ 93*7b2fa44dSJiayuan Chen RXMODE_BPF()) 94*7b2fa44dSJiayuan Chen 95*7b2fa44dSJiayuan Chen static struct socmap_ctx { 96*7b2fa44dSJiayuan Chen struct bench_sockmap_prog *skel; 97*7b2fa44dSJiayuan Chen enum SOCKMAP_ARG_FLAG mode; 98*7b2fa44dSJiayuan Chen #define c1 fds[0] 99*7b2fa44dSJiayuan Chen #define p1 fds[1] 100*7b2fa44dSJiayuan Chen #define c2 fds[2] 101*7b2fa44dSJiayuan Chen #define p2 fds[3] 102*7b2fa44dSJiayuan Chen #define sfd fds[4] 103*7b2fa44dSJiayuan Chen int fds[5]; 104*7b2fa44dSJiayuan Chen long send_calls; 105*7b2fa44dSJiayuan Chen long read_calls; 106*7b2fa44dSJiayuan Chen long prod_send; 107*7b2fa44dSJiayuan Chen long user_read; 108*7b2fa44dSJiayuan Chen int file_size; 109*7b2fa44dSJiayuan Chen int delay_consumer; 110*7b2fa44dSJiayuan Chen int prod_run_time; 111*7b2fa44dSJiayuan Chen int strp_size; 112*7b2fa44dSJiayuan Chen } ctx = { 113*7b2fa44dSJiayuan Chen .prod_send = 0, 114*7b2fa44dSJiayuan Chen .user_read = 0, 115*7b2fa44dSJiayuan Chen .file_size = FILE_SIZE, 116*7b2fa44dSJiayuan Chen .mode = ARG_FW_RX_VERDICT_EGRESS, 117*7b2fa44dSJiayuan Chen .fds = {0}, 118*7b2fa44dSJiayuan Chen .delay_consumer = 0, 119*7b2fa44dSJiayuan Chen .prod_run_time = 0, 120*7b2fa44dSJiayuan Chen .strp_size = 0, 121*7b2fa44dSJiayuan Chen }; 122*7b2fa44dSJiayuan Chen 123*7b2fa44dSJiayuan Chen static void bench_sockmap_prog_destroy(void) 124*7b2fa44dSJiayuan Chen { 125*7b2fa44dSJiayuan Chen int i; 126*7b2fa44dSJiayuan Chen 127*7b2fa44dSJiayuan Chen for (i = 0; i < sizeof(ctx.fds); i++) { 128*7b2fa44dSJiayuan Chen if (ctx.fds[0] > 0) 129*7b2fa44dSJiayuan Chen close(ctx.fds[i]); 130*7b2fa44dSJiayuan Chen } 131*7b2fa44dSJiayuan Chen 132*7b2fa44dSJiayuan Chen bench_sockmap_prog__destroy(ctx.skel); 133*7b2fa44dSJiayuan Chen } 134*7b2fa44dSJiayuan Chen 135*7b2fa44dSJiayuan Chen static void init_addr(struct sockaddr_storage *ss, 136*7b2fa44dSJiayuan Chen socklen_t *len) 137*7b2fa44dSJiayuan Chen { 138*7b2fa44dSJiayuan Chen struct sockaddr_in *addr4 = memset(ss, 0, sizeof(*ss)); 139*7b2fa44dSJiayuan Chen 140*7b2fa44dSJiayuan Chen addr4->sin_family = AF_INET; 141*7b2fa44dSJiayuan Chen addr4->sin_port = 0; 142*7b2fa44dSJiayuan Chen addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 143*7b2fa44dSJiayuan Chen *len = sizeof(*addr4); 144*7b2fa44dSJiayuan Chen } 145*7b2fa44dSJiayuan Chen 146*7b2fa44dSJiayuan Chen static bool set_non_block(int fd, bool blocking) 147*7b2fa44dSJiayuan Chen { 148*7b2fa44dSJiayuan Chen int flags = fcntl(fd, F_GETFL, 0); 149*7b2fa44dSJiayuan Chen 150*7b2fa44dSJiayuan Chen if (flags == -1) 151*7b2fa44dSJiayuan Chen return false; 152*7b2fa44dSJiayuan Chen flags = blocking ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK); 153*7b2fa44dSJiayuan Chen return (fcntl(fd, F_SETFL, flags) == 0); 154*7b2fa44dSJiayuan Chen } 155*7b2fa44dSJiayuan Chen 156*7b2fa44dSJiayuan Chen static int create_pair(int *c, int *p, int type) 157*7b2fa44dSJiayuan Chen { 158*7b2fa44dSJiayuan Chen struct sockaddr_storage addr; 159*7b2fa44dSJiayuan Chen int err, cfd, pfd; 160*7b2fa44dSJiayuan Chen socklen_t addr_len = sizeof(struct sockaddr_storage); 161*7b2fa44dSJiayuan Chen 162*7b2fa44dSJiayuan Chen err = getsockname(ctx.sfd, (struct sockaddr *)&addr, &addr_len); 163*7b2fa44dSJiayuan Chen if (err) { 164*7b2fa44dSJiayuan Chen fprintf(stderr, "getsockname error %d\n", errno); 165*7b2fa44dSJiayuan Chen return err; 166*7b2fa44dSJiayuan Chen } 167*7b2fa44dSJiayuan Chen cfd = socket(AF_INET, type, 0); 168*7b2fa44dSJiayuan Chen if (cfd < 0) { 169*7b2fa44dSJiayuan Chen fprintf(stderr, "socket error %d\n", errno); 170*7b2fa44dSJiayuan Chen return err; 171*7b2fa44dSJiayuan Chen } 172*7b2fa44dSJiayuan Chen 173*7b2fa44dSJiayuan Chen err = connect(cfd, (struct sockaddr *)&addr, addr_len); 174*7b2fa44dSJiayuan Chen if (err && errno != EINPROGRESS) { 175*7b2fa44dSJiayuan Chen fprintf(stderr, "connect error %d\n", errno); 176*7b2fa44dSJiayuan Chen return err; 177*7b2fa44dSJiayuan Chen } 178*7b2fa44dSJiayuan Chen 179*7b2fa44dSJiayuan Chen pfd = accept(ctx.sfd, NULL, NULL); 180*7b2fa44dSJiayuan Chen if (pfd < 0) { 181*7b2fa44dSJiayuan Chen fprintf(stderr, "accept error %d\n", errno); 182*7b2fa44dSJiayuan Chen return err; 183*7b2fa44dSJiayuan Chen } 184*7b2fa44dSJiayuan Chen *c = cfd; 185*7b2fa44dSJiayuan Chen *p = pfd; 186*7b2fa44dSJiayuan Chen return 0; 187*7b2fa44dSJiayuan Chen } 188*7b2fa44dSJiayuan Chen 189*7b2fa44dSJiayuan Chen static int create_sockets(void) 190*7b2fa44dSJiayuan Chen { 191*7b2fa44dSJiayuan Chen struct sockaddr_storage addr; 192*7b2fa44dSJiayuan Chen int err, one = 1; 193*7b2fa44dSJiayuan Chen socklen_t addr_len; 194*7b2fa44dSJiayuan Chen 195*7b2fa44dSJiayuan Chen init_addr(&addr, &addr_len); 196*7b2fa44dSJiayuan Chen ctx.sfd = socket(AF_INET, SOCK_STREAM, 0); 197*7b2fa44dSJiayuan Chen if (ctx.sfd < 0) { 198*7b2fa44dSJiayuan Chen fprintf(stderr, "socket error:%d\n", errno); 199*7b2fa44dSJiayuan Chen return ctx.sfd; 200*7b2fa44dSJiayuan Chen } 201*7b2fa44dSJiayuan Chen err = setsockopt(ctx.sfd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); 202*7b2fa44dSJiayuan Chen if (err) { 203*7b2fa44dSJiayuan Chen fprintf(stderr, "setsockopt error:%d\n", errno); 204*7b2fa44dSJiayuan Chen return err; 205*7b2fa44dSJiayuan Chen } 206*7b2fa44dSJiayuan Chen 207*7b2fa44dSJiayuan Chen err = bind(ctx.sfd, (struct sockaddr *)&addr, addr_len); 208*7b2fa44dSJiayuan Chen if (err) { 209*7b2fa44dSJiayuan Chen fprintf(stderr, "bind error:%d\n", errno); 210*7b2fa44dSJiayuan Chen return err; 211*7b2fa44dSJiayuan Chen } 212*7b2fa44dSJiayuan Chen 213*7b2fa44dSJiayuan Chen err = listen(ctx.sfd, SOMAXCONN); 214*7b2fa44dSJiayuan Chen if (err) { 215*7b2fa44dSJiayuan Chen fprintf(stderr, "listen error:%d\n", errno); 216*7b2fa44dSJiayuan Chen return err; 217*7b2fa44dSJiayuan Chen } 218*7b2fa44dSJiayuan Chen 219*7b2fa44dSJiayuan Chen err = create_pair(&ctx.c1, &ctx.p1, SOCK_STREAM); 220*7b2fa44dSJiayuan Chen if (err) { 221*7b2fa44dSJiayuan Chen fprintf(stderr, "create_pair 1 error\n"); 222*7b2fa44dSJiayuan Chen return err; 223*7b2fa44dSJiayuan Chen } 224*7b2fa44dSJiayuan Chen 225*7b2fa44dSJiayuan Chen err = create_pair(&ctx.c2, &ctx.p2, SOCK_STREAM); 226*7b2fa44dSJiayuan Chen if (err) { 227*7b2fa44dSJiayuan Chen fprintf(stderr, "create_pair 2 error\n"); 228*7b2fa44dSJiayuan Chen return err; 229*7b2fa44dSJiayuan Chen } 230*7b2fa44dSJiayuan Chen printf("create socket fd c1:%d p1:%d c2:%d p2:%d\n", 231*7b2fa44dSJiayuan Chen ctx.c1, ctx.p1, ctx.c2, ctx.p2); 232*7b2fa44dSJiayuan Chen return 0; 233*7b2fa44dSJiayuan Chen } 234*7b2fa44dSJiayuan Chen 235*7b2fa44dSJiayuan Chen static void validate(void) 236*7b2fa44dSJiayuan Chen { 237*7b2fa44dSJiayuan Chen if (env.consumer_cnt != 2 || env.producer_cnt != 1 || 238*7b2fa44dSJiayuan Chen !env.affinity) 239*7b2fa44dSJiayuan Chen goto err; 240*7b2fa44dSJiayuan Chen return; 241*7b2fa44dSJiayuan Chen err: 242*7b2fa44dSJiayuan Chen fprintf(stderr, "argument '-c 2 -p 1 -a' is necessary"); 243*7b2fa44dSJiayuan Chen exit(1); 244*7b2fa44dSJiayuan Chen } 245*7b2fa44dSJiayuan Chen 246*7b2fa44dSJiayuan Chen static int setup_rx_sockmap(void) 247*7b2fa44dSJiayuan Chen { 248*7b2fa44dSJiayuan Chen int verdict, pass, parser, map; 249*7b2fa44dSJiayuan Chen int zero = 0, one = 1; 250*7b2fa44dSJiayuan Chen int err; 251*7b2fa44dSJiayuan Chen 252*7b2fa44dSJiayuan Chen parser = bpf_program__fd(ctx.skel->progs.prog_skb_parser); 253*7b2fa44dSJiayuan Chen verdict = bpf_program__fd(ctx.skel->progs.prog_skb_verdict); 254*7b2fa44dSJiayuan Chen pass = bpf_program__fd(ctx.skel->progs.prog_skb_pass); 255*7b2fa44dSJiayuan Chen map = bpf_map__fd(ctx.skel->maps.sock_map_rx); 256*7b2fa44dSJiayuan Chen 257*7b2fa44dSJiayuan Chen if (ctx.strp_size != 0) { 258*7b2fa44dSJiayuan Chen ctx.skel->bss->pkt_size = ctx.strp_size; 259*7b2fa44dSJiayuan Chen err = bpf_prog_attach(parser, map, BPF_SK_SKB_STREAM_PARSER, 0); 260*7b2fa44dSJiayuan Chen if (err) 261*7b2fa44dSJiayuan Chen return err; 262*7b2fa44dSJiayuan Chen } 263*7b2fa44dSJiayuan Chen 264*7b2fa44dSJiayuan Chen if (RXMODE_BPF_VERDICT()) 265*7b2fa44dSJiayuan Chen err = bpf_prog_attach(verdict, map, BPF_SK_SKB_STREAM_VERDICT, 0); 266*7b2fa44dSJiayuan Chen else if (RXMODE_BPF_PASS()) 267*7b2fa44dSJiayuan Chen err = bpf_prog_attach(pass, map, BPF_SK_SKB_STREAM_VERDICT, 0); 268*7b2fa44dSJiayuan Chen if (err) 269*7b2fa44dSJiayuan Chen return err; 270*7b2fa44dSJiayuan Chen 271*7b2fa44dSJiayuan Chen if (RXMODE_BPF_PASS()) 272*7b2fa44dSJiayuan Chen return bpf_map_update_elem(map, &zero, &ctx.c2, BPF_NOEXIST); 273*7b2fa44dSJiayuan Chen 274*7b2fa44dSJiayuan Chen err = bpf_map_update_elem(map, &zero, &ctx.p1, BPF_NOEXIST); 275*7b2fa44dSJiayuan Chen if (err < 0) 276*7b2fa44dSJiayuan Chen return err; 277*7b2fa44dSJiayuan Chen 278*7b2fa44dSJiayuan Chen if (RXMODE_BPF_VERDICT_INGRESS()) { 279*7b2fa44dSJiayuan Chen ctx.skel->bss->verdict_dir = BPF_F_INGRESS; 280*7b2fa44dSJiayuan Chen err = bpf_map_update_elem(map, &one, &ctx.c2, BPF_NOEXIST); 281*7b2fa44dSJiayuan Chen } else { 282*7b2fa44dSJiayuan Chen err = bpf_map_update_elem(map, &one, &ctx.p2, BPF_NOEXIST); 283*7b2fa44dSJiayuan Chen } 284*7b2fa44dSJiayuan Chen if (err < 0) 285*7b2fa44dSJiayuan Chen return err; 286*7b2fa44dSJiayuan Chen 287*7b2fa44dSJiayuan Chen return 0; 288*7b2fa44dSJiayuan Chen } 289*7b2fa44dSJiayuan Chen 290*7b2fa44dSJiayuan Chen static int setup_tx_sockmap(void) 291*7b2fa44dSJiayuan Chen { 292*7b2fa44dSJiayuan Chen int zero = 0, one = 1; 293*7b2fa44dSJiayuan Chen int prog, map; 294*7b2fa44dSJiayuan Chen int err; 295*7b2fa44dSJiayuan Chen 296*7b2fa44dSJiayuan Chen map = bpf_map__fd(ctx.skel->maps.sock_map_tx); 297*7b2fa44dSJiayuan Chen prog = TXMODE_BPF_PASS() ? 298*7b2fa44dSJiayuan Chen bpf_program__fd(ctx.skel->progs.prog_skmsg_pass) : 299*7b2fa44dSJiayuan Chen bpf_program__fd(ctx.skel->progs.prog_skmsg_verdict); 300*7b2fa44dSJiayuan Chen 301*7b2fa44dSJiayuan Chen err = bpf_prog_attach(prog, map, BPF_SK_MSG_VERDICT, 0); 302*7b2fa44dSJiayuan Chen if (err) 303*7b2fa44dSJiayuan Chen return err; 304*7b2fa44dSJiayuan Chen 305*7b2fa44dSJiayuan Chen if (TXMODE_BPF_EGRESS()) { 306*7b2fa44dSJiayuan Chen err = bpf_map_update_elem(map, &zero, &ctx.p1, BPF_NOEXIST); 307*7b2fa44dSJiayuan Chen err |= bpf_map_update_elem(map, &one, &ctx.p2, BPF_NOEXIST); 308*7b2fa44dSJiayuan Chen } else { 309*7b2fa44dSJiayuan Chen ctx.skel->bss->verdict_dir = BPF_F_INGRESS; 310*7b2fa44dSJiayuan Chen err = bpf_map_update_elem(map, &zero, &ctx.p2, BPF_NOEXIST); 311*7b2fa44dSJiayuan Chen err |= bpf_map_update_elem(map, &one, &ctx.c2, BPF_NOEXIST); 312*7b2fa44dSJiayuan Chen } 313*7b2fa44dSJiayuan Chen 314*7b2fa44dSJiayuan Chen if (err < 0) 315*7b2fa44dSJiayuan Chen return err; 316*7b2fa44dSJiayuan Chen 317*7b2fa44dSJiayuan Chen return 0; 318*7b2fa44dSJiayuan Chen } 319*7b2fa44dSJiayuan Chen 320*7b2fa44dSJiayuan Chen static void setup(void) 321*7b2fa44dSJiayuan Chen { 322*7b2fa44dSJiayuan Chen int err; 323*7b2fa44dSJiayuan Chen 324*7b2fa44dSJiayuan Chen ctx.skel = bench_sockmap_prog__open_and_load(); 325*7b2fa44dSJiayuan Chen if (!ctx.skel) { 326*7b2fa44dSJiayuan Chen fprintf(stderr, "error loading skel\n"); 327*7b2fa44dSJiayuan Chen exit(1); 328*7b2fa44dSJiayuan Chen } 329*7b2fa44dSJiayuan Chen 330*7b2fa44dSJiayuan Chen if (create_sockets()) { 331*7b2fa44dSJiayuan Chen fprintf(stderr, "create_net_mode error\n"); 332*7b2fa44dSJiayuan Chen goto err; 333*7b2fa44dSJiayuan Chen } 334*7b2fa44dSJiayuan Chen 335*7b2fa44dSJiayuan Chen if (RXMODE_BPF()) { 336*7b2fa44dSJiayuan Chen err = setup_rx_sockmap(); 337*7b2fa44dSJiayuan Chen if (err) { 338*7b2fa44dSJiayuan Chen fprintf(stderr, "setup_rx_sockmap error:%d\n", err); 339*7b2fa44dSJiayuan Chen goto err; 340*7b2fa44dSJiayuan Chen } 341*7b2fa44dSJiayuan Chen } else if (TXMODE_BPF()) { 342*7b2fa44dSJiayuan Chen err = setup_tx_sockmap(); 343*7b2fa44dSJiayuan Chen if (err) { 344*7b2fa44dSJiayuan Chen fprintf(stderr, "setup_tx_sockmap error:%d\n", err); 345*7b2fa44dSJiayuan Chen goto err; 346*7b2fa44dSJiayuan Chen } 347*7b2fa44dSJiayuan Chen } else { 348*7b2fa44dSJiayuan Chen fprintf(stderr, "unknown sockmap bench mode: %d\n", ctx.mode); 349*7b2fa44dSJiayuan Chen goto err; 350*7b2fa44dSJiayuan Chen } 351*7b2fa44dSJiayuan Chen 352*7b2fa44dSJiayuan Chen return; 353*7b2fa44dSJiayuan Chen 354*7b2fa44dSJiayuan Chen err: 355*7b2fa44dSJiayuan Chen bench_sockmap_prog_destroy(); 356*7b2fa44dSJiayuan Chen exit(1); 357*7b2fa44dSJiayuan Chen } 358*7b2fa44dSJiayuan Chen 359*7b2fa44dSJiayuan Chen static void measure(struct bench_res *res) 360*7b2fa44dSJiayuan Chen { 361*7b2fa44dSJiayuan Chen res->drops = atomic_swap(&ctx.prod_send, 0); 362*7b2fa44dSJiayuan Chen res->hits = atomic_swap(&ctx.skel->bss->process_byte, 0); 363*7b2fa44dSJiayuan Chen res->false_hits = atomic_swap(&ctx.user_read, 0); 364*7b2fa44dSJiayuan Chen res->important_hits = atomic_swap(&ctx.send_calls, 0); 365*7b2fa44dSJiayuan Chen res->important_hits |= atomic_swap(&ctx.read_calls, 0) << 32; 366*7b2fa44dSJiayuan Chen } 367*7b2fa44dSJiayuan Chen 368*7b2fa44dSJiayuan Chen static void verify_data(int *check_pos, char *buf, int rcv) 369*7b2fa44dSJiayuan Chen { 370*7b2fa44dSJiayuan Chen for (int i = 0 ; i < rcv; i++) { 371*7b2fa44dSJiayuan Chen if (buf[i] != snd_data[(*check_pos) % DATA_REPEAT_SIZE]) { 372*7b2fa44dSJiayuan Chen fprintf(stderr, "verify data fail"); 373*7b2fa44dSJiayuan Chen exit(1); 374*7b2fa44dSJiayuan Chen } 375*7b2fa44dSJiayuan Chen (*check_pos)++; 376*7b2fa44dSJiayuan Chen if (*check_pos >= FILE_SIZE) 377*7b2fa44dSJiayuan Chen *check_pos = 0; 378*7b2fa44dSJiayuan Chen } 379*7b2fa44dSJiayuan Chen } 380*7b2fa44dSJiayuan Chen 381*7b2fa44dSJiayuan Chen static void *consumer(void *input) 382*7b2fa44dSJiayuan Chen { 383*7b2fa44dSJiayuan Chen int rcv, sent; 384*7b2fa44dSJiayuan Chen int check_pos = 0; 385*7b2fa44dSJiayuan Chen int tid = (long)input; 386*7b2fa44dSJiayuan Chen int recv_buf_size = FILE_SIZE; 387*7b2fa44dSJiayuan Chen char *buf = malloc(recv_buf_size); 388*7b2fa44dSJiayuan Chen int delay_read = ctx.delay_consumer; 389*7b2fa44dSJiayuan Chen 390*7b2fa44dSJiayuan Chen if (!buf) { 391*7b2fa44dSJiayuan Chen fprintf(stderr, "fail to init read buffer"); 392*7b2fa44dSJiayuan Chen return NULL; 393*7b2fa44dSJiayuan Chen } 394*7b2fa44dSJiayuan Chen 395*7b2fa44dSJiayuan Chen while (true) { 396*7b2fa44dSJiayuan Chen if (tid == 1) { 397*7b2fa44dSJiayuan Chen /* consumer 1 is unused for tx test and stream verdict test */ 398*7b2fa44dSJiayuan Chen if (RXMODE_BPF() || TXMODE()) 399*7b2fa44dSJiayuan Chen return NULL; 400*7b2fa44dSJiayuan Chen /* it's only for RX_NORMAL which service as reserve-proxy mode */ 401*7b2fa44dSJiayuan Chen rcv = read(ctx.p1, buf, recv_buf_size); 402*7b2fa44dSJiayuan Chen if (rcv < 0) { 403*7b2fa44dSJiayuan Chen fprintf(stderr, "fail to read p1"); 404*7b2fa44dSJiayuan Chen return NULL; 405*7b2fa44dSJiayuan Chen } 406*7b2fa44dSJiayuan Chen 407*7b2fa44dSJiayuan Chen sent = send(ctx.p2, buf, recv_buf_size, 0); 408*7b2fa44dSJiayuan Chen if (sent < 0) { 409*7b2fa44dSJiayuan Chen fprintf(stderr, "fail to send p2"); 410*7b2fa44dSJiayuan Chen return NULL; 411*7b2fa44dSJiayuan Chen } 412*7b2fa44dSJiayuan Chen } else { 413*7b2fa44dSJiayuan Chen if (delay_read != 0) { 414*7b2fa44dSJiayuan Chen if (delay_read < 0) 415*7b2fa44dSJiayuan Chen return NULL; 416*7b2fa44dSJiayuan Chen sleep(delay_read); 417*7b2fa44dSJiayuan Chen delay_read = 0; 418*7b2fa44dSJiayuan Chen } 419*7b2fa44dSJiayuan Chen /* read real endpoint by consumer 0 */ 420*7b2fa44dSJiayuan Chen atomic_inc(&ctx.read_calls); 421*7b2fa44dSJiayuan Chen rcv = read(ctx.c2, buf, recv_buf_size); 422*7b2fa44dSJiayuan Chen if (rcv < 0 && errno != EAGAIN) { 423*7b2fa44dSJiayuan Chen fprintf(stderr, "%s fail to read c2 %d\n", __func__, errno); 424*7b2fa44dSJiayuan Chen return NULL; 425*7b2fa44dSJiayuan Chen } 426*7b2fa44dSJiayuan Chen verify_data(&check_pos, buf, rcv); 427*7b2fa44dSJiayuan Chen atomic_add(&ctx.user_read, rcv); 428*7b2fa44dSJiayuan Chen } 429*7b2fa44dSJiayuan Chen } 430*7b2fa44dSJiayuan Chen 431*7b2fa44dSJiayuan Chen return NULL; 432*7b2fa44dSJiayuan Chen } 433*7b2fa44dSJiayuan Chen 434*7b2fa44dSJiayuan Chen static void *producer(void *input) 435*7b2fa44dSJiayuan Chen { 436*7b2fa44dSJiayuan Chen int off = 0, fp, need_sent, sent; 437*7b2fa44dSJiayuan Chen int file_size = ctx.file_size; 438*7b2fa44dSJiayuan Chen struct timespec ts1, ts2; 439*7b2fa44dSJiayuan Chen int target; 440*7b2fa44dSJiayuan Chen FILE *file; 441*7b2fa44dSJiayuan Chen 442*7b2fa44dSJiayuan Chen file = tmpfile(); 443*7b2fa44dSJiayuan Chen if (!file) { 444*7b2fa44dSJiayuan Chen fprintf(stderr, "create file for sendfile"); 445*7b2fa44dSJiayuan Chen return NULL; 446*7b2fa44dSJiayuan Chen } 447*7b2fa44dSJiayuan Chen 448*7b2fa44dSJiayuan Chen /* we need simple verify */ 449*7b2fa44dSJiayuan Chen for (int i = 0; i < file_size; i++) { 450*7b2fa44dSJiayuan Chen if (fwrite(&snd_data[off], sizeof(char), 1, file) != 1) { 451*7b2fa44dSJiayuan Chen fprintf(stderr, "init tmpfile error"); 452*7b2fa44dSJiayuan Chen return NULL; 453*7b2fa44dSJiayuan Chen } 454*7b2fa44dSJiayuan Chen if (++off >= sizeof(snd_data)) 455*7b2fa44dSJiayuan Chen off = 0; 456*7b2fa44dSJiayuan Chen } 457*7b2fa44dSJiayuan Chen fflush(file); 458*7b2fa44dSJiayuan Chen fseek(file, 0, SEEK_SET); 459*7b2fa44dSJiayuan Chen 460*7b2fa44dSJiayuan Chen fp = fileno(file); 461*7b2fa44dSJiayuan Chen need_sent = file_size; 462*7b2fa44dSJiayuan Chen clock_gettime(CLOCK_MONOTONIC, &ts1); 463*7b2fa44dSJiayuan Chen 464*7b2fa44dSJiayuan Chen if (RXMODE_BPF_VERDICT()) 465*7b2fa44dSJiayuan Chen target = ctx.c1; 466*7b2fa44dSJiayuan Chen else if (TXMODE_BPF_EGRESS()) 467*7b2fa44dSJiayuan Chen target = ctx.p1; 468*7b2fa44dSJiayuan Chen else 469*7b2fa44dSJiayuan Chen target = ctx.p2; 470*7b2fa44dSJiayuan Chen set_non_block(target, true); 471*7b2fa44dSJiayuan Chen while (true) { 472*7b2fa44dSJiayuan Chen if (ctx.prod_run_time) { 473*7b2fa44dSJiayuan Chen clock_gettime(CLOCK_MONOTONIC, &ts2); 474*7b2fa44dSJiayuan Chen if (ts2.tv_sec - ts1.tv_sec > ctx.prod_run_time) 475*7b2fa44dSJiayuan Chen return NULL; 476*7b2fa44dSJiayuan Chen } 477*7b2fa44dSJiayuan Chen 478*7b2fa44dSJiayuan Chen errno = 0; 479*7b2fa44dSJiayuan Chen atomic_inc(&ctx.send_calls); 480*7b2fa44dSJiayuan Chen sent = sendfile(target, fp, NULL, need_sent); 481*7b2fa44dSJiayuan Chen if (sent < 0) { 482*7b2fa44dSJiayuan Chen if (errno != EAGAIN && errno != ENOMEM && errno != ENOBUFS) { 483*7b2fa44dSJiayuan Chen fprintf(stderr, "sendfile return %d, errorno %d:%s\n", 484*7b2fa44dSJiayuan Chen sent, errno, strerror(errno)); 485*7b2fa44dSJiayuan Chen return NULL; 486*7b2fa44dSJiayuan Chen } 487*7b2fa44dSJiayuan Chen continue; 488*7b2fa44dSJiayuan Chen } else if (sent < need_sent) { 489*7b2fa44dSJiayuan Chen need_sent -= sent; 490*7b2fa44dSJiayuan Chen atomic_add(&ctx.prod_send, sent); 491*7b2fa44dSJiayuan Chen continue; 492*7b2fa44dSJiayuan Chen } 493*7b2fa44dSJiayuan Chen atomic_add(&ctx.prod_send, need_sent); 494*7b2fa44dSJiayuan Chen need_sent = file_size; 495*7b2fa44dSJiayuan Chen lseek(fp, 0, SEEK_SET); 496*7b2fa44dSJiayuan Chen } 497*7b2fa44dSJiayuan Chen 498*7b2fa44dSJiayuan Chen return NULL; 499*7b2fa44dSJiayuan Chen } 500*7b2fa44dSJiayuan Chen 501*7b2fa44dSJiayuan Chen static void report_progress(int iter, struct bench_res *res, long delta_ns) 502*7b2fa44dSJiayuan Chen { 503*7b2fa44dSJiayuan Chen double speed_mbs, prod_mbs, bpf_mbs, send_hz, read_hz; 504*7b2fa44dSJiayuan Chen 505*7b2fa44dSJiayuan Chen prod_mbs = res->drops / 1000000.0 / (delta_ns / 1000000000.0); 506*7b2fa44dSJiayuan Chen speed_mbs = res->false_hits / 1000000.0 / (delta_ns / 1000000000.0); 507*7b2fa44dSJiayuan Chen bpf_mbs = res->hits / 1000000.0 / (delta_ns / 1000000000.0); 508*7b2fa44dSJiayuan Chen send_hz = (res->important_hits & 0xFFFFFFFF) / (delta_ns / 1000000000.0); 509*7b2fa44dSJiayuan Chen read_hz = (res->important_hits >> 32) / (delta_ns / 1000000000.0); 510*7b2fa44dSJiayuan Chen 511*7b2fa44dSJiayuan Chen printf("Iter %3d (%7.3lfus): ", 512*7b2fa44dSJiayuan Chen iter, (delta_ns - 1000000000) / 1000.0); 513*7b2fa44dSJiayuan Chen printf("Send Speed %8.3lf MB/s (%8.3lf calls/s), BPF Speed %8.3lf MB/s, " 514*7b2fa44dSJiayuan Chen "Rcv Speed %8.3lf MB/s (%8.3lf calls/s)\n", 515*7b2fa44dSJiayuan Chen prod_mbs, send_hz, bpf_mbs, speed_mbs, read_hz); 516*7b2fa44dSJiayuan Chen } 517*7b2fa44dSJiayuan Chen 518*7b2fa44dSJiayuan Chen static void report_final(struct bench_res res[], int res_cnt) 519*7b2fa44dSJiayuan Chen { 520*7b2fa44dSJiayuan Chen double verdict_mbs_mean = 0.0; 521*7b2fa44dSJiayuan Chen long verdict_total = 0; 522*7b2fa44dSJiayuan Chen int i; 523*7b2fa44dSJiayuan Chen 524*7b2fa44dSJiayuan Chen for (i = 0; i < res_cnt; i++) { 525*7b2fa44dSJiayuan Chen verdict_mbs_mean += res[i].hits / 1000000.0 / (0.0 + res_cnt); 526*7b2fa44dSJiayuan Chen verdict_total += res[i].hits / 1000000.0; 527*7b2fa44dSJiayuan Chen } 528*7b2fa44dSJiayuan Chen 529*7b2fa44dSJiayuan Chen printf("Summary: total trans %8.3lu MB \u00B1 %5.3lf MB/s\n", 530*7b2fa44dSJiayuan Chen verdict_total, verdict_mbs_mean); 531*7b2fa44dSJiayuan Chen } 532*7b2fa44dSJiayuan Chen 533*7b2fa44dSJiayuan Chen static const struct argp_option opts[] = { 534*7b2fa44dSJiayuan Chen { "rx-normal", ARG_FW_RX_NORMAL, NULL, 0, 535*7b2fa44dSJiayuan Chen "simple reserve-proxy mode, no bfp enabled"}, 536*7b2fa44dSJiayuan Chen { "rx-pass", ARG_FW_RX_PASS, NULL, 0, 537*7b2fa44dSJiayuan Chen "run bpf prog but no redir applied"}, 538*7b2fa44dSJiayuan Chen { "rx-strp", ARG_CTL_RX_STRP, "Byte", 0, 539*7b2fa44dSJiayuan Chen "enable strparser and set the encapsulation size"}, 540*7b2fa44dSJiayuan Chen { "rx-verdict-egress", ARG_FW_RX_VERDICT_EGRESS, NULL, 0, 541*7b2fa44dSJiayuan Chen "forward data with bpf(stream verdict)"}, 542*7b2fa44dSJiayuan Chen { "rx-verdict-ingress", ARG_FW_RX_VERDICT_INGRESS, NULL, 0, 543*7b2fa44dSJiayuan Chen "forward data with bpf(stream verdict)"}, 544*7b2fa44dSJiayuan Chen { "tx-normal", ARG_FW_TX_NORMAL, NULL, 0, 545*7b2fa44dSJiayuan Chen "simple c-s mode, no bfp enabled"}, 546*7b2fa44dSJiayuan Chen { "tx-pass", ARG_FW_TX_PASS, NULL, 0, 547*7b2fa44dSJiayuan Chen "run bpf prog but no redir applied"}, 548*7b2fa44dSJiayuan Chen { "tx-verdict-ingress", ARG_FW_TX_VERDICT_INGRESS, NULL, 0, 549*7b2fa44dSJiayuan Chen "forward msg to ingress queue of another socket"}, 550*7b2fa44dSJiayuan Chen { "tx-verdict-egress", ARG_FW_TX_VERDICT_EGRESS, NULL, 0, 551*7b2fa44dSJiayuan Chen "forward msg to egress queue of another socket"}, 552*7b2fa44dSJiayuan Chen { "delay-consumer", ARG_CONSUMER_DELAY_TIME, "SEC", 0, 553*7b2fa44dSJiayuan Chen "delay consumer start"}, 554*7b2fa44dSJiayuan Chen { "producer-duration", ARG_PRODUCER_DURATION, "SEC", 0, 555*7b2fa44dSJiayuan Chen "producer duration"}, 556*7b2fa44dSJiayuan Chen {}, 557*7b2fa44dSJiayuan Chen }; 558*7b2fa44dSJiayuan Chen 559*7b2fa44dSJiayuan Chen static error_t parse_arg(int key, char *arg, struct argp_state *state) 560*7b2fa44dSJiayuan Chen { 561*7b2fa44dSJiayuan Chen switch (key) { 562*7b2fa44dSJiayuan Chen case ARG_FW_RX_NORMAL...ARG_FW_TX_VERDICT_EGRESS: 563*7b2fa44dSJiayuan Chen ctx.mode = key; 564*7b2fa44dSJiayuan Chen break; 565*7b2fa44dSJiayuan Chen case ARG_CONSUMER_DELAY_TIME: 566*7b2fa44dSJiayuan Chen ctx.delay_consumer = strtol(arg, NULL, 10); 567*7b2fa44dSJiayuan Chen break; 568*7b2fa44dSJiayuan Chen case ARG_PRODUCER_DURATION: 569*7b2fa44dSJiayuan Chen ctx.prod_run_time = strtol(arg, NULL, 10); 570*7b2fa44dSJiayuan Chen break; 571*7b2fa44dSJiayuan Chen case ARG_CTL_RX_STRP: 572*7b2fa44dSJiayuan Chen ctx.strp_size = strtol(arg, NULL, 10); 573*7b2fa44dSJiayuan Chen break; 574*7b2fa44dSJiayuan Chen default: 575*7b2fa44dSJiayuan Chen return ARGP_ERR_UNKNOWN; 576*7b2fa44dSJiayuan Chen } 577*7b2fa44dSJiayuan Chen 578*7b2fa44dSJiayuan Chen return 0; 579*7b2fa44dSJiayuan Chen } 580*7b2fa44dSJiayuan Chen 581*7b2fa44dSJiayuan Chen /* exported into benchmark runner */ 582*7b2fa44dSJiayuan Chen const struct argp bench_sockmap_argp = { 583*7b2fa44dSJiayuan Chen .options = opts, 584*7b2fa44dSJiayuan Chen .parser = parse_arg, 585*7b2fa44dSJiayuan Chen }; 586*7b2fa44dSJiayuan Chen 587*7b2fa44dSJiayuan Chen /* Benchmark performance of creating bpf local storage */ 588*7b2fa44dSJiayuan Chen const struct bench bench_sockmap = { 589*7b2fa44dSJiayuan Chen .name = "sockmap", 590*7b2fa44dSJiayuan Chen .argp = &bench_sockmap_argp, 591*7b2fa44dSJiayuan Chen .validate = validate, 592*7b2fa44dSJiayuan Chen .setup = setup, 593*7b2fa44dSJiayuan Chen .producer_thread = producer, 594*7b2fa44dSJiayuan Chen .consumer_thread = consumer, 595*7b2fa44dSJiayuan Chen .measure = measure, 596*7b2fa44dSJiayuan Chen .report_progress = report_progress, 597*7b2fa44dSJiayuan Chen .report_final = report_final, 598*7b2fa44dSJiayuan Chen }; 599