162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (c) 2017-2018 Covalent IO, Inc. http://covalent.io 362306a36Sopenharmony_ci#include <stdio.h> 462306a36Sopenharmony_ci#include <stdlib.h> 562306a36Sopenharmony_ci#include <sys/socket.h> 662306a36Sopenharmony_ci#include <sys/ioctl.h> 762306a36Sopenharmony_ci#include <sys/select.h> 862306a36Sopenharmony_ci#include <netinet/in.h> 962306a36Sopenharmony_ci#include <arpa/inet.h> 1062306a36Sopenharmony_ci#include <unistd.h> 1162306a36Sopenharmony_ci#include <string.h> 1262306a36Sopenharmony_ci#include <errno.h> 1362306a36Sopenharmony_ci#include <stdbool.h> 1462306a36Sopenharmony_ci#include <signal.h> 1562306a36Sopenharmony_ci#include <fcntl.h> 1662306a36Sopenharmony_ci#include <sys/wait.h> 1762306a36Sopenharmony_ci#include <time.h> 1862306a36Sopenharmony_ci#include <sched.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <sys/time.h> 2162306a36Sopenharmony_ci#include <sys/types.h> 2262306a36Sopenharmony_ci#include <sys/sendfile.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/netlink.h> 2562306a36Sopenharmony_ci#include <linux/socket.h> 2662306a36Sopenharmony_ci#include <linux/sock_diag.h> 2762306a36Sopenharmony_ci#include <linux/bpf.h> 2862306a36Sopenharmony_ci#include <linux/if_link.h> 2962306a36Sopenharmony_ci#include <linux/tls.h> 3062306a36Sopenharmony_ci#include <assert.h> 3162306a36Sopenharmony_ci#include <libgen.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <getopt.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <bpf/bpf.h> 3662306a36Sopenharmony_ci#include <bpf/libbpf.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "bpf_util.h" 3962306a36Sopenharmony_ci#include "cgroup_helpers.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciint running; 4262306a36Sopenharmony_cistatic void running_handler(int a); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#ifndef TCP_ULP 4562306a36Sopenharmony_ci# define TCP_ULP 31 4662306a36Sopenharmony_ci#endif 4762306a36Sopenharmony_ci#ifndef SOL_TLS 4862306a36Sopenharmony_ci# define SOL_TLS 282 4962306a36Sopenharmony_ci#endif 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* randomly selected ports for testing on lo */ 5262306a36Sopenharmony_ci#define S1_PORT 10000 5362306a36Sopenharmony_ci#define S2_PORT 10001 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define BPF_SOCKMAP_FILENAME "test_sockmap_kern.bpf.o" 5662306a36Sopenharmony_ci#define BPF_SOCKHASH_FILENAME "test_sockhash_kern.bpf.o" 5762306a36Sopenharmony_ci#define CG_PATH "/sockmap" 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* global sockets */ 6062306a36Sopenharmony_ciint s1, s2, c1, c2, p1, p2; 6162306a36Sopenharmony_ciint test_cnt; 6262306a36Sopenharmony_ciint passed; 6362306a36Sopenharmony_ciint failed; 6462306a36Sopenharmony_ciint map_fd[9]; 6562306a36Sopenharmony_cistruct bpf_map *maps[9]; 6662306a36Sopenharmony_ciint prog_fd[11]; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ciint txmsg_pass; 6962306a36Sopenharmony_ciint txmsg_redir; 7062306a36Sopenharmony_ciint txmsg_drop; 7162306a36Sopenharmony_ciint txmsg_apply; 7262306a36Sopenharmony_ciint txmsg_cork; 7362306a36Sopenharmony_ciint txmsg_start; 7462306a36Sopenharmony_ciint txmsg_end; 7562306a36Sopenharmony_ciint txmsg_start_push; 7662306a36Sopenharmony_ciint txmsg_end_push; 7762306a36Sopenharmony_ciint txmsg_start_pop; 7862306a36Sopenharmony_ciint txmsg_pop; 7962306a36Sopenharmony_ciint txmsg_ingress; 8062306a36Sopenharmony_ciint txmsg_redir_skb; 8162306a36Sopenharmony_ciint txmsg_ktls_skb; 8262306a36Sopenharmony_ciint txmsg_ktls_skb_drop; 8362306a36Sopenharmony_ciint txmsg_ktls_skb_redir; 8462306a36Sopenharmony_ciint ktls; 8562306a36Sopenharmony_ciint peek_flag; 8662306a36Sopenharmony_ciint skb_use_parser; 8762306a36Sopenharmony_ciint txmsg_omit_skb_parser; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic const struct option long_options[] = { 9062306a36Sopenharmony_ci {"help", no_argument, NULL, 'h' }, 9162306a36Sopenharmony_ci {"cgroup", required_argument, NULL, 'c' }, 9262306a36Sopenharmony_ci {"rate", required_argument, NULL, 'r' }, 9362306a36Sopenharmony_ci {"verbose", optional_argument, NULL, 'v' }, 9462306a36Sopenharmony_ci {"iov_count", required_argument, NULL, 'i' }, 9562306a36Sopenharmony_ci {"length", required_argument, NULL, 'l' }, 9662306a36Sopenharmony_ci {"test", required_argument, NULL, 't' }, 9762306a36Sopenharmony_ci {"data_test", no_argument, NULL, 'd' }, 9862306a36Sopenharmony_ci {"txmsg", no_argument, &txmsg_pass, 1 }, 9962306a36Sopenharmony_ci {"txmsg_redir", no_argument, &txmsg_redir, 1 }, 10062306a36Sopenharmony_ci {"txmsg_drop", no_argument, &txmsg_drop, 1 }, 10162306a36Sopenharmony_ci {"txmsg_apply", required_argument, NULL, 'a'}, 10262306a36Sopenharmony_ci {"txmsg_cork", required_argument, NULL, 'k'}, 10362306a36Sopenharmony_ci {"txmsg_start", required_argument, NULL, 's'}, 10462306a36Sopenharmony_ci {"txmsg_end", required_argument, NULL, 'e'}, 10562306a36Sopenharmony_ci {"txmsg_start_push", required_argument, NULL, 'p'}, 10662306a36Sopenharmony_ci {"txmsg_end_push", required_argument, NULL, 'q'}, 10762306a36Sopenharmony_ci {"txmsg_start_pop", required_argument, NULL, 'w'}, 10862306a36Sopenharmony_ci {"txmsg_pop", required_argument, NULL, 'x'}, 10962306a36Sopenharmony_ci {"txmsg_ingress", no_argument, &txmsg_ingress, 1 }, 11062306a36Sopenharmony_ci {"txmsg_redir_skb", no_argument, &txmsg_redir_skb, 1 }, 11162306a36Sopenharmony_ci {"ktls", no_argument, &ktls, 1 }, 11262306a36Sopenharmony_ci {"peek", no_argument, &peek_flag, 1 }, 11362306a36Sopenharmony_ci {"txmsg_omit_skb_parser", no_argument, &txmsg_omit_skb_parser, 1}, 11462306a36Sopenharmony_ci {"whitelist", required_argument, NULL, 'n' }, 11562306a36Sopenharmony_ci {"blacklist", required_argument, NULL, 'b' }, 11662306a36Sopenharmony_ci {0, 0, NULL, 0 } 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistruct test_env { 12062306a36Sopenharmony_ci const char *type; 12162306a36Sopenharmony_ci const char *subtest; 12262306a36Sopenharmony_ci const char *prepend; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci int test_num; 12562306a36Sopenharmony_ci int subtest_num; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci int succ_cnt; 12862306a36Sopenharmony_ci int fail_cnt; 12962306a36Sopenharmony_ci int fail_last; 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistruct test_env env; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistruct sockmap_options { 13562306a36Sopenharmony_ci int verbose; 13662306a36Sopenharmony_ci bool base; 13762306a36Sopenharmony_ci bool sendpage; 13862306a36Sopenharmony_ci bool data_test; 13962306a36Sopenharmony_ci bool drop_expected; 14062306a36Sopenharmony_ci bool check_recved_len; 14162306a36Sopenharmony_ci bool tx_wait_mem; 14262306a36Sopenharmony_ci int iov_count; 14362306a36Sopenharmony_ci int iov_length; 14462306a36Sopenharmony_ci int rate; 14562306a36Sopenharmony_ci char *map; 14662306a36Sopenharmony_ci char *whitelist; 14762306a36Sopenharmony_ci char *blacklist; 14862306a36Sopenharmony_ci char *prepend; 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistruct _test { 15262306a36Sopenharmony_ci char *title; 15362306a36Sopenharmony_ci void (*tester)(int cg_fd, struct sockmap_options *opt); 15462306a36Sopenharmony_ci}; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void test_start(void) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci env.subtest_num++; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void test_fail(void) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci env.fail_cnt++; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic void test_pass(void) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci env.succ_cnt++; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic void test_reset(void) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci txmsg_start = txmsg_end = 0; 17462306a36Sopenharmony_ci txmsg_start_pop = txmsg_pop = 0; 17562306a36Sopenharmony_ci txmsg_start_push = txmsg_end_push = 0; 17662306a36Sopenharmony_ci txmsg_pass = txmsg_drop = txmsg_redir = 0; 17762306a36Sopenharmony_ci txmsg_apply = txmsg_cork = 0; 17862306a36Sopenharmony_ci txmsg_ingress = txmsg_redir_skb = 0; 17962306a36Sopenharmony_ci txmsg_ktls_skb = txmsg_ktls_skb_drop = txmsg_ktls_skb_redir = 0; 18062306a36Sopenharmony_ci txmsg_omit_skb_parser = 0; 18162306a36Sopenharmony_ci skb_use_parser = 0; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic int test_start_subtest(const struct _test *t, struct sockmap_options *o) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci env.type = o->map; 18762306a36Sopenharmony_ci env.subtest = t->title; 18862306a36Sopenharmony_ci env.prepend = o->prepend; 18962306a36Sopenharmony_ci env.test_num++; 19062306a36Sopenharmony_ci env.subtest_num = 0; 19162306a36Sopenharmony_ci env.fail_last = env.fail_cnt; 19262306a36Sopenharmony_ci test_reset(); 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void test_end_subtest(void) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci int error = env.fail_cnt - env.fail_last; 19962306a36Sopenharmony_ci int type = strcmp(env.type, BPF_SOCKMAP_FILENAME); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (!error) 20262306a36Sopenharmony_ci test_pass(); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci fprintf(stdout, "#%2d/%2d %8s:%s:%s:%s\n", 20562306a36Sopenharmony_ci env.test_num, env.subtest_num, 20662306a36Sopenharmony_ci !type ? "sockmap" : "sockhash", 20762306a36Sopenharmony_ci env.prepend ? : "", 20862306a36Sopenharmony_ci env.subtest, error ? "FAIL" : "OK"); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void test_print_results(void) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci fprintf(stdout, "Pass: %d Fail: %d\n", 21462306a36Sopenharmony_ci env.succ_cnt, env.fail_cnt); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void usage(char *argv[]) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci int i; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci printf(" Usage: %s --cgroup <cgroup_path>\n", argv[0]); 22262306a36Sopenharmony_ci printf(" options:\n"); 22362306a36Sopenharmony_ci for (i = 0; long_options[i].name != 0; i++) { 22462306a36Sopenharmony_ci printf(" --%-12s", long_options[i].name); 22562306a36Sopenharmony_ci if (long_options[i].flag != NULL) 22662306a36Sopenharmony_ci printf(" flag (internal value:%d)\n", 22762306a36Sopenharmony_ci *long_options[i].flag); 22862306a36Sopenharmony_ci else 22962306a36Sopenharmony_ci printf(" -%c\n", long_options[i].val); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci printf("\n"); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cichar *sock_to_string(int s) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci if (s == c1) 23762306a36Sopenharmony_ci return "client1"; 23862306a36Sopenharmony_ci else if (s == c2) 23962306a36Sopenharmony_ci return "client2"; 24062306a36Sopenharmony_ci else if (s == s1) 24162306a36Sopenharmony_ci return "server1"; 24262306a36Sopenharmony_ci else if (s == s2) 24362306a36Sopenharmony_ci return "server2"; 24462306a36Sopenharmony_ci else if (s == p1) 24562306a36Sopenharmony_ci return "peer1"; 24662306a36Sopenharmony_ci else if (s == p2) 24762306a36Sopenharmony_ci return "peer2"; 24862306a36Sopenharmony_ci else 24962306a36Sopenharmony_ci return "unknown"; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic int sockmap_init_ktls(int verbose, int s) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct tls12_crypto_info_aes_gcm_128 tls_tx = { 25562306a36Sopenharmony_ci .info = { 25662306a36Sopenharmony_ci .version = TLS_1_2_VERSION, 25762306a36Sopenharmony_ci .cipher_type = TLS_CIPHER_AES_GCM_128, 25862306a36Sopenharmony_ci }, 25962306a36Sopenharmony_ci }; 26062306a36Sopenharmony_ci struct tls12_crypto_info_aes_gcm_128 tls_rx = { 26162306a36Sopenharmony_ci .info = { 26262306a36Sopenharmony_ci .version = TLS_1_2_VERSION, 26362306a36Sopenharmony_ci .cipher_type = TLS_CIPHER_AES_GCM_128, 26462306a36Sopenharmony_ci }, 26562306a36Sopenharmony_ci }; 26662306a36Sopenharmony_ci int so_buf = 6553500; 26762306a36Sopenharmony_ci int err; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci err = setsockopt(s, 6, TCP_ULP, "tls", sizeof("tls")); 27062306a36Sopenharmony_ci if (err) { 27162306a36Sopenharmony_ci fprintf(stderr, "setsockopt: TCP_ULP(%s) failed with error %i\n", sock_to_string(s), err); 27262306a36Sopenharmony_ci return -EINVAL; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci err = setsockopt(s, SOL_TLS, TLS_TX, (void *)&tls_tx, sizeof(tls_tx)); 27562306a36Sopenharmony_ci if (err) { 27662306a36Sopenharmony_ci fprintf(stderr, "setsockopt: TLS_TX(%s) failed with error %i\n", sock_to_string(s), err); 27762306a36Sopenharmony_ci return -EINVAL; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci err = setsockopt(s, SOL_TLS, TLS_RX, (void *)&tls_rx, sizeof(tls_rx)); 28062306a36Sopenharmony_ci if (err) { 28162306a36Sopenharmony_ci fprintf(stderr, "setsockopt: TLS_RX(%s) failed with error %i\n", sock_to_string(s), err); 28262306a36Sopenharmony_ci return -EINVAL; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &so_buf, sizeof(so_buf)); 28562306a36Sopenharmony_ci if (err) { 28662306a36Sopenharmony_ci fprintf(stderr, "setsockopt: (%s) failed sndbuf with error %i\n", sock_to_string(s), err); 28762306a36Sopenharmony_ci return -EINVAL; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, &so_buf, sizeof(so_buf)); 29062306a36Sopenharmony_ci if (err) { 29162306a36Sopenharmony_ci fprintf(stderr, "setsockopt: (%s) failed rcvbuf with error %i\n", sock_to_string(s), err); 29262306a36Sopenharmony_ci return -EINVAL; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (verbose) 29662306a36Sopenharmony_ci fprintf(stdout, "socket(%s) kTLS enabled\n", sock_to_string(s)); 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_cistatic int sockmap_init_sockets(int verbose) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci int i, err, one = 1; 30262306a36Sopenharmony_ci struct sockaddr_in addr; 30362306a36Sopenharmony_ci int *fds[4] = {&s1, &s2, &c1, &c2}; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci s1 = s2 = p1 = p2 = c1 = c2 = 0; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* Init sockets */ 30862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 30962306a36Sopenharmony_ci *fds[i] = socket(AF_INET, SOCK_STREAM, 0); 31062306a36Sopenharmony_ci if (*fds[i] < 0) { 31162306a36Sopenharmony_ci perror("socket s1 failed()"); 31262306a36Sopenharmony_ci return errno; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Allow reuse */ 31762306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 31862306a36Sopenharmony_ci err = setsockopt(*fds[i], SOL_SOCKET, SO_REUSEADDR, 31962306a36Sopenharmony_ci (char *)&one, sizeof(one)); 32062306a36Sopenharmony_ci if (err) { 32162306a36Sopenharmony_ci perror("setsockopt failed()"); 32262306a36Sopenharmony_ci return errno; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* Non-blocking sockets */ 32762306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 32862306a36Sopenharmony_ci err = ioctl(*fds[i], FIONBIO, (char *)&one); 32962306a36Sopenharmony_ci if (err < 0) { 33062306a36Sopenharmony_ci perror("ioctl s1 failed()"); 33162306a36Sopenharmony_ci return errno; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Bind server sockets */ 33662306a36Sopenharmony_ci memset(&addr, 0, sizeof(struct sockaddr_in)); 33762306a36Sopenharmony_ci addr.sin_family = AF_INET; 33862306a36Sopenharmony_ci addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci addr.sin_port = htons(S1_PORT); 34162306a36Sopenharmony_ci err = bind(s1, (struct sockaddr *)&addr, sizeof(addr)); 34262306a36Sopenharmony_ci if (err < 0) { 34362306a36Sopenharmony_ci perror("bind s1 failed()"); 34462306a36Sopenharmony_ci return errno; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci addr.sin_port = htons(S2_PORT); 34862306a36Sopenharmony_ci err = bind(s2, (struct sockaddr *)&addr, sizeof(addr)); 34962306a36Sopenharmony_ci if (err < 0) { 35062306a36Sopenharmony_ci perror("bind s2 failed()"); 35162306a36Sopenharmony_ci return errno; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* Listen server sockets */ 35562306a36Sopenharmony_ci addr.sin_port = htons(S1_PORT); 35662306a36Sopenharmony_ci err = listen(s1, 32); 35762306a36Sopenharmony_ci if (err < 0) { 35862306a36Sopenharmony_ci perror("listen s1 failed()"); 35962306a36Sopenharmony_ci return errno; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci addr.sin_port = htons(S2_PORT); 36362306a36Sopenharmony_ci err = listen(s2, 32); 36462306a36Sopenharmony_ci if (err < 0) { 36562306a36Sopenharmony_ci perror("listen s1 failed()"); 36662306a36Sopenharmony_ci return errno; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* Initiate Connect */ 37062306a36Sopenharmony_ci addr.sin_port = htons(S1_PORT); 37162306a36Sopenharmony_ci err = connect(c1, (struct sockaddr *)&addr, sizeof(addr)); 37262306a36Sopenharmony_ci if (err < 0 && errno != EINPROGRESS) { 37362306a36Sopenharmony_ci perror("connect c1 failed()"); 37462306a36Sopenharmony_ci return errno; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci addr.sin_port = htons(S2_PORT); 37862306a36Sopenharmony_ci err = connect(c2, (struct sockaddr *)&addr, sizeof(addr)); 37962306a36Sopenharmony_ci if (err < 0 && errno != EINPROGRESS) { 38062306a36Sopenharmony_ci perror("connect c2 failed()"); 38162306a36Sopenharmony_ci return errno; 38262306a36Sopenharmony_ci } else if (err < 0) { 38362306a36Sopenharmony_ci err = 0; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* Accept Connecrtions */ 38762306a36Sopenharmony_ci p1 = accept(s1, NULL, NULL); 38862306a36Sopenharmony_ci if (p1 < 0) { 38962306a36Sopenharmony_ci perror("accept s1 failed()"); 39062306a36Sopenharmony_ci return errno; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci p2 = accept(s2, NULL, NULL); 39462306a36Sopenharmony_ci if (p2 < 0) { 39562306a36Sopenharmony_ci perror("accept s1 failed()"); 39662306a36Sopenharmony_ci return errno; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (verbose > 1) { 40062306a36Sopenharmony_ci printf("connected sockets: c1 <-> p1, c2 <-> p2\n"); 40162306a36Sopenharmony_ci printf("cgroups binding: c1(%i) <-> s1(%i) - - - c2(%i) <-> s2(%i)\n", 40262306a36Sopenharmony_ci c1, s1, c2, s2); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistruct msg_stats { 40862306a36Sopenharmony_ci size_t bytes_sent; 40962306a36Sopenharmony_ci size_t bytes_recvd; 41062306a36Sopenharmony_ci struct timespec start; 41162306a36Sopenharmony_ci struct timespec end; 41262306a36Sopenharmony_ci}; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic int msg_loop_sendpage(int fd, int iov_length, int cnt, 41562306a36Sopenharmony_ci struct msg_stats *s, 41662306a36Sopenharmony_ci struct sockmap_options *opt) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci bool drop = opt->drop_expected; 41962306a36Sopenharmony_ci unsigned char k = 0; 42062306a36Sopenharmony_ci FILE *file; 42162306a36Sopenharmony_ci int i, fp; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci file = tmpfile(); 42462306a36Sopenharmony_ci if (!file) { 42562306a36Sopenharmony_ci perror("create file for sendpage"); 42662306a36Sopenharmony_ci return 1; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci for (i = 0; i < iov_length * cnt; i++, k++) 42962306a36Sopenharmony_ci fwrite(&k, sizeof(char), 1, file); 43062306a36Sopenharmony_ci fflush(file); 43162306a36Sopenharmony_ci fseek(file, 0, SEEK_SET); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci fp = fileno(file); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &s->start); 43662306a36Sopenharmony_ci for (i = 0; i < cnt; i++) { 43762306a36Sopenharmony_ci int sent; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci errno = 0; 44062306a36Sopenharmony_ci sent = sendfile(fd, fp, NULL, iov_length); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (!drop && sent < 0) { 44362306a36Sopenharmony_ci perror("sendpage loop error"); 44462306a36Sopenharmony_ci fclose(file); 44562306a36Sopenharmony_ci return sent; 44662306a36Sopenharmony_ci } else if (drop && sent >= 0) { 44762306a36Sopenharmony_ci printf("sendpage loop error expected: %i errno %i\n", 44862306a36Sopenharmony_ci sent, errno); 44962306a36Sopenharmony_ci fclose(file); 45062306a36Sopenharmony_ci return -EIO; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (sent > 0) 45462306a36Sopenharmony_ci s->bytes_sent += sent; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &s->end); 45762306a36Sopenharmony_ci fclose(file); 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void msg_free_iov(struct msghdr *msg) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci int i; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci for (i = 0; i < msg->msg_iovlen; i++) 46662306a36Sopenharmony_ci free(msg->msg_iov[i].iov_base); 46762306a36Sopenharmony_ci free(msg->msg_iov); 46862306a36Sopenharmony_ci msg->msg_iov = NULL; 46962306a36Sopenharmony_ci msg->msg_iovlen = 0; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic int msg_alloc_iov(struct msghdr *msg, 47362306a36Sopenharmony_ci int iov_count, int iov_length, 47462306a36Sopenharmony_ci bool data, bool xmit) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci unsigned char k = 0; 47762306a36Sopenharmony_ci struct iovec *iov; 47862306a36Sopenharmony_ci int i; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci iov = calloc(iov_count, sizeof(struct iovec)); 48162306a36Sopenharmony_ci if (!iov) 48262306a36Sopenharmony_ci return errno; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci for (i = 0; i < iov_count; i++) { 48562306a36Sopenharmony_ci unsigned char *d = calloc(iov_length, sizeof(char)); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (!d) { 48862306a36Sopenharmony_ci fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count); 48962306a36Sopenharmony_ci goto unwind_iov; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci iov[i].iov_base = d; 49262306a36Sopenharmony_ci iov[i].iov_len = iov_length; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (data && xmit) { 49562306a36Sopenharmony_ci int j; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci for (j = 0; j < iov_length; j++) 49862306a36Sopenharmony_ci d[j] = k++; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci msg->msg_iov = iov; 50362306a36Sopenharmony_ci msg->msg_iovlen = iov_count; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci return 0; 50662306a36Sopenharmony_ciunwind_iov: 50762306a36Sopenharmony_ci for (i--; i >= 0 ; i--) 50862306a36Sopenharmony_ci free(msg->msg_iov[i].iov_base); 50962306a36Sopenharmony_ci return -ENOMEM; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic int msg_verify_data(struct msghdr *msg, int size, int chunk_sz) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci int i, j = 0, bytes_cnt = 0; 51562306a36Sopenharmony_ci unsigned char k = 0; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci for (i = 0; i < msg->msg_iovlen; i++) { 51862306a36Sopenharmony_ci unsigned char *d = msg->msg_iov[i].iov_base; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Special case test for skb ingress + ktls */ 52162306a36Sopenharmony_ci if (i == 0 && txmsg_ktls_skb) { 52262306a36Sopenharmony_ci if (msg->msg_iov[i].iov_len < 4) 52362306a36Sopenharmony_ci return -EIO; 52462306a36Sopenharmony_ci if (memcmp(d, "PASS", 4) != 0) { 52562306a36Sopenharmony_ci fprintf(stderr, 52662306a36Sopenharmony_ci "detected skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n", 52762306a36Sopenharmony_ci i, 0, d[0], d[1], d[2], d[3]); 52862306a36Sopenharmony_ci return -EIO; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci j = 4; /* advance index past PASS header */ 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci for (; j < msg->msg_iov[i].iov_len && size; j++) { 53462306a36Sopenharmony_ci if (d[j] != k++) { 53562306a36Sopenharmony_ci fprintf(stderr, 53662306a36Sopenharmony_ci "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n", 53762306a36Sopenharmony_ci i, j, d[j], k - 1, d[j+1], k); 53862306a36Sopenharmony_ci return -EIO; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci bytes_cnt++; 54162306a36Sopenharmony_ci if (bytes_cnt == chunk_sz) { 54262306a36Sopenharmony_ci k = 0; 54362306a36Sopenharmony_ci bytes_cnt = 0; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci size--; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci return 0; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic int msg_loop(int fd, int iov_count, int iov_length, int cnt, 55262306a36Sopenharmony_ci struct msg_stats *s, bool tx, 55362306a36Sopenharmony_ci struct sockmap_options *opt) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci struct msghdr msg = {0}, msg_peek = {0}; 55662306a36Sopenharmony_ci int err, i, flags = MSG_NOSIGNAL; 55762306a36Sopenharmony_ci bool drop = opt->drop_expected; 55862306a36Sopenharmony_ci bool data = opt->data_test; 55962306a36Sopenharmony_ci int iov_alloc_length = iov_length; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (!tx && opt->check_recved_len) 56262306a36Sopenharmony_ci iov_alloc_length *= 2; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci err = msg_alloc_iov(&msg, iov_count, iov_alloc_length, data, tx); 56562306a36Sopenharmony_ci if (err) 56662306a36Sopenharmony_ci goto out_errno; 56762306a36Sopenharmony_ci if (peek_flag) { 56862306a36Sopenharmony_ci err = msg_alloc_iov(&msg_peek, iov_count, iov_length, data, tx); 56962306a36Sopenharmony_ci if (err) 57062306a36Sopenharmony_ci goto out_errno; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (tx) { 57462306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &s->start); 57562306a36Sopenharmony_ci for (i = 0; i < cnt; i++) { 57662306a36Sopenharmony_ci int sent; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci errno = 0; 57962306a36Sopenharmony_ci sent = sendmsg(fd, &msg, flags); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (!drop && sent < 0) { 58262306a36Sopenharmony_ci if (opt->tx_wait_mem && errno == EACCES) { 58362306a36Sopenharmony_ci errno = 0; 58462306a36Sopenharmony_ci goto out_errno; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci perror("sendmsg loop error"); 58762306a36Sopenharmony_ci goto out_errno; 58862306a36Sopenharmony_ci } else if (drop && sent >= 0) { 58962306a36Sopenharmony_ci fprintf(stderr, 59062306a36Sopenharmony_ci "sendmsg loop error expected: %i errno %i\n", 59162306a36Sopenharmony_ci sent, errno); 59262306a36Sopenharmony_ci errno = -EIO; 59362306a36Sopenharmony_ci goto out_errno; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci if (sent > 0) 59662306a36Sopenharmony_ci s->bytes_sent += sent; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &s->end); 59962306a36Sopenharmony_ci } else { 60062306a36Sopenharmony_ci int slct, recvp = 0, recv, max_fd = fd; 60162306a36Sopenharmony_ci float total_bytes, txmsg_pop_total; 60262306a36Sopenharmony_ci int fd_flags = O_NONBLOCK; 60362306a36Sopenharmony_ci struct timeval timeout; 60462306a36Sopenharmony_ci fd_set w; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci fcntl(fd, fd_flags); 60762306a36Sopenharmony_ci /* Account for pop bytes noting each iteration of apply will 60862306a36Sopenharmony_ci * call msg_pop_data helper so we need to account for this 60962306a36Sopenharmony_ci * by calculating the number of apply iterations. Note user 61062306a36Sopenharmony_ci * of the tool can create cases where no data is sent by 61162306a36Sopenharmony_ci * manipulating pop/push/pull/etc. For example txmsg_apply 1 61262306a36Sopenharmony_ci * with txmsg_pop 1 will try to apply 1B at a time but each 61362306a36Sopenharmony_ci * iteration will then pop 1B so no data will ever be sent. 61462306a36Sopenharmony_ci * This is really only useful for testing edge cases in code 61562306a36Sopenharmony_ci * paths. 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_ci total_bytes = (float)iov_count * (float)iov_length * (float)cnt; 61862306a36Sopenharmony_ci if (txmsg_apply) 61962306a36Sopenharmony_ci txmsg_pop_total = txmsg_pop * (total_bytes / txmsg_apply); 62062306a36Sopenharmony_ci else 62162306a36Sopenharmony_ci txmsg_pop_total = txmsg_pop * cnt; 62262306a36Sopenharmony_ci total_bytes -= txmsg_pop_total; 62362306a36Sopenharmony_ci err = clock_gettime(CLOCK_MONOTONIC, &s->start); 62462306a36Sopenharmony_ci if (err < 0) 62562306a36Sopenharmony_ci perror("recv start time"); 62662306a36Sopenharmony_ci while (s->bytes_recvd < total_bytes) { 62762306a36Sopenharmony_ci if (txmsg_cork) { 62862306a36Sopenharmony_ci timeout.tv_sec = 0; 62962306a36Sopenharmony_ci timeout.tv_usec = 300000; 63062306a36Sopenharmony_ci } else { 63162306a36Sopenharmony_ci timeout.tv_sec = 3; 63262306a36Sopenharmony_ci timeout.tv_usec = 0; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* FD sets */ 63662306a36Sopenharmony_ci FD_ZERO(&w); 63762306a36Sopenharmony_ci FD_SET(fd, &w); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci slct = select(max_fd + 1, &w, NULL, NULL, &timeout); 64062306a36Sopenharmony_ci if (slct == -1) { 64162306a36Sopenharmony_ci perror("select()"); 64262306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &s->end); 64362306a36Sopenharmony_ci goto out_errno; 64462306a36Sopenharmony_ci } else if (!slct) { 64562306a36Sopenharmony_ci if (opt->verbose) 64662306a36Sopenharmony_ci fprintf(stderr, "unexpected timeout: recved %zu/%f pop_total %f\n", s->bytes_recvd, total_bytes, txmsg_pop_total); 64762306a36Sopenharmony_ci errno = -EIO; 64862306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &s->end); 64962306a36Sopenharmony_ci goto out_errno; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (opt->tx_wait_mem) { 65362306a36Sopenharmony_ci FD_ZERO(&w); 65462306a36Sopenharmony_ci FD_SET(fd, &w); 65562306a36Sopenharmony_ci slct = select(max_fd + 1, NULL, NULL, &w, &timeout); 65662306a36Sopenharmony_ci errno = 0; 65762306a36Sopenharmony_ci close(fd); 65862306a36Sopenharmony_ci goto out_errno; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci errno = 0; 66262306a36Sopenharmony_ci if (peek_flag) { 66362306a36Sopenharmony_ci flags |= MSG_PEEK; 66462306a36Sopenharmony_ci recvp = recvmsg(fd, &msg_peek, flags); 66562306a36Sopenharmony_ci if (recvp < 0) { 66662306a36Sopenharmony_ci if (errno != EWOULDBLOCK) { 66762306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &s->end); 66862306a36Sopenharmony_ci goto out_errno; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci flags = 0; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci recv = recvmsg(fd, &msg, flags); 67562306a36Sopenharmony_ci if (recv < 0) { 67662306a36Sopenharmony_ci if (errno != EWOULDBLOCK) { 67762306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &s->end); 67862306a36Sopenharmony_ci perror("recv failed()"); 67962306a36Sopenharmony_ci goto out_errno; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci s->bytes_recvd += recv; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (opt->check_recved_len && s->bytes_recvd > total_bytes) { 68662306a36Sopenharmony_ci errno = EMSGSIZE; 68762306a36Sopenharmony_ci fprintf(stderr, "recv failed(), bytes_recvd:%zd, total_bytes:%f\n", 68862306a36Sopenharmony_ci s->bytes_recvd, total_bytes); 68962306a36Sopenharmony_ci goto out_errno; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (data) { 69362306a36Sopenharmony_ci int chunk_sz = opt->sendpage ? 69462306a36Sopenharmony_ci iov_length * cnt : 69562306a36Sopenharmony_ci iov_length * iov_count; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci errno = msg_verify_data(&msg, recv, chunk_sz); 69862306a36Sopenharmony_ci if (errno) { 69962306a36Sopenharmony_ci perror("data verify msg failed"); 70062306a36Sopenharmony_ci goto out_errno; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci if (recvp) { 70362306a36Sopenharmony_ci errno = msg_verify_data(&msg_peek, 70462306a36Sopenharmony_ci recvp, 70562306a36Sopenharmony_ci chunk_sz); 70662306a36Sopenharmony_ci if (errno) { 70762306a36Sopenharmony_ci perror("data verify msg_peek failed"); 70862306a36Sopenharmony_ci goto out_errno; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &s->end); 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci msg_free_iov(&msg); 71762306a36Sopenharmony_ci msg_free_iov(&msg_peek); 71862306a36Sopenharmony_ci return err; 71962306a36Sopenharmony_ciout_errno: 72062306a36Sopenharmony_ci msg_free_iov(&msg); 72162306a36Sopenharmony_ci msg_free_iov(&msg_peek); 72262306a36Sopenharmony_ci return errno; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic float giga = 1000000000; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic inline float sentBps(struct msg_stats s) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci return s.bytes_sent / (s.end.tv_sec - s.start.tv_sec); 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic inline float recvdBps(struct msg_stats s) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec); 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic int sendmsg_test(struct sockmap_options *opt) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci float sent_Bps = 0, recvd_Bps = 0; 74062306a36Sopenharmony_ci int rx_fd, txpid, rxpid, err = 0; 74162306a36Sopenharmony_ci struct msg_stats s = {0}; 74262306a36Sopenharmony_ci int iov_count = opt->iov_count; 74362306a36Sopenharmony_ci int iov_buf = opt->iov_length; 74462306a36Sopenharmony_ci int rx_status, tx_status; 74562306a36Sopenharmony_ci int cnt = opt->rate; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci errno = 0; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (opt->base) 75062306a36Sopenharmony_ci rx_fd = p1; 75162306a36Sopenharmony_ci else 75262306a36Sopenharmony_ci rx_fd = p2; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (ktls) { 75562306a36Sopenharmony_ci /* Redirecting into non-TLS socket which sends into a TLS 75662306a36Sopenharmony_ci * socket is not a valid test. So in this case lets not 75762306a36Sopenharmony_ci * enable kTLS but still run the test. 75862306a36Sopenharmony_ci */ 75962306a36Sopenharmony_ci if (!txmsg_redir || txmsg_ingress) { 76062306a36Sopenharmony_ci err = sockmap_init_ktls(opt->verbose, rx_fd); 76162306a36Sopenharmony_ci if (err) 76262306a36Sopenharmony_ci return err; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci err = sockmap_init_ktls(opt->verbose, c1); 76562306a36Sopenharmony_ci if (err) 76662306a36Sopenharmony_ci return err; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (opt->tx_wait_mem) { 77062306a36Sopenharmony_ci struct timeval timeout; 77162306a36Sopenharmony_ci int rxtx_buf_len = 1024; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci timeout.tv_sec = 3; 77462306a36Sopenharmony_ci timeout.tv_usec = 0; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci err = setsockopt(c2, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)); 77762306a36Sopenharmony_ci err |= setsockopt(c2, SOL_SOCKET, SO_SNDBUFFORCE, &rxtx_buf_len, sizeof(int)); 77862306a36Sopenharmony_ci err |= setsockopt(p2, SOL_SOCKET, SO_RCVBUFFORCE, &rxtx_buf_len, sizeof(int)); 77962306a36Sopenharmony_ci if (err) { 78062306a36Sopenharmony_ci perror("setsockopt failed()"); 78162306a36Sopenharmony_ci return errno; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci rxpid = fork(); 78662306a36Sopenharmony_ci if (rxpid == 0) { 78762306a36Sopenharmony_ci if (txmsg_pop || txmsg_start_pop) 78862306a36Sopenharmony_ci iov_buf -= (txmsg_pop - txmsg_start_pop + 1); 78962306a36Sopenharmony_ci if (opt->drop_expected || txmsg_ktls_skb_drop) 79062306a36Sopenharmony_ci _exit(0); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (!iov_buf) /* zero bytes sent case */ 79362306a36Sopenharmony_ci _exit(0); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (opt->sendpage) 79662306a36Sopenharmony_ci iov_count = 1; 79762306a36Sopenharmony_ci err = msg_loop(rx_fd, iov_count, iov_buf, 79862306a36Sopenharmony_ci cnt, &s, false, opt); 79962306a36Sopenharmony_ci if (opt->verbose > 1) 80062306a36Sopenharmony_ci fprintf(stderr, 80162306a36Sopenharmony_ci "msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n", 80262306a36Sopenharmony_ci iov_count, iov_buf, cnt, err); 80362306a36Sopenharmony_ci if (s.end.tv_sec - s.start.tv_sec) { 80462306a36Sopenharmony_ci sent_Bps = sentBps(s); 80562306a36Sopenharmony_ci recvd_Bps = recvdBps(s); 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci if (opt->verbose > 1) 80862306a36Sopenharmony_ci fprintf(stdout, 80962306a36Sopenharmony_ci "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s %s\n", 81062306a36Sopenharmony_ci s.bytes_sent, sent_Bps, sent_Bps/giga, 81162306a36Sopenharmony_ci s.bytes_recvd, recvd_Bps, recvd_Bps/giga, 81262306a36Sopenharmony_ci peek_flag ? "(peek_msg)" : ""); 81362306a36Sopenharmony_ci if (err && txmsg_cork) 81462306a36Sopenharmony_ci err = 0; 81562306a36Sopenharmony_ci exit(err ? 1 : 0); 81662306a36Sopenharmony_ci } else if (rxpid == -1) { 81762306a36Sopenharmony_ci perror("msg_loop_rx"); 81862306a36Sopenharmony_ci return errno; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (opt->tx_wait_mem) 82262306a36Sopenharmony_ci close(c2); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci txpid = fork(); 82562306a36Sopenharmony_ci if (txpid == 0) { 82662306a36Sopenharmony_ci if (opt->sendpage) 82762306a36Sopenharmony_ci err = msg_loop_sendpage(c1, iov_buf, cnt, &s, opt); 82862306a36Sopenharmony_ci else 82962306a36Sopenharmony_ci err = msg_loop(c1, iov_count, iov_buf, 83062306a36Sopenharmony_ci cnt, &s, true, opt); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (err) 83362306a36Sopenharmony_ci fprintf(stderr, 83462306a36Sopenharmony_ci "msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n", 83562306a36Sopenharmony_ci iov_count, iov_buf, cnt, err); 83662306a36Sopenharmony_ci if (s.end.tv_sec - s.start.tv_sec) { 83762306a36Sopenharmony_ci sent_Bps = sentBps(s); 83862306a36Sopenharmony_ci recvd_Bps = recvdBps(s); 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci if (opt->verbose > 1) 84162306a36Sopenharmony_ci fprintf(stdout, 84262306a36Sopenharmony_ci "tx_sendmsg: TX: %zuB %fB/s %f GB/s RX: %zuB %fB/s %fGB/s\n", 84362306a36Sopenharmony_ci s.bytes_sent, sent_Bps, sent_Bps/giga, 84462306a36Sopenharmony_ci s.bytes_recvd, recvd_Bps, recvd_Bps/giga); 84562306a36Sopenharmony_ci exit(err ? 1 : 0); 84662306a36Sopenharmony_ci } else if (txpid == -1) { 84762306a36Sopenharmony_ci perror("msg_loop_tx"); 84862306a36Sopenharmony_ci return errno; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci assert(waitpid(rxpid, &rx_status, 0) == rxpid); 85262306a36Sopenharmony_ci assert(waitpid(txpid, &tx_status, 0) == txpid); 85362306a36Sopenharmony_ci if (WIFEXITED(rx_status)) { 85462306a36Sopenharmony_ci err = WEXITSTATUS(rx_status); 85562306a36Sopenharmony_ci if (err) { 85662306a36Sopenharmony_ci fprintf(stderr, "rx thread exited with err %d.\n", err); 85762306a36Sopenharmony_ci goto out; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci if (WIFEXITED(tx_status)) { 86162306a36Sopenharmony_ci err = WEXITSTATUS(tx_status); 86262306a36Sopenharmony_ci if (err) 86362306a36Sopenharmony_ci fprintf(stderr, "tx thread exited with err %d.\n", err); 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ciout: 86662306a36Sopenharmony_ci return err; 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_cistatic int forever_ping_pong(int rate, struct sockmap_options *opt) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci struct timeval timeout; 87262306a36Sopenharmony_ci char buf[1024] = {0}; 87362306a36Sopenharmony_ci int sc; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci timeout.tv_sec = 10; 87662306a36Sopenharmony_ci timeout.tv_usec = 0; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* Ping/Pong data from client to server */ 87962306a36Sopenharmony_ci sc = send(c1, buf, sizeof(buf), 0); 88062306a36Sopenharmony_ci if (sc < 0) { 88162306a36Sopenharmony_ci perror("send failed()"); 88262306a36Sopenharmony_ci return sc; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci do { 88662306a36Sopenharmony_ci int s, rc, i, max_fd = p2; 88762306a36Sopenharmony_ci fd_set w; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* FD sets */ 89062306a36Sopenharmony_ci FD_ZERO(&w); 89162306a36Sopenharmony_ci FD_SET(c1, &w); 89262306a36Sopenharmony_ci FD_SET(c2, &w); 89362306a36Sopenharmony_ci FD_SET(p1, &w); 89462306a36Sopenharmony_ci FD_SET(p2, &w); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci s = select(max_fd + 1, &w, NULL, NULL, &timeout); 89762306a36Sopenharmony_ci if (s == -1) { 89862306a36Sopenharmony_ci perror("select()"); 89962306a36Sopenharmony_ci break; 90062306a36Sopenharmony_ci } else if (!s) { 90162306a36Sopenharmony_ci fprintf(stderr, "unexpected timeout\n"); 90262306a36Sopenharmony_ci break; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci for (i = 0; i <= max_fd && s > 0; ++i) { 90662306a36Sopenharmony_ci if (!FD_ISSET(i, &w)) 90762306a36Sopenharmony_ci continue; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci s--; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci rc = recv(i, buf, sizeof(buf), 0); 91262306a36Sopenharmony_ci if (rc < 0) { 91362306a36Sopenharmony_ci if (errno != EWOULDBLOCK) { 91462306a36Sopenharmony_ci perror("recv failed()"); 91562306a36Sopenharmony_ci return rc; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci if (rc == 0) { 92062306a36Sopenharmony_ci close(i); 92162306a36Sopenharmony_ci break; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci sc = send(i, buf, rc, 0); 92562306a36Sopenharmony_ci if (sc < 0) { 92662306a36Sopenharmony_ci perror("send failed()"); 92762306a36Sopenharmony_ci return sc; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (rate) 93262306a36Sopenharmony_ci sleep(rate); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (opt->verbose) { 93562306a36Sopenharmony_ci printf("."); 93662306a36Sopenharmony_ci fflush(stdout); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci } while (running); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci return 0; 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cienum { 94562306a36Sopenharmony_ci SELFTESTS, 94662306a36Sopenharmony_ci PING_PONG, 94762306a36Sopenharmony_ci SENDMSG, 94862306a36Sopenharmony_ci BASE, 94962306a36Sopenharmony_ci BASE_SENDPAGE, 95062306a36Sopenharmony_ci SENDPAGE, 95162306a36Sopenharmony_ci}; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_cistatic int run_options(struct sockmap_options *options, int cg_fd, int test) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci int i, key, next_key, err, tx_prog_fd = -1, zero = 0; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci /* If base test skip BPF setup */ 95862306a36Sopenharmony_ci if (test == BASE || test == BASE_SENDPAGE) 95962306a36Sopenharmony_ci goto run; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci /* Attach programs to sockmap */ 96262306a36Sopenharmony_ci if (!txmsg_omit_skb_parser) { 96362306a36Sopenharmony_ci err = bpf_prog_attach(prog_fd[0], map_fd[0], 96462306a36Sopenharmony_ci BPF_SK_SKB_STREAM_PARSER, 0); 96562306a36Sopenharmony_ci if (err) { 96662306a36Sopenharmony_ci fprintf(stderr, 96762306a36Sopenharmony_ci "ERROR: bpf_prog_attach (sockmap %i->%i): %d (%s)\n", 96862306a36Sopenharmony_ci prog_fd[0], map_fd[0], err, strerror(errno)); 96962306a36Sopenharmony_ci return err; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci err = bpf_prog_attach(prog_fd[1], map_fd[0], 97462306a36Sopenharmony_ci BPF_SK_SKB_STREAM_VERDICT, 0); 97562306a36Sopenharmony_ci if (err) { 97662306a36Sopenharmony_ci fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n", 97762306a36Sopenharmony_ci err, strerror(errno)); 97862306a36Sopenharmony_ci return err; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* Attach programs to TLS sockmap */ 98262306a36Sopenharmony_ci if (txmsg_ktls_skb) { 98362306a36Sopenharmony_ci if (!txmsg_omit_skb_parser) { 98462306a36Sopenharmony_ci err = bpf_prog_attach(prog_fd[0], map_fd[8], 98562306a36Sopenharmony_ci BPF_SK_SKB_STREAM_PARSER, 0); 98662306a36Sopenharmony_ci if (err) { 98762306a36Sopenharmony_ci fprintf(stderr, 98862306a36Sopenharmony_ci "ERROR: bpf_prog_attach (TLS sockmap %i->%i): %d (%s)\n", 98962306a36Sopenharmony_ci prog_fd[0], map_fd[8], err, strerror(errno)); 99062306a36Sopenharmony_ci return err; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci err = bpf_prog_attach(prog_fd[2], map_fd[8], 99562306a36Sopenharmony_ci BPF_SK_SKB_STREAM_VERDICT, 0); 99662306a36Sopenharmony_ci if (err) { 99762306a36Sopenharmony_ci fprintf(stderr, "ERROR: bpf_prog_attach (TLS sockmap): %d (%s)\n", 99862306a36Sopenharmony_ci err, strerror(errno)); 99962306a36Sopenharmony_ci return err; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* Attach to cgroups */ 100462306a36Sopenharmony_ci err = bpf_prog_attach(prog_fd[3], cg_fd, BPF_CGROUP_SOCK_OPS, 0); 100562306a36Sopenharmony_ci if (err) { 100662306a36Sopenharmony_ci fprintf(stderr, "ERROR: bpf_prog_attach (groups): %d (%s)\n", 100762306a36Sopenharmony_ci err, strerror(errno)); 100862306a36Sopenharmony_ci return err; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cirun: 101262306a36Sopenharmony_ci err = sockmap_init_sockets(options->verbose); 101362306a36Sopenharmony_ci if (err) { 101462306a36Sopenharmony_ci fprintf(stderr, "ERROR: test socket failed: %d\n", err); 101562306a36Sopenharmony_ci goto out; 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci /* Attach txmsg program to sockmap */ 101962306a36Sopenharmony_ci if (txmsg_pass) 102062306a36Sopenharmony_ci tx_prog_fd = prog_fd[4]; 102162306a36Sopenharmony_ci else if (txmsg_redir) 102262306a36Sopenharmony_ci tx_prog_fd = prog_fd[5]; 102362306a36Sopenharmony_ci else if (txmsg_apply) 102462306a36Sopenharmony_ci tx_prog_fd = prog_fd[6]; 102562306a36Sopenharmony_ci else if (txmsg_cork) 102662306a36Sopenharmony_ci tx_prog_fd = prog_fd[7]; 102762306a36Sopenharmony_ci else if (txmsg_drop) 102862306a36Sopenharmony_ci tx_prog_fd = prog_fd[8]; 102962306a36Sopenharmony_ci else 103062306a36Sopenharmony_ci tx_prog_fd = 0; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (tx_prog_fd) { 103362306a36Sopenharmony_ci int redir_fd, i = 0; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci err = bpf_prog_attach(tx_prog_fd, 103662306a36Sopenharmony_ci map_fd[1], BPF_SK_MSG_VERDICT, 0); 103762306a36Sopenharmony_ci if (err) { 103862306a36Sopenharmony_ci fprintf(stderr, 103962306a36Sopenharmony_ci "ERROR: bpf_prog_attach (txmsg): %d (%s)\n", 104062306a36Sopenharmony_ci err, strerror(errno)); 104162306a36Sopenharmony_ci goto out; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[1], &i, &c1, BPF_ANY); 104562306a36Sopenharmony_ci if (err) { 104662306a36Sopenharmony_ci fprintf(stderr, 104762306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (txmsg): %d (%s\n", 104862306a36Sopenharmony_ci err, strerror(errno)); 104962306a36Sopenharmony_ci goto out; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (txmsg_redir) 105362306a36Sopenharmony_ci redir_fd = c2; 105462306a36Sopenharmony_ci else 105562306a36Sopenharmony_ci redir_fd = c1; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[2], &i, &redir_fd, BPF_ANY); 105862306a36Sopenharmony_ci if (err) { 105962306a36Sopenharmony_ci fprintf(stderr, 106062306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (txmsg): %d (%s\n", 106162306a36Sopenharmony_ci err, strerror(errno)); 106262306a36Sopenharmony_ci goto out; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (txmsg_apply) { 106662306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[3], 106762306a36Sopenharmony_ci &i, &txmsg_apply, BPF_ANY); 106862306a36Sopenharmony_ci if (err) { 106962306a36Sopenharmony_ci fprintf(stderr, 107062306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (apply_bytes): %d (%s\n", 107162306a36Sopenharmony_ci err, strerror(errno)); 107262306a36Sopenharmony_ci goto out; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if (txmsg_cork) { 107762306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[4], 107862306a36Sopenharmony_ci &i, &txmsg_cork, BPF_ANY); 107962306a36Sopenharmony_ci if (err) { 108062306a36Sopenharmony_ci fprintf(stderr, 108162306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (cork_bytes): %d (%s\n", 108262306a36Sopenharmony_ci err, strerror(errno)); 108362306a36Sopenharmony_ci goto out; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (txmsg_start) { 108862306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[5], 108962306a36Sopenharmony_ci &i, &txmsg_start, BPF_ANY); 109062306a36Sopenharmony_ci if (err) { 109162306a36Sopenharmony_ci fprintf(stderr, 109262306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (txmsg_start): %d (%s)\n", 109362306a36Sopenharmony_ci err, strerror(errno)); 109462306a36Sopenharmony_ci goto out; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (txmsg_end) { 109962306a36Sopenharmony_ci i = 1; 110062306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[5], 110162306a36Sopenharmony_ci &i, &txmsg_end, BPF_ANY); 110262306a36Sopenharmony_ci if (err) { 110362306a36Sopenharmony_ci fprintf(stderr, 110462306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (txmsg_end): %d (%s)\n", 110562306a36Sopenharmony_ci err, strerror(errno)); 110662306a36Sopenharmony_ci goto out; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (txmsg_start_push) { 111162306a36Sopenharmony_ci i = 2; 111262306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[5], 111362306a36Sopenharmony_ci &i, &txmsg_start_push, BPF_ANY); 111462306a36Sopenharmony_ci if (err) { 111562306a36Sopenharmony_ci fprintf(stderr, 111662306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (txmsg_start_push): %d (%s)\n", 111762306a36Sopenharmony_ci err, strerror(errno)); 111862306a36Sopenharmony_ci goto out; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (txmsg_end_push) { 112362306a36Sopenharmony_ci i = 3; 112462306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[5], 112562306a36Sopenharmony_ci &i, &txmsg_end_push, BPF_ANY); 112662306a36Sopenharmony_ci if (err) { 112762306a36Sopenharmony_ci fprintf(stderr, 112862306a36Sopenharmony_ci "ERROR: bpf_map_update_elem %i@%i (txmsg_end_push): %d (%s)\n", 112962306a36Sopenharmony_ci txmsg_end_push, i, err, strerror(errno)); 113062306a36Sopenharmony_ci goto out; 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (txmsg_start_pop) { 113562306a36Sopenharmony_ci i = 4; 113662306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[5], 113762306a36Sopenharmony_ci &i, &txmsg_start_pop, BPF_ANY); 113862306a36Sopenharmony_ci if (err) { 113962306a36Sopenharmony_ci fprintf(stderr, 114062306a36Sopenharmony_ci "ERROR: bpf_map_update_elem %i@%i (txmsg_start_pop): %d (%s)\n", 114162306a36Sopenharmony_ci txmsg_start_pop, i, err, strerror(errno)); 114262306a36Sopenharmony_ci goto out; 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci } else { 114562306a36Sopenharmony_ci i = 4; 114662306a36Sopenharmony_ci bpf_map_update_elem(map_fd[5], 114762306a36Sopenharmony_ci &i, &txmsg_start_pop, BPF_ANY); 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci if (txmsg_pop) { 115162306a36Sopenharmony_ci i = 5; 115262306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[5], 115362306a36Sopenharmony_ci &i, &txmsg_pop, BPF_ANY); 115462306a36Sopenharmony_ci if (err) { 115562306a36Sopenharmony_ci fprintf(stderr, 115662306a36Sopenharmony_ci "ERROR: bpf_map_update_elem %i@%i (txmsg_pop): %d (%s)\n", 115762306a36Sopenharmony_ci txmsg_pop, i, err, strerror(errno)); 115862306a36Sopenharmony_ci goto out; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci } else { 116162306a36Sopenharmony_ci i = 5; 116262306a36Sopenharmony_ci bpf_map_update_elem(map_fd[5], 116362306a36Sopenharmony_ci &i, &txmsg_pop, BPF_ANY); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (txmsg_ingress) { 116862306a36Sopenharmony_ci int in = BPF_F_INGRESS; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci i = 0; 117162306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[6], &i, &in, BPF_ANY); 117262306a36Sopenharmony_ci if (err) { 117362306a36Sopenharmony_ci fprintf(stderr, 117462306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n", 117562306a36Sopenharmony_ci err, strerror(errno)); 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci i = 1; 117862306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[1], &i, &p1, BPF_ANY); 117962306a36Sopenharmony_ci if (err) { 118062306a36Sopenharmony_ci fprintf(stderr, 118162306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (p1 txmsg): %d (%s)\n", 118262306a36Sopenharmony_ci err, strerror(errno)); 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[2], &i, &p1, BPF_ANY); 118562306a36Sopenharmony_ci if (err) { 118662306a36Sopenharmony_ci fprintf(stderr, 118762306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (p1 redir): %d (%s)\n", 118862306a36Sopenharmony_ci err, strerror(errno)); 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci i = 2; 119262306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[2], &i, &p2, BPF_ANY); 119362306a36Sopenharmony_ci if (err) { 119462306a36Sopenharmony_ci fprintf(stderr, 119562306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (p2 txmsg): %d (%s)\n", 119662306a36Sopenharmony_ci err, strerror(errno)); 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci if (txmsg_ktls_skb) { 120162306a36Sopenharmony_ci int ingress = BPF_F_INGRESS; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci i = 0; 120462306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[8], &i, &p2, BPF_ANY); 120562306a36Sopenharmony_ci if (err) { 120662306a36Sopenharmony_ci fprintf(stderr, 120762306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n", 120862306a36Sopenharmony_ci err, strerror(errno)); 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci if (txmsg_ktls_skb_redir) { 121262306a36Sopenharmony_ci i = 1; 121362306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[7], 121462306a36Sopenharmony_ci &i, &ingress, BPF_ANY); 121562306a36Sopenharmony_ci if (err) { 121662306a36Sopenharmony_ci fprintf(stderr, 121762306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n", 121862306a36Sopenharmony_ci err, strerror(errno)); 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci if (txmsg_ktls_skb_drop) { 122362306a36Sopenharmony_ci i = 1; 122462306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[7], &i, &i, BPF_ANY); 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (txmsg_redir_skb) { 122962306a36Sopenharmony_ci int skb_fd = (test == SENDMSG || test == SENDPAGE) ? 123062306a36Sopenharmony_ci p2 : p1; 123162306a36Sopenharmony_ci int ingress = BPF_F_INGRESS; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci i = 0; 123462306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[7], 123562306a36Sopenharmony_ci &i, &ingress, BPF_ANY); 123662306a36Sopenharmony_ci if (err) { 123762306a36Sopenharmony_ci fprintf(stderr, 123862306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n", 123962306a36Sopenharmony_ci err, strerror(errno)); 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci i = 3; 124362306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[0], &i, &skb_fd, BPF_ANY); 124462306a36Sopenharmony_ci if (err) { 124562306a36Sopenharmony_ci fprintf(stderr, 124662306a36Sopenharmony_ci "ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n", 124762306a36Sopenharmony_ci err, strerror(errno)); 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci } 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (skb_use_parser) { 125362306a36Sopenharmony_ci i = 2; 125462306a36Sopenharmony_ci err = bpf_map_update_elem(map_fd[7], &i, &skb_use_parser, BPF_ANY); 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (txmsg_drop) 125862306a36Sopenharmony_ci options->drop_expected = true; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci if (test == PING_PONG) 126162306a36Sopenharmony_ci err = forever_ping_pong(options->rate, options); 126262306a36Sopenharmony_ci else if (test == SENDMSG) { 126362306a36Sopenharmony_ci options->base = false; 126462306a36Sopenharmony_ci options->sendpage = false; 126562306a36Sopenharmony_ci err = sendmsg_test(options); 126662306a36Sopenharmony_ci } else if (test == SENDPAGE) { 126762306a36Sopenharmony_ci options->base = false; 126862306a36Sopenharmony_ci options->sendpage = true; 126962306a36Sopenharmony_ci err = sendmsg_test(options); 127062306a36Sopenharmony_ci } else if (test == BASE) { 127162306a36Sopenharmony_ci options->base = true; 127262306a36Sopenharmony_ci options->sendpage = false; 127362306a36Sopenharmony_ci err = sendmsg_test(options); 127462306a36Sopenharmony_ci } else if (test == BASE_SENDPAGE) { 127562306a36Sopenharmony_ci options->base = true; 127662306a36Sopenharmony_ci options->sendpage = true; 127762306a36Sopenharmony_ci err = sendmsg_test(options); 127862306a36Sopenharmony_ci } else 127962306a36Sopenharmony_ci fprintf(stderr, "unknown test\n"); 128062306a36Sopenharmony_ciout: 128162306a36Sopenharmony_ci /* Detatch and zero all the maps */ 128262306a36Sopenharmony_ci bpf_prog_detach2(prog_fd[3], cg_fd, BPF_CGROUP_SOCK_OPS); 128362306a36Sopenharmony_ci bpf_prog_detach2(prog_fd[0], map_fd[0], BPF_SK_SKB_STREAM_PARSER); 128462306a36Sopenharmony_ci bpf_prog_detach2(prog_fd[1], map_fd[0], BPF_SK_SKB_STREAM_VERDICT); 128562306a36Sopenharmony_ci bpf_prog_detach2(prog_fd[0], map_fd[8], BPF_SK_SKB_STREAM_PARSER); 128662306a36Sopenharmony_ci bpf_prog_detach2(prog_fd[2], map_fd[8], BPF_SK_SKB_STREAM_VERDICT); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (tx_prog_fd >= 0) 128962306a36Sopenharmony_ci bpf_prog_detach2(tx_prog_fd, map_fd[1], BPF_SK_MSG_VERDICT); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 129262306a36Sopenharmony_ci key = next_key = 0; 129362306a36Sopenharmony_ci bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY); 129462306a36Sopenharmony_ci while (bpf_map_get_next_key(map_fd[i], &key, &next_key) == 0) { 129562306a36Sopenharmony_ci bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY); 129662306a36Sopenharmony_ci key = next_key; 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci close(s1); 130162306a36Sopenharmony_ci close(s2); 130262306a36Sopenharmony_ci close(p1); 130362306a36Sopenharmony_ci close(p2); 130462306a36Sopenharmony_ci close(c1); 130562306a36Sopenharmony_ci close(c2); 130662306a36Sopenharmony_ci return err; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic char *test_to_str(int test) 131062306a36Sopenharmony_ci{ 131162306a36Sopenharmony_ci switch (test) { 131262306a36Sopenharmony_ci case SENDMSG: 131362306a36Sopenharmony_ci return "sendmsg"; 131462306a36Sopenharmony_ci case SENDPAGE: 131562306a36Sopenharmony_ci return "sendpage"; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci return "unknown"; 131862306a36Sopenharmony_ci} 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_cistatic void append_str(char *dst, const char *src, size_t dst_cap) 132162306a36Sopenharmony_ci{ 132262306a36Sopenharmony_ci size_t avail = dst_cap - strlen(dst); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci if (avail <= 1) /* just zero byte could be written */ 132562306a36Sopenharmony_ci return; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci strncat(dst, src, avail - 1); /* strncat() adds + 1 for zero byte */ 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci#define OPTSTRING 60 133162306a36Sopenharmony_cistatic void test_options(char *options) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci char tstr[OPTSTRING]; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci memset(options, 0, OPTSTRING); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (txmsg_pass) 133862306a36Sopenharmony_ci append_str(options, "pass,", OPTSTRING); 133962306a36Sopenharmony_ci if (txmsg_redir) 134062306a36Sopenharmony_ci append_str(options, "redir,", OPTSTRING); 134162306a36Sopenharmony_ci if (txmsg_drop) 134262306a36Sopenharmony_ci append_str(options, "drop,", OPTSTRING); 134362306a36Sopenharmony_ci if (txmsg_apply) { 134462306a36Sopenharmony_ci snprintf(tstr, OPTSTRING, "apply %d,", txmsg_apply); 134562306a36Sopenharmony_ci append_str(options, tstr, OPTSTRING); 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci if (txmsg_cork) { 134862306a36Sopenharmony_ci snprintf(tstr, OPTSTRING, "cork %d,", txmsg_cork); 134962306a36Sopenharmony_ci append_str(options, tstr, OPTSTRING); 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci if (txmsg_start) { 135262306a36Sopenharmony_ci snprintf(tstr, OPTSTRING, "start %d,", txmsg_start); 135362306a36Sopenharmony_ci append_str(options, tstr, OPTSTRING); 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci if (txmsg_end) { 135662306a36Sopenharmony_ci snprintf(tstr, OPTSTRING, "end %d,", txmsg_end); 135762306a36Sopenharmony_ci append_str(options, tstr, OPTSTRING); 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci if (txmsg_start_pop) { 136062306a36Sopenharmony_ci snprintf(tstr, OPTSTRING, "pop (%d,%d),", 136162306a36Sopenharmony_ci txmsg_start_pop, txmsg_start_pop + txmsg_pop); 136262306a36Sopenharmony_ci append_str(options, tstr, OPTSTRING); 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci if (txmsg_ingress) 136562306a36Sopenharmony_ci append_str(options, "ingress,", OPTSTRING); 136662306a36Sopenharmony_ci if (txmsg_redir_skb) 136762306a36Sopenharmony_ci append_str(options, "redir_skb,", OPTSTRING); 136862306a36Sopenharmony_ci if (txmsg_ktls_skb) 136962306a36Sopenharmony_ci append_str(options, "ktls_skb,", OPTSTRING); 137062306a36Sopenharmony_ci if (ktls) 137162306a36Sopenharmony_ci append_str(options, "ktls,", OPTSTRING); 137262306a36Sopenharmony_ci if (peek_flag) 137362306a36Sopenharmony_ci append_str(options, "peek,", OPTSTRING); 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cistatic int __test_exec(int cgrp, int test, struct sockmap_options *opt) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci char *options = calloc(OPTSTRING, sizeof(char)); 137962306a36Sopenharmony_ci int err; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci if (test == SENDPAGE) 138262306a36Sopenharmony_ci opt->sendpage = true; 138362306a36Sopenharmony_ci else 138462306a36Sopenharmony_ci opt->sendpage = false; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (txmsg_drop) 138762306a36Sopenharmony_ci opt->drop_expected = true; 138862306a36Sopenharmony_ci else 138962306a36Sopenharmony_ci opt->drop_expected = false; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci test_options(options); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci if (opt->verbose) { 139462306a36Sopenharmony_ci fprintf(stdout, 139562306a36Sopenharmony_ci " [TEST %i]: (%i, %i, %i, %s, %s): ", 139662306a36Sopenharmony_ci test_cnt, opt->rate, opt->iov_count, opt->iov_length, 139762306a36Sopenharmony_ci test_to_str(test), options); 139862306a36Sopenharmony_ci fflush(stdout); 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci err = run_options(opt, cgrp, test); 140162306a36Sopenharmony_ci if (opt->verbose) 140262306a36Sopenharmony_ci fprintf(stdout, " %s\n", !err ? "PASS" : "FAILED"); 140362306a36Sopenharmony_ci test_cnt++; 140462306a36Sopenharmony_ci !err ? passed++ : failed++; 140562306a36Sopenharmony_ci free(options); 140662306a36Sopenharmony_ci return err; 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_cistatic void test_exec(int cgrp, struct sockmap_options *opt) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci int type = strcmp(opt->map, BPF_SOCKMAP_FILENAME); 141262306a36Sopenharmony_ci int err; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (type == 0) { 141562306a36Sopenharmony_ci test_start(); 141662306a36Sopenharmony_ci err = __test_exec(cgrp, SENDMSG, opt); 141762306a36Sopenharmony_ci if (err) 141862306a36Sopenharmony_ci test_fail(); 141962306a36Sopenharmony_ci } else { 142062306a36Sopenharmony_ci test_start(); 142162306a36Sopenharmony_ci err = __test_exec(cgrp, SENDPAGE, opt); 142262306a36Sopenharmony_ci if (err) 142362306a36Sopenharmony_ci test_fail(); 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci} 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_cistatic void test_send_one(struct sockmap_options *opt, int cgrp) 142862306a36Sopenharmony_ci{ 142962306a36Sopenharmony_ci opt->iov_length = 1; 143062306a36Sopenharmony_ci opt->iov_count = 1; 143162306a36Sopenharmony_ci opt->rate = 1; 143262306a36Sopenharmony_ci test_exec(cgrp, opt); 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci opt->iov_length = 1; 143562306a36Sopenharmony_ci opt->iov_count = 1024; 143662306a36Sopenharmony_ci opt->rate = 1; 143762306a36Sopenharmony_ci test_exec(cgrp, opt); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci opt->iov_length = 1024; 144062306a36Sopenharmony_ci opt->iov_count = 1; 144162306a36Sopenharmony_ci opt->rate = 1; 144262306a36Sopenharmony_ci test_exec(cgrp, opt); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci} 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_cistatic void test_send_many(struct sockmap_options *opt, int cgrp) 144762306a36Sopenharmony_ci{ 144862306a36Sopenharmony_ci opt->iov_length = 3; 144962306a36Sopenharmony_ci opt->iov_count = 1; 145062306a36Sopenharmony_ci opt->rate = 512; 145162306a36Sopenharmony_ci test_exec(cgrp, opt); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci opt->rate = 100; 145462306a36Sopenharmony_ci opt->iov_count = 1; 145562306a36Sopenharmony_ci opt->iov_length = 5; 145662306a36Sopenharmony_ci test_exec(cgrp, opt); 145762306a36Sopenharmony_ci} 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_cistatic void test_send_large(struct sockmap_options *opt, int cgrp) 146062306a36Sopenharmony_ci{ 146162306a36Sopenharmony_ci opt->iov_length = 256; 146262306a36Sopenharmony_ci opt->iov_count = 1024; 146362306a36Sopenharmony_ci opt->rate = 2; 146462306a36Sopenharmony_ci test_exec(cgrp, opt); 146562306a36Sopenharmony_ci} 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_cistatic void test_send(struct sockmap_options *opt, int cgrp) 146862306a36Sopenharmony_ci{ 146962306a36Sopenharmony_ci test_send_one(opt, cgrp); 147062306a36Sopenharmony_ci test_send_many(opt, cgrp); 147162306a36Sopenharmony_ci test_send_large(opt, cgrp); 147262306a36Sopenharmony_ci sched_yield(); 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_cistatic void test_txmsg_pass(int cgrp, struct sockmap_options *opt) 147662306a36Sopenharmony_ci{ 147762306a36Sopenharmony_ci /* Test small and large iov_count values with pass/redir/apply/cork */ 147862306a36Sopenharmony_ci txmsg_pass = 1; 147962306a36Sopenharmony_ci test_send(opt, cgrp); 148062306a36Sopenharmony_ci} 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_cistatic void test_txmsg_redir(int cgrp, struct sockmap_options *opt) 148362306a36Sopenharmony_ci{ 148462306a36Sopenharmony_ci txmsg_redir = 1; 148562306a36Sopenharmony_ci test_send(opt, cgrp); 148662306a36Sopenharmony_ci} 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_cistatic void test_txmsg_redir_wait_sndmem(int cgrp, struct sockmap_options *opt) 148962306a36Sopenharmony_ci{ 149062306a36Sopenharmony_ci txmsg_redir = 1; 149162306a36Sopenharmony_ci opt->tx_wait_mem = true; 149262306a36Sopenharmony_ci test_send_large(opt, cgrp); 149362306a36Sopenharmony_ci opt->tx_wait_mem = false; 149462306a36Sopenharmony_ci} 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_cistatic void test_txmsg_drop(int cgrp, struct sockmap_options *opt) 149762306a36Sopenharmony_ci{ 149862306a36Sopenharmony_ci txmsg_drop = 1; 149962306a36Sopenharmony_ci test_send(opt, cgrp); 150062306a36Sopenharmony_ci} 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_cistatic void test_txmsg_ingress_redir(int cgrp, struct sockmap_options *opt) 150362306a36Sopenharmony_ci{ 150462306a36Sopenharmony_ci txmsg_pass = txmsg_drop = 0; 150562306a36Sopenharmony_ci txmsg_ingress = txmsg_redir = 1; 150662306a36Sopenharmony_ci test_send(opt, cgrp); 150762306a36Sopenharmony_ci} 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_cistatic void test_txmsg_skb(int cgrp, struct sockmap_options *opt) 151062306a36Sopenharmony_ci{ 151162306a36Sopenharmony_ci bool data = opt->data_test; 151262306a36Sopenharmony_ci int k = ktls; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci opt->data_test = true; 151562306a36Sopenharmony_ci ktls = 1; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci txmsg_pass = txmsg_drop = 0; 151862306a36Sopenharmony_ci txmsg_ingress = txmsg_redir = 0; 151962306a36Sopenharmony_ci txmsg_ktls_skb = 1; 152062306a36Sopenharmony_ci txmsg_pass = 1; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci /* Using data verification so ensure iov layout is 152362306a36Sopenharmony_ci * expected from test receiver side. e.g. has enough 152462306a36Sopenharmony_ci * bytes to write test code. 152562306a36Sopenharmony_ci */ 152662306a36Sopenharmony_ci opt->iov_length = 100; 152762306a36Sopenharmony_ci opt->iov_count = 1; 152862306a36Sopenharmony_ci opt->rate = 1; 152962306a36Sopenharmony_ci test_exec(cgrp, opt); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci txmsg_ktls_skb_drop = 1; 153262306a36Sopenharmony_ci test_exec(cgrp, opt); 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci txmsg_ktls_skb_drop = 0; 153562306a36Sopenharmony_ci txmsg_ktls_skb_redir = 1; 153662306a36Sopenharmony_ci test_exec(cgrp, opt); 153762306a36Sopenharmony_ci txmsg_ktls_skb_redir = 0; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci /* Tests that omit skb_parser */ 154062306a36Sopenharmony_ci txmsg_omit_skb_parser = 1; 154162306a36Sopenharmony_ci ktls = 0; 154262306a36Sopenharmony_ci txmsg_ktls_skb = 0; 154362306a36Sopenharmony_ci test_exec(cgrp, opt); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci txmsg_ktls_skb_drop = 1; 154662306a36Sopenharmony_ci test_exec(cgrp, opt); 154762306a36Sopenharmony_ci txmsg_ktls_skb_drop = 0; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci txmsg_ktls_skb_redir = 1; 155062306a36Sopenharmony_ci test_exec(cgrp, opt); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci ktls = 1; 155362306a36Sopenharmony_ci test_exec(cgrp, opt); 155462306a36Sopenharmony_ci txmsg_omit_skb_parser = 0; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci opt->data_test = data; 155762306a36Sopenharmony_ci ktls = k; 155862306a36Sopenharmony_ci} 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci/* Test cork with hung data. This tests poor usage patterns where 156162306a36Sopenharmony_ci * cork can leave data on the ring if user program is buggy and 156262306a36Sopenharmony_ci * doesn't flush them somehow. They do take some time however 156362306a36Sopenharmony_ci * because they wait for a timeout. Test pass, redir and cork with 156462306a36Sopenharmony_ci * apply logic. Use cork size of 4097 with send_large to avoid 156562306a36Sopenharmony_ci * aligning cork size with send size. 156662306a36Sopenharmony_ci */ 156762306a36Sopenharmony_cistatic void test_txmsg_cork_hangs(int cgrp, struct sockmap_options *opt) 156862306a36Sopenharmony_ci{ 156962306a36Sopenharmony_ci txmsg_pass = 1; 157062306a36Sopenharmony_ci txmsg_redir = 0; 157162306a36Sopenharmony_ci txmsg_cork = 4097; 157262306a36Sopenharmony_ci txmsg_apply = 4097; 157362306a36Sopenharmony_ci test_send_large(opt, cgrp); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci txmsg_pass = 0; 157662306a36Sopenharmony_ci txmsg_redir = 1; 157762306a36Sopenharmony_ci txmsg_apply = 0; 157862306a36Sopenharmony_ci txmsg_cork = 4097; 157962306a36Sopenharmony_ci test_send_large(opt, cgrp); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci txmsg_pass = 0; 158262306a36Sopenharmony_ci txmsg_redir = 1; 158362306a36Sopenharmony_ci txmsg_apply = 4097; 158462306a36Sopenharmony_ci txmsg_cork = 4097; 158562306a36Sopenharmony_ci test_send_large(opt, cgrp); 158662306a36Sopenharmony_ci} 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_cistatic void test_txmsg_pull(int cgrp, struct sockmap_options *opt) 158962306a36Sopenharmony_ci{ 159062306a36Sopenharmony_ci /* Test basic start/end */ 159162306a36Sopenharmony_ci txmsg_start = 1; 159262306a36Sopenharmony_ci txmsg_end = 2; 159362306a36Sopenharmony_ci test_send(opt, cgrp); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci /* Test >4k pull */ 159662306a36Sopenharmony_ci txmsg_start = 4096; 159762306a36Sopenharmony_ci txmsg_end = 9182; 159862306a36Sopenharmony_ci test_send_large(opt, cgrp); 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci /* Test pull + redirect */ 160162306a36Sopenharmony_ci txmsg_redir = 0; 160262306a36Sopenharmony_ci txmsg_start = 1; 160362306a36Sopenharmony_ci txmsg_end = 2; 160462306a36Sopenharmony_ci test_send(opt, cgrp); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci /* Test pull + cork */ 160762306a36Sopenharmony_ci txmsg_redir = 0; 160862306a36Sopenharmony_ci txmsg_cork = 512; 160962306a36Sopenharmony_ci txmsg_start = 1; 161062306a36Sopenharmony_ci txmsg_end = 2; 161162306a36Sopenharmony_ci test_send_many(opt, cgrp); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci /* Test pull + cork + redirect */ 161462306a36Sopenharmony_ci txmsg_redir = 1; 161562306a36Sopenharmony_ci txmsg_cork = 512; 161662306a36Sopenharmony_ci txmsg_start = 1; 161762306a36Sopenharmony_ci txmsg_end = 2; 161862306a36Sopenharmony_ci test_send_many(opt, cgrp); 161962306a36Sopenharmony_ci} 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_cistatic void test_txmsg_pop(int cgrp, struct sockmap_options *opt) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci /* Test basic pop */ 162462306a36Sopenharmony_ci txmsg_start_pop = 1; 162562306a36Sopenharmony_ci txmsg_pop = 2; 162662306a36Sopenharmony_ci test_send_many(opt, cgrp); 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci /* Test pop with >4k */ 162962306a36Sopenharmony_ci txmsg_start_pop = 4096; 163062306a36Sopenharmony_ci txmsg_pop = 4096; 163162306a36Sopenharmony_ci test_send_large(opt, cgrp); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci /* Test pop + redirect */ 163462306a36Sopenharmony_ci txmsg_redir = 1; 163562306a36Sopenharmony_ci txmsg_start_pop = 1; 163662306a36Sopenharmony_ci txmsg_pop = 2; 163762306a36Sopenharmony_ci test_send_many(opt, cgrp); 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci /* Test pop + cork */ 164062306a36Sopenharmony_ci txmsg_redir = 0; 164162306a36Sopenharmony_ci txmsg_cork = 512; 164262306a36Sopenharmony_ci txmsg_start_pop = 1; 164362306a36Sopenharmony_ci txmsg_pop = 2; 164462306a36Sopenharmony_ci test_send_many(opt, cgrp); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci /* Test pop + redirect + cork */ 164762306a36Sopenharmony_ci txmsg_redir = 1; 164862306a36Sopenharmony_ci txmsg_cork = 4; 164962306a36Sopenharmony_ci txmsg_start_pop = 1; 165062306a36Sopenharmony_ci txmsg_pop = 2; 165162306a36Sopenharmony_ci test_send_many(opt, cgrp); 165262306a36Sopenharmony_ci} 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_cistatic void test_txmsg_push(int cgrp, struct sockmap_options *opt) 165562306a36Sopenharmony_ci{ 165662306a36Sopenharmony_ci /* Test basic push */ 165762306a36Sopenharmony_ci txmsg_start_push = 1; 165862306a36Sopenharmony_ci txmsg_end_push = 1; 165962306a36Sopenharmony_ci test_send(opt, cgrp); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci /* Test push 4kB >4k */ 166262306a36Sopenharmony_ci txmsg_start_push = 4096; 166362306a36Sopenharmony_ci txmsg_end_push = 4096; 166462306a36Sopenharmony_ci test_send_large(opt, cgrp); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci /* Test push + redirect */ 166762306a36Sopenharmony_ci txmsg_redir = 1; 166862306a36Sopenharmony_ci txmsg_start_push = 1; 166962306a36Sopenharmony_ci txmsg_end_push = 2; 167062306a36Sopenharmony_ci test_send_many(opt, cgrp); 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci /* Test push + cork */ 167362306a36Sopenharmony_ci txmsg_redir = 0; 167462306a36Sopenharmony_ci txmsg_cork = 512; 167562306a36Sopenharmony_ci txmsg_start_push = 1; 167662306a36Sopenharmony_ci txmsg_end_push = 2; 167762306a36Sopenharmony_ci test_send_many(opt, cgrp); 167862306a36Sopenharmony_ci} 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_cistatic void test_txmsg_push_pop(int cgrp, struct sockmap_options *opt) 168162306a36Sopenharmony_ci{ 168262306a36Sopenharmony_ci txmsg_start_push = 1; 168362306a36Sopenharmony_ci txmsg_end_push = 10; 168462306a36Sopenharmony_ci txmsg_start_pop = 5; 168562306a36Sopenharmony_ci txmsg_pop = 4; 168662306a36Sopenharmony_ci test_send_large(opt, cgrp); 168762306a36Sopenharmony_ci} 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_cistatic void test_txmsg_apply(int cgrp, struct sockmap_options *opt) 169062306a36Sopenharmony_ci{ 169162306a36Sopenharmony_ci txmsg_pass = 1; 169262306a36Sopenharmony_ci txmsg_redir = 0; 169362306a36Sopenharmony_ci txmsg_ingress = 0; 169462306a36Sopenharmony_ci txmsg_apply = 1; 169562306a36Sopenharmony_ci txmsg_cork = 0; 169662306a36Sopenharmony_ci test_send_one(opt, cgrp); 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci txmsg_pass = 0; 169962306a36Sopenharmony_ci txmsg_redir = 1; 170062306a36Sopenharmony_ci txmsg_ingress = 0; 170162306a36Sopenharmony_ci txmsg_apply = 1; 170262306a36Sopenharmony_ci txmsg_cork = 0; 170362306a36Sopenharmony_ci test_send_one(opt, cgrp); 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci txmsg_pass = 0; 170662306a36Sopenharmony_ci txmsg_redir = 1; 170762306a36Sopenharmony_ci txmsg_ingress = 1; 170862306a36Sopenharmony_ci txmsg_apply = 1; 170962306a36Sopenharmony_ci txmsg_cork = 0; 171062306a36Sopenharmony_ci test_send_one(opt, cgrp); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci txmsg_pass = 1; 171362306a36Sopenharmony_ci txmsg_redir = 0; 171462306a36Sopenharmony_ci txmsg_ingress = 0; 171562306a36Sopenharmony_ci txmsg_apply = 1024; 171662306a36Sopenharmony_ci txmsg_cork = 0; 171762306a36Sopenharmony_ci test_send_large(opt, cgrp); 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci txmsg_pass = 0; 172062306a36Sopenharmony_ci txmsg_redir = 1; 172162306a36Sopenharmony_ci txmsg_ingress = 0; 172262306a36Sopenharmony_ci txmsg_apply = 1024; 172362306a36Sopenharmony_ci txmsg_cork = 0; 172462306a36Sopenharmony_ci test_send_large(opt, cgrp); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci txmsg_pass = 0; 172762306a36Sopenharmony_ci txmsg_redir = 1; 172862306a36Sopenharmony_ci txmsg_ingress = 1; 172962306a36Sopenharmony_ci txmsg_apply = 1024; 173062306a36Sopenharmony_ci txmsg_cork = 0; 173162306a36Sopenharmony_ci test_send_large(opt, cgrp); 173262306a36Sopenharmony_ci} 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_cistatic void test_txmsg_cork(int cgrp, struct sockmap_options *opt) 173562306a36Sopenharmony_ci{ 173662306a36Sopenharmony_ci txmsg_pass = 1; 173762306a36Sopenharmony_ci txmsg_redir = 0; 173862306a36Sopenharmony_ci txmsg_apply = 0; 173962306a36Sopenharmony_ci txmsg_cork = 1; 174062306a36Sopenharmony_ci test_send(opt, cgrp); 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci txmsg_pass = 1; 174362306a36Sopenharmony_ci txmsg_redir = 0; 174462306a36Sopenharmony_ci txmsg_apply = 1; 174562306a36Sopenharmony_ci txmsg_cork = 1; 174662306a36Sopenharmony_ci test_send(opt, cgrp); 174762306a36Sopenharmony_ci} 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_cistatic void test_txmsg_ingress_parser(int cgrp, struct sockmap_options *opt) 175062306a36Sopenharmony_ci{ 175162306a36Sopenharmony_ci txmsg_pass = 1; 175262306a36Sopenharmony_ci skb_use_parser = 512; 175362306a36Sopenharmony_ci if (ktls == 1) 175462306a36Sopenharmony_ci skb_use_parser = 570; 175562306a36Sopenharmony_ci opt->iov_length = 256; 175662306a36Sopenharmony_ci opt->iov_count = 1; 175762306a36Sopenharmony_ci opt->rate = 2; 175862306a36Sopenharmony_ci test_exec(cgrp, opt); 175962306a36Sopenharmony_ci} 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_cistatic void test_txmsg_ingress_parser2(int cgrp, struct sockmap_options *opt) 176262306a36Sopenharmony_ci{ 176362306a36Sopenharmony_ci if (ktls == 1) 176462306a36Sopenharmony_ci return; 176562306a36Sopenharmony_ci skb_use_parser = 10; 176662306a36Sopenharmony_ci opt->iov_length = 20; 176762306a36Sopenharmony_ci opt->iov_count = 1; 176862306a36Sopenharmony_ci opt->rate = 1; 176962306a36Sopenharmony_ci opt->check_recved_len = true; 177062306a36Sopenharmony_ci test_exec(cgrp, opt); 177162306a36Sopenharmony_ci opt->check_recved_len = false; 177262306a36Sopenharmony_ci} 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_cichar *map_names[] = { 177562306a36Sopenharmony_ci "sock_map", 177662306a36Sopenharmony_ci "sock_map_txmsg", 177762306a36Sopenharmony_ci "sock_map_redir", 177862306a36Sopenharmony_ci "sock_apply_bytes", 177962306a36Sopenharmony_ci "sock_cork_bytes", 178062306a36Sopenharmony_ci "sock_bytes", 178162306a36Sopenharmony_ci "sock_redir_flags", 178262306a36Sopenharmony_ci "sock_skb_opts", 178362306a36Sopenharmony_ci "tls_sock_map", 178462306a36Sopenharmony_ci}; 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ciint prog_attach_type[] = { 178762306a36Sopenharmony_ci BPF_SK_SKB_STREAM_PARSER, 178862306a36Sopenharmony_ci BPF_SK_SKB_STREAM_VERDICT, 178962306a36Sopenharmony_ci BPF_SK_SKB_STREAM_VERDICT, 179062306a36Sopenharmony_ci BPF_CGROUP_SOCK_OPS, 179162306a36Sopenharmony_ci BPF_SK_MSG_VERDICT, 179262306a36Sopenharmony_ci BPF_SK_MSG_VERDICT, 179362306a36Sopenharmony_ci BPF_SK_MSG_VERDICT, 179462306a36Sopenharmony_ci BPF_SK_MSG_VERDICT, 179562306a36Sopenharmony_ci BPF_SK_MSG_VERDICT, 179662306a36Sopenharmony_ci BPF_SK_MSG_VERDICT, 179762306a36Sopenharmony_ci BPF_SK_MSG_VERDICT, 179862306a36Sopenharmony_ci}; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ciint prog_type[] = { 180162306a36Sopenharmony_ci BPF_PROG_TYPE_SK_SKB, 180262306a36Sopenharmony_ci BPF_PROG_TYPE_SK_SKB, 180362306a36Sopenharmony_ci BPF_PROG_TYPE_SK_SKB, 180462306a36Sopenharmony_ci BPF_PROG_TYPE_SOCK_OPS, 180562306a36Sopenharmony_ci BPF_PROG_TYPE_SK_MSG, 180662306a36Sopenharmony_ci BPF_PROG_TYPE_SK_MSG, 180762306a36Sopenharmony_ci BPF_PROG_TYPE_SK_MSG, 180862306a36Sopenharmony_ci BPF_PROG_TYPE_SK_MSG, 180962306a36Sopenharmony_ci BPF_PROG_TYPE_SK_MSG, 181062306a36Sopenharmony_ci BPF_PROG_TYPE_SK_MSG, 181162306a36Sopenharmony_ci BPF_PROG_TYPE_SK_MSG, 181262306a36Sopenharmony_ci}; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_cistatic int populate_progs(char *bpf_file) 181562306a36Sopenharmony_ci{ 181662306a36Sopenharmony_ci struct bpf_program *prog; 181762306a36Sopenharmony_ci struct bpf_object *obj; 181862306a36Sopenharmony_ci int i = 0; 181962306a36Sopenharmony_ci long err; 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci obj = bpf_object__open(bpf_file); 182262306a36Sopenharmony_ci err = libbpf_get_error(obj); 182362306a36Sopenharmony_ci if (err) { 182462306a36Sopenharmony_ci char err_buf[256]; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci libbpf_strerror(err, err_buf, sizeof(err_buf)); 182762306a36Sopenharmony_ci printf("Unable to load eBPF objects in file '%s' : %s\n", 182862306a36Sopenharmony_ci bpf_file, err_buf); 182962306a36Sopenharmony_ci return -1; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci bpf_object__for_each_program(prog, obj) { 183362306a36Sopenharmony_ci bpf_program__set_type(prog, prog_type[i]); 183462306a36Sopenharmony_ci bpf_program__set_expected_attach_type(prog, 183562306a36Sopenharmony_ci prog_attach_type[i]); 183662306a36Sopenharmony_ci i++; 183762306a36Sopenharmony_ci } 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci i = bpf_object__load(obj); 184062306a36Sopenharmony_ci i = 0; 184162306a36Sopenharmony_ci bpf_object__for_each_program(prog, obj) { 184262306a36Sopenharmony_ci prog_fd[i] = bpf_program__fd(prog); 184362306a36Sopenharmony_ci i++; 184462306a36Sopenharmony_ci } 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(map_fd); i++) { 184762306a36Sopenharmony_ci maps[i] = bpf_object__find_map_by_name(obj, map_names[i]); 184862306a36Sopenharmony_ci map_fd[i] = bpf_map__fd(maps[i]); 184962306a36Sopenharmony_ci if (map_fd[i] < 0) { 185062306a36Sopenharmony_ci fprintf(stderr, "load_bpf_file: (%i) %s\n", 185162306a36Sopenharmony_ci map_fd[i], strerror(errno)); 185262306a36Sopenharmony_ci return -1; 185362306a36Sopenharmony_ci } 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci return 0; 185762306a36Sopenharmony_ci} 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_cistruct _test test[] = { 186062306a36Sopenharmony_ci {"txmsg test passthrough", test_txmsg_pass}, 186162306a36Sopenharmony_ci {"txmsg test redirect", test_txmsg_redir}, 186262306a36Sopenharmony_ci {"txmsg test redirect wait send mem", test_txmsg_redir_wait_sndmem}, 186362306a36Sopenharmony_ci {"txmsg test drop", test_txmsg_drop}, 186462306a36Sopenharmony_ci {"txmsg test ingress redirect", test_txmsg_ingress_redir}, 186562306a36Sopenharmony_ci {"txmsg test skb", test_txmsg_skb}, 186662306a36Sopenharmony_ci {"txmsg test apply", test_txmsg_apply}, 186762306a36Sopenharmony_ci {"txmsg test cork", test_txmsg_cork}, 186862306a36Sopenharmony_ci {"txmsg test hanging corks", test_txmsg_cork_hangs}, 186962306a36Sopenharmony_ci {"txmsg test push_data", test_txmsg_push}, 187062306a36Sopenharmony_ci {"txmsg test pull-data", test_txmsg_pull}, 187162306a36Sopenharmony_ci {"txmsg test pop-data", test_txmsg_pop}, 187262306a36Sopenharmony_ci {"txmsg test push/pop data", test_txmsg_push_pop}, 187362306a36Sopenharmony_ci {"txmsg test ingress parser", test_txmsg_ingress_parser}, 187462306a36Sopenharmony_ci {"txmsg test ingress parser2", test_txmsg_ingress_parser2}, 187562306a36Sopenharmony_ci}; 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_cistatic int check_whitelist(struct _test *t, struct sockmap_options *opt) 187862306a36Sopenharmony_ci{ 187962306a36Sopenharmony_ci char *entry, *ptr; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci if (!opt->whitelist) 188262306a36Sopenharmony_ci return 0; 188362306a36Sopenharmony_ci ptr = strdup(opt->whitelist); 188462306a36Sopenharmony_ci if (!ptr) 188562306a36Sopenharmony_ci return -ENOMEM; 188662306a36Sopenharmony_ci entry = strtok(ptr, ","); 188762306a36Sopenharmony_ci while (entry) { 188862306a36Sopenharmony_ci if ((opt->prepend && strstr(opt->prepend, entry) != 0) || 188962306a36Sopenharmony_ci strstr(opt->map, entry) != 0 || 189062306a36Sopenharmony_ci strstr(t->title, entry) != 0) 189162306a36Sopenharmony_ci return 0; 189262306a36Sopenharmony_ci entry = strtok(NULL, ","); 189362306a36Sopenharmony_ci } 189462306a36Sopenharmony_ci return -EINVAL; 189562306a36Sopenharmony_ci} 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_cistatic int check_blacklist(struct _test *t, struct sockmap_options *opt) 189862306a36Sopenharmony_ci{ 189962306a36Sopenharmony_ci char *entry, *ptr; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci if (!opt->blacklist) 190262306a36Sopenharmony_ci return -EINVAL; 190362306a36Sopenharmony_ci ptr = strdup(opt->blacklist); 190462306a36Sopenharmony_ci if (!ptr) 190562306a36Sopenharmony_ci return -ENOMEM; 190662306a36Sopenharmony_ci entry = strtok(ptr, ","); 190762306a36Sopenharmony_ci while (entry) { 190862306a36Sopenharmony_ci if ((opt->prepend && strstr(opt->prepend, entry) != 0) || 190962306a36Sopenharmony_ci strstr(opt->map, entry) != 0 || 191062306a36Sopenharmony_ci strstr(t->title, entry) != 0) 191162306a36Sopenharmony_ci return 0; 191262306a36Sopenharmony_ci entry = strtok(NULL, ","); 191362306a36Sopenharmony_ci } 191462306a36Sopenharmony_ci return -EINVAL; 191562306a36Sopenharmony_ci} 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_cistatic int __test_selftests(int cg_fd, struct sockmap_options *opt) 191862306a36Sopenharmony_ci{ 191962306a36Sopenharmony_ci int i, err; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci err = populate_progs(opt->map); 192262306a36Sopenharmony_ci if (err < 0) { 192362306a36Sopenharmony_ci fprintf(stderr, "ERROR: (%i) load bpf failed\n", err); 192462306a36Sopenharmony_ci return err; 192562306a36Sopenharmony_ci } 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci /* Tests basic commands and APIs */ 192862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(test); i++) { 192962306a36Sopenharmony_ci struct _test t = test[i]; 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci if (check_whitelist(&t, opt) != 0) 193262306a36Sopenharmony_ci continue; 193362306a36Sopenharmony_ci if (check_blacklist(&t, opt) == 0) 193462306a36Sopenharmony_ci continue; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci test_start_subtest(&t, opt); 193762306a36Sopenharmony_ci t.tester(cg_fd, opt); 193862306a36Sopenharmony_ci test_end_subtest(); 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci return err; 194262306a36Sopenharmony_ci} 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_cistatic void test_selftests_sockmap(int cg_fd, struct sockmap_options *opt) 194562306a36Sopenharmony_ci{ 194662306a36Sopenharmony_ci opt->map = BPF_SOCKMAP_FILENAME; 194762306a36Sopenharmony_ci __test_selftests(cg_fd, opt); 194862306a36Sopenharmony_ci} 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_cistatic void test_selftests_sockhash(int cg_fd, struct sockmap_options *opt) 195162306a36Sopenharmony_ci{ 195262306a36Sopenharmony_ci opt->map = BPF_SOCKHASH_FILENAME; 195362306a36Sopenharmony_ci __test_selftests(cg_fd, opt); 195462306a36Sopenharmony_ci} 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_cistatic void test_selftests_ktls(int cg_fd, struct sockmap_options *opt) 195762306a36Sopenharmony_ci{ 195862306a36Sopenharmony_ci opt->map = BPF_SOCKHASH_FILENAME; 195962306a36Sopenharmony_ci opt->prepend = "ktls"; 196062306a36Sopenharmony_ci ktls = 1; 196162306a36Sopenharmony_ci __test_selftests(cg_fd, opt); 196262306a36Sopenharmony_ci ktls = 0; 196362306a36Sopenharmony_ci} 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_cistatic int test_selftest(int cg_fd, struct sockmap_options *opt) 196662306a36Sopenharmony_ci{ 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci test_selftests_sockmap(cg_fd, opt); 196962306a36Sopenharmony_ci test_selftests_sockhash(cg_fd, opt); 197062306a36Sopenharmony_ci test_selftests_ktls(cg_fd, opt); 197162306a36Sopenharmony_ci test_print_results(); 197262306a36Sopenharmony_ci return 0; 197362306a36Sopenharmony_ci} 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ciint main(int argc, char **argv) 197662306a36Sopenharmony_ci{ 197762306a36Sopenharmony_ci int iov_count = 1, length = 1024, rate = 1; 197862306a36Sopenharmony_ci struct sockmap_options options = {0}; 197962306a36Sopenharmony_ci int opt, longindex, err, cg_fd = 0; 198062306a36Sopenharmony_ci char *bpf_file = BPF_SOCKMAP_FILENAME; 198162306a36Sopenharmony_ci int test = SELFTESTS; 198262306a36Sopenharmony_ci bool cg_created = 0; 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci while ((opt = getopt_long(argc, argv, ":dhv:c:r:i:l:t:p:q:n:b:", 198562306a36Sopenharmony_ci long_options, &longindex)) != -1) { 198662306a36Sopenharmony_ci switch (opt) { 198762306a36Sopenharmony_ci case 's': 198862306a36Sopenharmony_ci txmsg_start = atoi(optarg); 198962306a36Sopenharmony_ci break; 199062306a36Sopenharmony_ci case 'e': 199162306a36Sopenharmony_ci txmsg_end = atoi(optarg); 199262306a36Sopenharmony_ci break; 199362306a36Sopenharmony_ci case 'p': 199462306a36Sopenharmony_ci txmsg_start_push = atoi(optarg); 199562306a36Sopenharmony_ci break; 199662306a36Sopenharmony_ci case 'q': 199762306a36Sopenharmony_ci txmsg_end_push = atoi(optarg); 199862306a36Sopenharmony_ci break; 199962306a36Sopenharmony_ci case 'w': 200062306a36Sopenharmony_ci txmsg_start_pop = atoi(optarg); 200162306a36Sopenharmony_ci break; 200262306a36Sopenharmony_ci case 'x': 200362306a36Sopenharmony_ci txmsg_pop = atoi(optarg); 200462306a36Sopenharmony_ci break; 200562306a36Sopenharmony_ci case 'a': 200662306a36Sopenharmony_ci txmsg_apply = atoi(optarg); 200762306a36Sopenharmony_ci break; 200862306a36Sopenharmony_ci case 'k': 200962306a36Sopenharmony_ci txmsg_cork = atoi(optarg); 201062306a36Sopenharmony_ci break; 201162306a36Sopenharmony_ci case 'c': 201262306a36Sopenharmony_ci cg_fd = open(optarg, O_DIRECTORY, O_RDONLY); 201362306a36Sopenharmony_ci if (cg_fd < 0) { 201462306a36Sopenharmony_ci fprintf(stderr, 201562306a36Sopenharmony_ci "ERROR: (%i) open cg path failed: %s\n", 201662306a36Sopenharmony_ci cg_fd, optarg); 201762306a36Sopenharmony_ci return cg_fd; 201862306a36Sopenharmony_ci } 201962306a36Sopenharmony_ci break; 202062306a36Sopenharmony_ci case 'r': 202162306a36Sopenharmony_ci rate = atoi(optarg); 202262306a36Sopenharmony_ci break; 202362306a36Sopenharmony_ci case 'v': 202462306a36Sopenharmony_ci options.verbose = 1; 202562306a36Sopenharmony_ci if (optarg) 202662306a36Sopenharmony_ci options.verbose = atoi(optarg); 202762306a36Sopenharmony_ci break; 202862306a36Sopenharmony_ci case 'i': 202962306a36Sopenharmony_ci iov_count = atoi(optarg); 203062306a36Sopenharmony_ci break; 203162306a36Sopenharmony_ci case 'l': 203262306a36Sopenharmony_ci length = atoi(optarg); 203362306a36Sopenharmony_ci break; 203462306a36Sopenharmony_ci case 'd': 203562306a36Sopenharmony_ci options.data_test = true; 203662306a36Sopenharmony_ci break; 203762306a36Sopenharmony_ci case 't': 203862306a36Sopenharmony_ci if (strcmp(optarg, "ping") == 0) { 203962306a36Sopenharmony_ci test = PING_PONG; 204062306a36Sopenharmony_ci } else if (strcmp(optarg, "sendmsg") == 0) { 204162306a36Sopenharmony_ci test = SENDMSG; 204262306a36Sopenharmony_ci } else if (strcmp(optarg, "base") == 0) { 204362306a36Sopenharmony_ci test = BASE; 204462306a36Sopenharmony_ci } else if (strcmp(optarg, "base_sendpage") == 0) { 204562306a36Sopenharmony_ci test = BASE_SENDPAGE; 204662306a36Sopenharmony_ci } else if (strcmp(optarg, "sendpage") == 0) { 204762306a36Sopenharmony_ci test = SENDPAGE; 204862306a36Sopenharmony_ci } else { 204962306a36Sopenharmony_ci usage(argv); 205062306a36Sopenharmony_ci return -1; 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci break; 205362306a36Sopenharmony_ci case 'n': 205462306a36Sopenharmony_ci options.whitelist = strdup(optarg); 205562306a36Sopenharmony_ci if (!options.whitelist) 205662306a36Sopenharmony_ci return -ENOMEM; 205762306a36Sopenharmony_ci break; 205862306a36Sopenharmony_ci case 'b': 205962306a36Sopenharmony_ci options.blacklist = strdup(optarg); 206062306a36Sopenharmony_ci if (!options.blacklist) 206162306a36Sopenharmony_ci return -ENOMEM; 206262306a36Sopenharmony_ci case 0: 206362306a36Sopenharmony_ci break; 206462306a36Sopenharmony_ci case 'h': 206562306a36Sopenharmony_ci default: 206662306a36Sopenharmony_ci usage(argv); 206762306a36Sopenharmony_ci return -1; 206862306a36Sopenharmony_ci } 206962306a36Sopenharmony_ci } 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci if (!cg_fd) { 207262306a36Sopenharmony_ci cg_fd = cgroup_setup_and_join(CG_PATH); 207362306a36Sopenharmony_ci if (cg_fd < 0) 207462306a36Sopenharmony_ci return cg_fd; 207562306a36Sopenharmony_ci cg_created = 1; 207662306a36Sopenharmony_ci } 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci /* Use libbpf 1.0 API mode */ 207962306a36Sopenharmony_ci libbpf_set_strict_mode(LIBBPF_STRICT_ALL); 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci if (test == SELFTESTS) { 208262306a36Sopenharmony_ci err = test_selftest(cg_fd, &options); 208362306a36Sopenharmony_ci goto out; 208462306a36Sopenharmony_ci } 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci err = populate_progs(bpf_file); 208762306a36Sopenharmony_ci if (err) { 208862306a36Sopenharmony_ci fprintf(stderr, "populate program: (%s) %s\n", 208962306a36Sopenharmony_ci bpf_file, strerror(errno)); 209062306a36Sopenharmony_ci return 1; 209162306a36Sopenharmony_ci } 209262306a36Sopenharmony_ci running = 1; 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci /* catch SIGINT */ 209562306a36Sopenharmony_ci signal(SIGINT, running_handler); 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci options.iov_count = iov_count; 209862306a36Sopenharmony_ci options.iov_length = length; 209962306a36Sopenharmony_ci options.rate = rate; 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci err = run_options(&options, cg_fd, test); 210262306a36Sopenharmony_ciout: 210362306a36Sopenharmony_ci if (options.whitelist) 210462306a36Sopenharmony_ci free(options.whitelist); 210562306a36Sopenharmony_ci if (options.blacklist) 210662306a36Sopenharmony_ci free(options.blacklist); 210762306a36Sopenharmony_ci if (cg_created) 210862306a36Sopenharmony_ci cleanup_cgroup_environment(); 210962306a36Sopenharmony_ci close(cg_fd); 211062306a36Sopenharmony_ci return err; 211162306a36Sopenharmony_ci} 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_civoid running_handler(int a) 211462306a36Sopenharmony_ci{ 211562306a36Sopenharmony_ci running = 0; 211662306a36Sopenharmony_ci} 2117