PageRenderTime 70ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/testing/selftests/bpf/test_sockmap.c

https://github.com/kvaneesh/linux
C | 2026 lines | 1714 code | 248 blank | 64 comment | 325 complexity | fb5fee5544db7292bf48761cc456169e MD5 | raw file
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (c) 2017-2018 Covalent IO, Inc. http://covalent.io
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <sys/socket.h>
  6. #include <sys/ioctl.h>
  7. #include <sys/select.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <unistd.h>
  11. #include <string.h>
  12. #include <errno.h>
  13. #include <stdbool.h>
  14. #include <signal.h>
  15. #include <fcntl.h>
  16. #include <sys/wait.h>
  17. #include <time.h>
  18. #include <sched.h>
  19. #include <sys/time.h>
  20. #include <sys/resource.h>
  21. #include <sys/types.h>
  22. #include <sys/sendfile.h>
  23. #include <linux/netlink.h>
  24. #include <linux/socket.h>
  25. #include <linux/sock_diag.h>
  26. #include <linux/bpf.h>
  27. #include <linux/if_link.h>
  28. #include <linux/tls.h>
  29. #include <assert.h>
  30. #include <libgen.h>
  31. #include <getopt.h>
  32. #include <bpf/bpf.h>
  33. #include <bpf/libbpf.h>
  34. #include "bpf_util.h"
  35. #include "bpf_rlimit.h"
  36. #include "cgroup_helpers.h"
  37. int running;
  38. static void running_handler(int a);
  39. #ifndef TCP_ULP
  40. # define TCP_ULP 31
  41. #endif
  42. #ifndef SOL_TLS
  43. # define SOL_TLS 282
  44. #endif
  45. /* randomly selected ports for testing on lo */
  46. #define S1_PORT 10000
  47. #define S2_PORT 10001
  48. #define BPF_SOCKMAP_FILENAME "test_sockmap_kern.o"
  49. #define BPF_SOCKHASH_FILENAME "test_sockhash_kern.o"
  50. #define CG_PATH "/sockmap"
  51. /* global sockets */
  52. int s1, s2, c1, c2, p1, p2;
  53. int test_cnt;
  54. int passed;
  55. int failed;
  56. int map_fd[9];
  57. struct bpf_map *maps[9];
  58. int prog_fd[11];
  59. int txmsg_pass;
  60. int txmsg_redir;
  61. int txmsg_drop;
  62. int txmsg_apply;
  63. int txmsg_cork;
  64. int txmsg_start;
  65. int txmsg_end;
  66. int txmsg_start_push;
  67. int txmsg_end_push;
  68. int txmsg_start_pop;
  69. int txmsg_pop;
  70. int txmsg_ingress;
  71. int txmsg_redir_skb;
  72. int txmsg_ktls_skb;
  73. int txmsg_ktls_skb_drop;
  74. int txmsg_ktls_skb_redir;
  75. int ktls;
  76. int peek_flag;
  77. int skb_use_parser;
  78. int txmsg_omit_skb_parser;
  79. static const struct option long_options[] = {
  80. {"help", no_argument, NULL, 'h' },
  81. {"cgroup", required_argument, NULL, 'c' },
  82. {"rate", required_argument, NULL, 'r' },
  83. {"verbose", optional_argument, NULL, 'v' },
  84. {"iov_count", required_argument, NULL, 'i' },
  85. {"length", required_argument, NULL, 'l' },
  86. {"test", required_argument, NULL, 't' },
  87. {"data_test", no_argument, NULL, 'd' },
  88. {"txmsg", no_argument, &txmsg_pass, 1 },
  89. {"txmsg_redir", no_argument, &txmsg_redir, 1 },
  90. {"txmsg_drop", no_argument, &txmsg_drop, 1 },
  91. {"txmsg_apply", required_argument, NULL, 'a'},
  92. {"txmsg_cork", required_argument, NULL, 'k'},
  93. {"txmsg_start", required_argument, NULL, 's'},
  94. {"txmsg_end", required_argument, NULL, 'e'},
  95. {"txmsg_start_push", required_argument, NULL, 'p'},
  96. {"txmsg_end_push", required_argument, NULL, 'q'},
  97. {"txmsg_start_pop", required_argument, NULL, 'w'},
  98. {"txmsg_pop", required_argument, NULL, 'x'},
  99. {"txmsg_ingress", no_argument, &txmsg_ingress, 1 },
  100. {"txmsg_redir_skb", no_argument, &txmsg_redir_skb, 1 },
  101. {"ktls", no_argument, &ktls, 1 },
  102. {"peek", no_argument, &peek_flag, 1 },
  103. {"txmsg_omit_skb_parser", no_argument, &txmsg_omit_skb_parser, 1},
  104. {"whitelist", required_argument, NULL, 'n' },
  105. {"blacklist", required_argument, NULL, 'b' },
  106. {0, 0, NULL, 0 }
  107. };
  108. struct test_env {
  109. const char *type;
  110. const char *subtest;
  111. const char *prepend;
  112. int test_num;
  113. int subtest_num;
  114. int succ_cnt;
  115. int fail_cnt;
  116. int fail_last;
  117. };
  118. struct test_env env;
  119. struct sockmap_options {
  120. int verbose;
  121. bool base;
  122. bool sendpage;
  123. bool data_test;
  124. bool drop_expected;
  125. int iov_count;
  126. int iov_length;
  127. int rate;
  128. char *map;
  129. char *whitelist;
  130. char *blacklist;
  131. char *prepend;
  132. };
  133. struct _test {
  134. char *title;
  135. void (*tester)(int cg_fd, struct sockmap_options *opt);
  136. };
  137. static void test_start(void)
  138. {
  139. env.subtest_num++;
  140. }
  141. static void test_fail(void)
  142. {
  143. env.fail_cnt++;
  144. }
  145. static void test_pass(void)
  146. {
  147. env.succ_cnt++;
  148. }
  149. static void test_reset(void)
  150. {
  151. txmsg_start = txmsg_end = 0;
  152. txmsg_start_pop = txmsg_pop = 0;
  153. txmsg_start_push = txmsg_end_push = 0;
  154. txmsg_pass = txmsg_drop = txmsg_redir = 0;
  155. txmsg_apply = txmsg_cork = 0;
  156. txmsg_ingress = txmsg_redir_skb = 0;
  157. txmsg_ktls_skb = txmsg_ktls_skb_drop = txmsg_ktls_skb_redir = 0;
  158. txmsg_omit_skb_parser = 0;
  159. skb_use_parser = 0;
  160. }
  161. static int test_start_subtest(const struct _test *t, struct sockmap_options *o)
  162. {
  163. env.type = o->map;
  164. env.subtest = t->title;
  165. env.prepend = o->prepend;
  166. env.test_num++;
  167. env.subtest_num = 0;
  168. env.fail_last = env.fail_cnt;
  169. test_reset();
  170. return 0;
  171. }
  172. static void test_end_subtest(void)
  173. {
  174. int error = env.fail_cnt - env.fail_last;
  175. int type = strcmp(env.type, BPF_SOCKMAP_FILENAME);
  176. if (!error)
  177. test_pass();
  178. fprintf(stdout, "#%2d/%2d %8s:%s:%s:%s\n",
  179. env.test_num, env.subtest_num,
  180. !type ? "sockmap" : "sockhash",
  181. env.prepend ? : "",
  182. env.subtest, error ? "FAIL" : "OK");
  183. }
  184. static void test_print_results(void)
  185. {
  186. fprintf(stdout, "Pass: %d Fail: %d\n",
  187. env.succ_cnt, env.fail_cnt);
  188. }
  189. static void usage(char *argv[])
  190. {
  191. int i;
  192. printf(" Usage: %s --cgroup <cgroup_path>\n", argv[0]);
  193. printf(" options:\n");
  194. for (i = 0; long_options[i].name != 0; i++) {
  195. printf(" --%-12s", long_options[i].name);
  196. if (long_options[i].flag != NULL)
  197. printf(" flag (internal value:%d)\n",
  198. *long_options[i].flag);
  199. else
  200. printf(" -%c\n", long_options[i].val);
  201. }
  202. printf("\n");
  203. }
  204. char *sock_to_string(int s)
  205. {
  206. if (s == c1)
  207. return "client1";
  208. else if (s == c2)
  209. return "client2";
  210. else if (s == s1)
  211. return "server1";
  212. else if (s == s2)
  213. return "server2";
  214. else if (s == p1)
  215. return "peer1";
  216. else if (s == p2)
  217. return "peer2";
  218. else
  219. return "unknown";
  220. }
  221. static int sockmap_init_ktls(int verbose, int s)
  222. {
  223. struct tls12_crypto_info_aes_gcm_128 tls_tx = {
  224. .info = {
  225. .version = TLS_1_2_VERSION,
  226. .cipher_type = TLS_CIPHER_AES_GCM_128,
  227. },
  228. };
  229. struct tls12_crypto_info_aes_gcm_128 tls_rx = {
  230. .info = {
  231. .version = TLS_1_2_VERSION,
  232. .cipher_type = TLS_CIPHER_AES_GCM_128,
  233. },
  234. };
  235. int so_buf = 6553500;
  236. int err;
  237. err = setsockopt(s, 6, TCP_ULP, "tls", sizeof("tls"));
  238. if (err) {
  239. fprintf(stderr, "setsockopt: TCP_ULP(%s) failed with error %i\n", sock_to_string(s), err);
  240. return -EINVAL;
  241. }
  242. err = setsockopt(s, SOL_TLS, TLS_TX, (void *)&tls_tx, sizeof(tls_tx));
  243. if (err) {
  244. fprintf(stderr, "setsockopt: TLS_TX(%s) failed with error %i\n", sock_to_string(s), err);
  245. return -EINVAL;
  246. }
  247. err = setsockopt(s, SOL_TLS, TLS_RX, (void *)&tls_rx, sizeof(tls_rx));
  248. if (err) {
  249. fprintf(stderr, "setsockopt: TLS_RX(%s) failed with error %i\n", sock_to_string(s), err);
  250. return -EINVAL;
  251. }
  252. err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &so_buf, sizeof(so_buf));
  253. if (err) {
  254. fprintf(stderr, "setsockopt: (%s) failed sndbuf with error %i\n", sock_to_string(s), err);
  255. return -EINVAL;
  256. }
  257. err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, &so_buf, sizeof(so_buf));
  258. if (err) {
  259. fprintf(stderr, "setsockopt: (%s) failed rcvbuf with error %i\n", sock_to_string(s), err);
  260. return -EINVAL;
  261. }
  262. if (verbose)
  263. fprintf(stdout, "socket(%s) kTLS enabled\n", sock_to_string(s));
  264. return 0;
  265. }
  266. static int sockmap_init_sockets(int verbose)
  267. {
  268. int i, err, one = 1;
  269. struct sockaddr_in addr;
  270. int *fds[4] = {&s1, &s2, &c1, &c2};
  271. s1 = s2 = p1 = p2 = c1 = c2 = 0;
  272. /* Init sockets */
  273. for (i = 0; i < 4; i++) {
  274. *fds[i] = socket(AF_INET, SOCK_STREAM, 0);
  275. if (*fds[i] < 0) {
  276. perror("socket s1 failed()");
  277. return errno;
  278. }
  279. }
  280. /* Allow reuse */
  281. for (i = 0; i < 2; i++) {
  282. err = setsockopt(*fds[i], SOL_SOCKET, SO_REUSEADDR,
  283. (char *)&one, sizeof(one));
  284. if (err) {
  285. perror("setsockopt failed()");
  286. return errno;
  287. }
  288. }
  289. /* Non-blocking sockets */
  290. for (i = 0; i < 2; i++) {
  291. err = ioctl(*fds[i], FIONBIO, (char *)&one);
  292. if (err < 0) {
  293. perror("ioctl s1 failed()");
  294. return errno;
  295. }
  296. }
  297. /* Bind server sockets */
  298. memset(&addr, 0, sizeof(struct sockaddr_in));
  299. addr.sin_family = AF_INET;
  300. addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  301. addr.sin_port = htons(S1_PORT);
  302. err = bind(s1, (struct sockaddr *)&addr, sizeof(addr));
  303. if (err < 0) {
  304. perror("bind s1 failed()");
  305. return errno;
  306. }
  307. addr.sin_port = htons(S2_PORT);
  308. err = bind(s2, (struct sockaddr *)&addr, sizeof(addr));
  309. if (err < 0) {
  310. perror("bind s2 failed()");
  311. return errno;
  312. }
  313. /* Listen server sockets */
  314. addr.sin_port = htons(S1_PORT);
  315. err = listen(s1, 32);
  316. if (err < 0) {
  317. perror("listen s1 failed()");
  318. return errno;
  319. }
  320. addr.sin_port = htons(S2_PORT);
  321. err = listen(s2, 32);
  322. if (err < 0) {
  323. perror("listen s1 failed()");
  324. return errno;
  325. }
  326. /* Initiate Connect */
  327. addr.sin_port = htons(S1_PORT);
  328. err = connect(c1, (struct sockaddr *)&addr, sizeof(addr));
  329. if (err < 0 && errno != EINPROGRESS) {
  330. perror("connect c1 failed()");
  331. return errno;
  332. }
  333. addr.sin_port = htons(S2_PORT);
  334. err = connect(c2, (struct sockaddr *)&addr, sizeof(addr));
  335. if (err < 0 && errno != EINPROGRESS) {
  336. perror("connect c2 failed()");
  337. return errno;
  338. } else if (err < 0) {
  339. err = 0;
  340. }
  341. /* Accept Connecrtions */
  342. p1 = accept(s1, NULL, NULL);
  343. if (p1 < 0) {
  344. perror("accept s1 failed()");
  345. return errno;
  346. }
  347. p2 = accept(s2, NULL, NULL);
  348. if (p2 < 0) {
  349. perror("accept s1 failed()");
  350. return errno;
  351. }
  352. if (verbose > 1) {
  353. printf("connected sockets: c1 <-> p1, c2 <-> p2\n");
  354. printf("cgroups binding: c1(%i) <-> s1(%i) - - - c2(%i) <-> s2(%i)\n",
  355. c1, s1, c2, s2);
  356. }
  357. return 0;
  358. }
  359. struct msg_stats {
  360. size_t bytes_sent;
  361. size_t bytes_recvd;
  362. struct timespec start;
  363. struct timespec end;
  364. };
  365. static int msg_loop_sendpage(int fd, int iov_length, int cnt,
  366. struct msg_stats *s,
  367. struct sockmap_options *opt)
  368. {
  369. bool drop = opt->drop_expected;
  370. unsigned char k = 0;
  371. FILE *file;
  372. int i, fp;
  373. file = tmpfile();
  374. if (!file) {
  375. perror("create file for sendpage");
  376. return 1;
  377. }
  378. for (i = 0; i < iov_length * cnt; i++, k++)
  379. fwrite(&k, sizeof(char), 1, file);
  380. fflush(file);
  381. fseek(file, 0, SEEK_SET);
  382. fp = fileno(file);
  383. clock_gettime(CLOCK_MONOTONIC, &s->start);
  384. for (i = 0; i < cnt; i++) {
  385. int sent;
  386. errno = 0;
  387. sent = sendfile(fd, fp, NULL, iov_length);
  388. if (!drop && sent < 0) {
  389. perror("sendpage loop error");
  390. fclose(file);
  391. return sent;
  392. } else if (drop && sent >= 0) {
  393. printf("sendpage loop error expected: %i errno %i\n",
  394. sent, errno);
  395. fclose(file);
  396. return -EIO;
  397. }
  398. if (sent > 0)
  399. s->bytes_sent += sent;
  400. }
  401. clock_gettime(CLOCK_MONOTONIC, &s->end);
  402. fclose(file);
  403. return 0;
  404. }
  405. static void msg_free_iov(struct msghdr *msg)
  406. {
  407. int i;
  408. for (i = 0; i < msg->msg_iovlen; i++)
  409. free(msg->msg_iov[i].iov_base);
  410. free(msg->msg_iov);
  411. msg->msg_iov = NULL;
  412. msg->msg_iovlen = 0;
  413. }
  414. static int msg_alloc_iov(struct msghdr *msg,
  415. int iov_count, int iov_length,
  416. bool data, bool xmit)
  417. {
  418. unsigned char k = 0;
  419. struct iovec *iov;
  420. int i;
  421. iov = calloc(iov_count, sizeof(struct iovec));
  422. if (!iov)
  423. return errno;
  424. for (i = 0; i < iov_count; i++) {
  425. unsigned char *d = calloc(iov_length, sizeof(char));
  426. if (!d) {
  427. fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count);
  428. goto unwind_iov;
  429. }
  430. iov[i].iov_base = d;
  431. iov[i].iov_len = iov_length;
  432. if (data && xmit) {
  433. int j;
  434. for (j = 0; j < iov_length; j++)
  435. d[j] = k++;
  436. }
  437. }
  438. msg->msg_iov = iov;
  439. msg->msg_iovlen = iov_count;
  440. return 0;
  441. unwind_iov:
  442. for (i--; i >= 0 ; i--)
  443. free(msg->msg_iov[i].iov_base);
  444. return -ENOMEM;
  445. }
  446. static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz)
  447. {
  448. int i, j = 0, bytes_cnt = 0;
  449. unsigned char k = 0;
  450. for (i = 0; i < msg->msg_iovlen; i++) {
  451. unsigned char *d = msg->msg_iov[i].iov_base;
  452. /* Special case test for skb ingress + ktls */
  453. if (i == 0 && txmsg_ktls_skb) {
  454. if (msg->msg_iov[i].iov_len < 4)
  455. return -EIO;
  456. if (memcmp(d, "PASS", 4) != 0) {
  457. fprintf(stderr,
  458. "detected skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n",
  459. i, 0, d[0], d[1], d[2], d[3]);
  460. return -EIO;
  461. }
  462. j = 4; /* advance index past PASS header */
  463. }
  464. for (; j < msg->msg_iov[i].iov_len && size; j++) {
  465. if (d[j] != k++) {
  466. fprintf(stderr,
  467. "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n",
  468. i, j, d[j], k - 1, d[j+1], k);
  469. return -EIO;
  470. }
  471. bytes_cnt++;
  472. if (bytes_cnt == chunk_sz) {
  473. k = 0;
  474. bytes_cnt = 0;
  475. }
  476. size--;
  477. }
  478. }
  479. return 0;
  480. }
  481. static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
  482. struct msg_stats *s, bool tx,
  483. struct sockmap_options *opt)
  484. {
  485. struct msghdr msg = {0}, msg_peek = {0};
  486. int err, i, flags = MSG_NOSIGNAL;
  487. bool drop = opt->drop_expected;
  488. bool data = opt->data_test;
  489. err = msg_alloc_iov(&msg, iov_count, iov_length, data, tx);
  490. if (err)
  491. goto out_errno;
  492. if (peek_flag) {
  493. err = msg_alloc_iov(&msg_peek, iov_count, iov_length, data, tx);
  494. if (err)
  495. goto out_errno;
  496. }
  497. if (tx) {
  498. clock_gettime(CLOCK_MONOTONIC, &s->start);
  499. for (i = 0; i < cnt; i++) {
  500. int sent;
  501. errno = 0;
  502. sent = sendmsg(fd, &msg, flags);
  503. if (!drop && sent < 0) {
  504. perror("sendmsg loop error");
  505. goto out_errno;
  506. } else if (drop && sent >= 0) {
  507. fprintf(stderr,
  508. "sendmsg loop error expected: %i errno %i\n",
  509. sent, errno);
  510. errno = -EIO;
  511. goto out_errno;
  512. }
  513. if (sent > 0)
  514. s->bytes_sent += sent;
  515. }
  516. clock_gettime(CLOCK_MONOTONIC, &s->end);
  517. } else {
  518. int slct, recvp = 0, recv, max_fd = fd;
  519. float total_bytes, txmsg_pop_total;
  520. int fd_flags = O_NONBLOCK;
  521. struct timeval timeout;
  522. fd_set w;
  523. fcntl(fd, fd_flags);
  524. /* Account for pop bytes noting each iteration of apply will
  525. * call msg_pop_data helper so we need to account for this
  526. * by calculating the number of apply iterations. Note user
  527. * of the tool can create cases where no data is sent by
  528. * manipulating pop/push/pull/etc. For example txmsg_apply 1
  529. * with txmsg_pop 1 will try to apply 1B at a time but each
  530. * iteration will then pop 1B so no data will ever be sent.
  531. * This is really only useful for testing edge cases in code
  532. * paths.
  533. */
  534. total_bytes = (float)iov_count * (float)iov_length * (float)cnt;
  535. if (txmsg_apply)
  536. txmsg_pop_total = txmsg_pop * (total_bytes / txmsg_apply);
  537. else
  538. txmsg_pop_total = txmsg_pop * cnt;
  539. total_bytes -= txmsg_pop_total;
  540. err = clock_gettime(CLOCK_MONOTONIC, &s->start);
  541. if (err < 0)
  542. perror("recv start time");
  543. while (s->bytes_recvd < total_bytes) {
  544. if (txmsg_cork) {
  545. timeout.tv_sec = 0;
  546. timeout.tv_usec = 300000;
  547. } else {
  548. timeout.tv_sec = 3;
  549. timeout.tv_usec = 0;
  550. }
  551. /* FD sets */
  552. FD_ZERO(&w);
  553. FD_SET(fd, &w);
  554. slct = select(max_fd + 1, &w, NULL, NULL, &timeout);
  555. if (slct == -1) {
  556. perror("select()");
  557. clock_gettime(CLOCK_MONOTONIC, &s->end);
  558. goto out_errno;
  559. } else if (!slct) {
  560. if (opt->verbose)
  561. fprintf(stderr, "unexpected timeout: recved %zu/%f pop_total %f\n", s->bytes_recvd, total_bytes, txmsg_pop_total);
  562. errno = -EIO;
  563. clock_gettime(CLOCK_MONOTONIC, &s->end);
  564. goto out_errno;
  565. }
  566. errno = 0;
  567. if (peek_flag) {
  568. flags |= MSG_PEEK;
  569. recvp = recvmsg(fd, &msg_peek, flags);
  570. if (recvp < 0) {
  571. if (errno != EWOULDBLOCK) {
  572. clock_gettime(CLOCK_MONOTONIC, &s->end);
  573. goto out_errno;
  574. }
  575. }
  576. flags = 0;
  577. }
  578. recv = recvmsg(fd, &msg, flags);
  579. if (recv < 0) {
  580. if (errno != EWOULDBLOCK) {
  581. clock_gettime(CLOCK_MONOTONIC, &s->end);
  582. perror("recv failed()");
  583. goto out_errno;
  584. }
  585. }
  586. s->bytes_recvd += recv;
  587. if (data) {
  588. int chunk_sz = opt->sendpage ?
  589. iov_length * cnt :
  590. iov_length * iov_count;
  591. errno = msg_verify_data(&msg, recv, chunk_sz);
  592. if (errno) {
  593. perror("data verify msg failed");
  594. goto out_errno;
  595. }
  596. if (recvp) {
  597. errno = msg_verify_data(&msg_peek,
  598. recvp,
  599. chunk_sz);
  600. if (errno) {
  601. perror("data verify msg_peek failed");
  602. goto out_errno;
  603. }
  604. }
  605. }
  606. }
  607. clock_gettime(CLOCK_MONOTONIC, &s->end);
  608. }
  609. msg_free_iov(&msg);
  610. msg_free_iov(&msg_peek);
  611. return err;
  612. out_errno:
  613. msg_free_iov(&msg);
  614. msg_free_iov(&msg_peek);
  615. return errno;
  616. }
  617. static float giga = 1000000000;
  618. static inline float sentBps(struct msg_stats s)
  619. {
  620. return s.bytes_sent / (s.end.tv_sec - s.start.tv_sec);
  621. }
  622. static inline float recvdBps(struct msg_stats s)
  623. {
  624. return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec);
  625. }
  626. static int sendmsg_test(struct sockmap_options *opt)
  627. {
  628. float sent_Bps = 0, recvd_Bps = 0;
  629. int rx_fd, txpid, rxpid, err = 0;
  630. struct msg_stats s = {0};
  631. int iov_count = opt->iov_count;
  632. int iov_buf = opt->iov_length;
  633. int rx_status, tx_status;
  634. int cnt = opt->rate;
  635. errno = 0;
  636. if (opt->base)
  637. rx_fd = p1;
  638. else
  639. rx_fd = p2;
  640. if (ktls) {
  641. /* Redirecting into non-TLS socket which sends into a TLS
  642. * socket is not a valid test. So in this case lets not
  643. * enable kTLS but still run the test.
  644. */
  645. if (!txmsg_redir || txmsg_ingress) {
  646. err = sockmap_init_ktls(opt->verbose, rx_fd);
  647. if (err)
  648. return err;
  649. }
  650. err = sockmap_init_ktls(opt->verbose, c1);
  651. if (err)
  652. return err;
  653. }
  654. rxpid = fork();
  655. if (rxpid == 0) {
  656. iov_buf -= (txmsg_pop - txmsg_start_pop + 1);
  657. if (opt->drop_expected || txmsg_ktls_skb_drop)
  658. _exit(0);
  659. if (!iov_buf) /* zero bytes sent case */
  660. _exit(0);
  661. if (opt->sendpage)
  662. iov_count = 1;
  663. err = msg_loop(rx_fd, iov_count, iov_buf,
  664. cnt, &s, false, opt);
  665. if (opt->verbose > 1)
  666. fprintf(stderr,
  667. "msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n",
  668. iov_count, iov_buf, cnt, err);
  669. if (s.end.tv_sec - s.start.tv_sec) {
  670. sent_Bps = sentBps(s);
  671. recvd_Bps = recvdBps(s);
  672. }
  673. if (opt->verbose > 1)
  674. fprintf(stdout,
  675. "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s %s\n",
  676. s.bytes_sent, sent_Bps, sent_Bps/giga,
  677. s.bytes_recvd, recvd_Bps, recvd_Bps/giga,
  678. peek_flag ? "(peek_msg)" : "");
  679. if (err && txmsg_cork)
  680. err = 0;
  681. exit(err ? 1 : 0);
  682. } else if (rxpid == -1) {
  683. perror("msg_loop_rx");
  684. return errno;
  685. }
  686. txpid = fork();
  687. if (txpid == 0) {
  688. if (opt->sendpage)
  689. err = msg_loop_sendpage(c1, iov_buf, cnt, &s, opt);
  690. else
  691. err = msg_loop(c1, iov_count, iov_buf,
  692. cnt, &s, true, opt);
  693. if (err)
  694. fprintf(stderr,
  695. "msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n",
  696. iov_count, iov_buf, cnt, err);
  697. if (s.end.tv_sec - s.start.tv_sec) {
  698. sent_Bps = sentBps(s);
  699. recvd_Bps = recvdBps(s);
  700. }
  701. if (opt->verbose > 1)
  702. fprintf(stdout,
  703. "tx_sendmsg: TX: %zuB %fB/s %f GB/s RX: %zuB %fB/s %fGB/s\n",
  704. s.bytes_sent, sent_Bps, sent_Bps/giga,
  705. s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
  706. exit(err ? 1 : 0);
  707. } else if (txpid == -1) {
  708. perror("msg_loop_tx");
  709. return errno;
  710. }
  711. assert(waitpid(rxpid, &rx_status, 0) == rxpid);
  712. assert(waitpid(txpid, &tx_status, 0) == txpid);
  713. if (WIFEXITED(rx_status)) {
  714. err = WEXITSTATUS(rx_status);
  715. if (err) {
  716. fprintf(stderr, "rx thread exited with err %d.\n", err);
  717. goto out;
  718. }
  719. }
  720. if (WIFEXITED(tx_status)) {
  721. err = WEXITSTATUS(tx_status);
  722. if (err)
  723. fprintf(stderr, "tx thread exited with err %d.\n", err);
  724. }
  725. out:
  726. return err;
  727. }
  728. static int forever_ping_pong(int rate, struct sockmap_options *opt)
  729. {
  730. struct timeval timeout;
  731. char buf[1024] = {0};
  732. int sc;
  733. timeout.tv_sec = 10;
  734. timeout.tv_usec = 0;
  735. /* Ping/Pong data from client to server */
  736. sc = send(c1, buf, sizeof(buf), 0);
  737. if (sc < 0) {
  738. perror("send failed()");
  739. return sc;
  740. }
  741. do {
  742. int s, rc, i, max_fd = p2;
  743. fd_set w;
  744. /* FD sets */
  745. FD_ZERO(&w);
  746. FD_SET(c1, &w);
  747. FD_SET(c2, &w);
  748. FD_SET(p1, &w);
  749. FD_SET(p2, &w);
  750. s = select(max_fd + 1, &w, NULL, NULL, &timeout);
  751. if (s == -1) {
  752. perror("select()");
  753. break;
  754. } else if (!s) {
  755. fprintf(stderr, "unexpected timeout\n");
  756. break;
  757. }
  758. for (i = 0; i <= max_fd && s > 0; ++i) {
  759. if (!FD_ISSET(i, &w))
  760. continue;
  761. s--;
  762. rc = recv(i, buf, sizeof(buf), 0);
  763. if (rc < 0) {
  764. if (errno != EWOULDBLOCK) {
  765. perror("recv failed()");
  766. return rc;
  767. }
  768. }
  769. if (rc == 0) {
  770. close(i);
  771. break;
  772. }
  773. sc = send(i, buf, rc, 0);
  774. if (sc < 0) {
  775. perror("send failed()");
  776. return sc;
  777. }
  778. }
  779. if (rate)
  780. sleep(rate);
  781. if (opt->verbose) {
  782. printf(".");
  783. fflush(stdout);
  784. }
  785. } while (running);
  786. return 0;
  787. }
  788. enum {
  789. SELFTESTS,
  790. PING_PONG,
  791. SENDMSG,
  792. BASE,
  793. BASE_SENDPAGE,
  794. SENDPAGE,
  795. };
  796. static int run_options(struct sockmap_options *options, int cg_fd, int test)
  797. {
  798. int i, key, next_key, err, tx_prog_fd = -1, zero = 0;
  799. /* If base test skip BPF setup */
  800. if (test == BASE || test == BASE_SENDPAGE)
  801. goto run;
  802. /* Attach programs to sockmap */
  803. if (!txmsg_omit_skb_parser) {
  804. err = bpf_prog_attach(prog_fd[0], map_fd[0],
  805. BPF_SK_SKB_STREAM_PARSER, 0);
  806. if (err) {
  807. fprintf(stderr,
  808. "ERROR: bpf_prog_attach (sockmap %i->%i): %d (%s)\n",
  809. prog_fd[0], map_fd[0], err, strerror(errno));
  810. return err;
  811. }
  812. }
  813. err = bpf_prog_attach(prog_fd[1], map_fd[0],
  814. BPF_SK_SKB_STREAM_VERDICT, 0);
  815. if (err) {
  816. fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n",
  817. err, strerror(errno));
  818. return err;
  819. }
  820. /* Attach programs to TLS sockmap */
  821. if (txmsg_ktls_skb) {
  822. if (!txmsg_omit_skb_parser) {
  823. err = bpf_prog_attach(prog_fd[0], map_fd[8],
  824. BPF_SK_SKB_STREAM_PARSER, 0);
  825. if (err) {
  826. fprintf(stderr,
  827. "ERROR: bpf_prog_attach (TLS sockmap %i->%i): %d (%s)\n",
  828. prog_fd[0], map_fd[8], err, strerror(errno));
  829. return err;
  830. }
  831. }
  832. err = bpf_prog_attach(prog_fd[2], map_fd[8],
  833. BPF_SK_SKB_STREAM_VERDICT, 0);
  834. if (err) {
  835. fprintf(stderr, "ERROR: bpf_prog_attach (TLS sockmap): %d (%s)\n",
  836. err, strerror(errno));
  837. return err;
  838. }
  839. }
  840. /* Attach to cgroups */
  841. err = bpf_prog_attach(prog_fd[3], cg_fd, BPF_CGROUP_SOCK_OPS, 0);
  842. if (err) {
  843. fprintf(stderr, "ERROR: bpf_prog_attach (groups): %d (%s)\n",
  844. err, strerror(errno));
  845. return err;
  846. }
  847. run:
  848. err = sockmap_init_sockets(options->verbose);
  849. if (err) {
  850. fprintf(stderr, "ERROR: test socket failed: %d\n", err);
  851. goto out;
  852. }
  853. /* Attach txmsg program to sockmap */
  854. if (txmsg_pass)
  855. tx_prog_fd = prog_fd[4];
  856. else if (txmsg_redir)
  857. tx_prog_fd = prog_fd[5];
  858. else if (txmsg_apply)
  859. tx_prog_fd = prog_fd[6];
  860. else if (txmsg_cork)
  861. tx_prog_fd = prog_fd[7];
  862. else if (txmsg_drop)
  863. tx_prog_fd = prog_fd[8];
  864. else
  865. tx_prog_fd = 0;
  866. if (tx_prog_fd) {
  867. int redir_fd, i = 0;
  868. err = bpf_prog_attach(tx_prog_fd,
  869. map_fd[1], BPF_SK_MSG_VERDICT, 0);
  870. if (err) {
  871. fprintf(stderr,
  872. "ERROR: bpf_prog_attach (txmsg): %d (%s)\n",
  873. err, strerror(errno));
  874. goto out;
  875. }
  876. err = bpf_map_update_elem(map_fd[1], &i, &c1, BPF_ANY);
  877. if (err) {
  878. fprintf(stderr,
  879. "ERROR: bpf_map_update_elem (txmsg): %d (%s\n",
  880. err, strerror(errno));
  881. goto out;
  882. }
  883. if (txmsg_redir)
  884. redir_fd = c2;
  885. else
  886. redir_fd = c1;
  887. err = bpf_map_update_elem(map_fd[2], &i, &redir_fd, BPF_ANY);
  888. if (err) {
  889. fprintf(stderr,
  890. "ERROR: bpf_map_update_elem (txmsg): %d (%s\n",
  891. err, strerror(errno));
  892. goto out;
  893. }
  894. if (txmsg_apply) {
  895. err = bpf_map_update_elem(map_fd[3],
  896. &i, &txmsg_apply, BPF_ANY);
  897. if (err) {
  898. fprintf(stderr,
  899. "ERROR: bpf_map_update_elem (apply_bytes): %d (%s\n",
  900. err, strerror(errno));
  901. goto out;
  902. }
  903. }
  904. if (txmsg_cork) {
  905. err = bpf_map_update_elem(map_fd[4],
  906. &i, &txmsg_cork, BPF_ANY);
  907. if (err) {
  908. fprintf(stderr,
  909. "ERROR: bpf_map_update_elem (cork_bytes): %d (%s\n",
  910. err, strerror(errno));
  911. goto out;
  912. }
  913. }
  914. if (txmsg_start) {
  915. err = bpf_map_update_elem(map_fd[5],
  916. &i, &txmsg_start, BPF_ANY);
  917. if (err) {
  918. fprintf(stderr,
  919. "ERROR: bpf_map_update_elem (txmsg_start): %d (%s)\n",
  920. err, strerror(errno));
  921. goto out;
  922. }
  923. }
  924. if (txmsg_end) {
  925. i = 1;
  926. err = bpf_map_update_elem(map_fd[5],
  927. &i, &txmsg_end, BPF_ANY);
  928. if (err) {
  929. fprintf(stderr,
  930. "ERROR: bpf_map_update_elem (txmsg_end): %d (%s)\n",
  931. err, strerror(errno));
  932. goto out;
  933. }
  934. }
  935. if (txmsg_start_push) {
  936. i = 2;
  937. err = bpf_map_update_elem(map_fd[5],
  938. &i, &txmsg_start_push, BPF_ANY);
  939. if (err) {
  940. fprintf(stderr,
  941. "ERROR: bpf_map_update_elem (txmsg_start_push): %d (%s)\n",
  942. err, strerror(errno));
  943. goto out;
  944. }
  945. }
  946. if (txmsg_end_push) {
  947. i = 3;
  948. err = bpf_map_update_elem(map_fd[5],
  949. &i, &txmsg_end_push, BPF_ANY);
  950. if (err) {
  951. fprintf(stderr,
  952. "ERROR: bpf_map_update_elem %i@%i (txmsg_end_push): %d (%s)\n",
  953. txmsg_end_push, i, err, strerror(errno));
  954. goto out;
  955. }
  956. }
  957. if (txmsg_start_pop) {
  958. i = 4;
  959. err = bpf_map_update_elem(map_fd[5],
  960. &i, &txmsg_start_pop, BPF_ANY);
  961. if (err) {
  962. fprintf(stderr,
  963. "ERROR: bpf_map_update_elem %i@%i (txmsg_start_pop): %d (%s)\n",
  964. txmsg_start_pop, i, err, strerror(errno));
  965. goto out;
  966. }
  967. } else {
  968. i = 4;
  969. bpf_map_update_elem(map_fd[5],
  970. &i, &txmsg_start_pop, BPF_ANY);
  971. }
  972. if (txmsg_pop) {
  973. i = 5;
  974. err = bpf_map_update_elem(map_fd[5],
  975. &i, &txmsg_pop, BPF_ANY);
  976. if (err) {
  977. fprintf(stderr,
  978. "ERROR: bpf_map_update_elem %i@%i (txmsg_pop): %d (%s)\n",
  979. txmsg_pop, i, err, strerror(errno));
  980. goto out;
  981. }
  982. } else {
  983. i = 5;
  984. bpf_map_update_elem(map_fd[5],
  985. &i, &txmsg_pop, BPF_ANY);
  986. }
  987. if (txmsg_ingress) {
  988. int in = BPF_F_INGRESS;
  989. i = 0;
  990. err = bpf_map_update_elem(map_fd[6], &i, &in, BPF_ANY);
  991. if (err) {
  992. fprintf(stderr,
  993. "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
  994. err, strerror(errno));
  995. }
  996. i = 1;
  997. err = bpf_map_update_elem(map_fd[1], &i, &p1, BPF_ANY);
  998. if (err) {
  999. fprintf(stderr,
  1000. "ERROR: bpf_map_update_elem (p1 txmsg): %d (%s)\n",
  1001. err, strerror(errno));
  1002. }
  1003. err = bpf_map_update_elem(map_fd[2], &i, &p1, BPF_ANY);
  1004. if (err) {
  1005. fprintf(stderr,
  1006. "ERROR: bpf_map_update_elem (p1 redir): %d (%s)\n",
  1007. err, strerror(errno));
  1008. }
  1009. i = 2;
  1010. err = bpf_map_update_elem(map_fd[2], &i, &p2, BPF_ANY);
  1011. if (err) {
  1012. fprintf(stderr,
  1013. "ERROR: bpf_map_update_elem (p2 txmsg): %d (%s)\n",
  1014. err, strerror(errno));
  1015. }
  1016. }
  1017. if (txmsg_ktls_skb) {
  1018. int ingress = BPF_F_INGRESS;
  1019. i = 0;
  1020. err = bpf_map_update_elem(map_fd[8], &i, &p2, BPF_ANY);
  1021. if (err) {
  1022. fprintf(stderr,
  1023. "ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n",
  1024. err, strerror(errno));
  1025. }
  1026. if (txmsg_ktls_skb_redir) {
  1027. i = 1;
  1028. err = bpf_map_update_elem(map_fd[7],
  1029. &i, &ingress, BPF_ANY);
  1030. if (err) {
  1031. fprintf(stderr,
  1032. "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
  1033. err, strerror(errno));
  1034. }
  1035. }
  1036. if (txmsg_ktls_skb_drop) {
  1037. i = 1;
  1038. err = bpf_map_update_elem(map_fd[7], &i, &i, BPF_ANY);
  1039. }
  1040. }
  1041. if (txmsg_redir_skb) {
  1042. int skb_fd = (test == SENDMSG || test == SENDPAGE) ?
  1043. p2 : p1;
  1044. int ingress = BPF_F_INGRESS;
  1045. i = 0;
  1046. err = bpf_map_update_elem(map_fd[7],
  1047. &i, &ingress, BPF_ANY);
  1048. if (err) {
  1049. fprintf(stderr,
  1050. "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
  1051. err, strerror(errno));
  1052. }
  1053. i = 3;
  1054. err = bpf_map_update_elem(map_fd[0], &i, &skb_fd, BPF_ANY);
  1055. if (err) {
  1056. fprintf(stderr,
  1057. "ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n",
  1058. err, strerror(errno));
  1059. }
  1060. }
  1061. }
  1062. if (skb_use_parser) {
  1063. i = 2;
  1064. err = bpf_map_update_elem(map_fd[7], &i, &skb_use_parser, BPF_ANY);
  1065. }
  1066. if (txmsg_drop)
  1067. options->drop_expected = true;
  1068. if (test == PING_PONG)
  1069. err = forever_ping_pong(options->rate, options);
  1070. else if (test == SENDMSG) {
  1071. options->base = false;
  1072. options->sendpage = false;
  1073. err = sendmsg_test(options);
  1074. } else if (test == SENDPAGE) {
  1075. options->base = false;
  1076. options->sendpage = true;
  1077. err = sendmsg_test(options);
  1078. } else if (test == BASE) {
  1079. options->base = true;
  1080. options->sendpage = false;
  1081. err = sendmsg_test(options);
  1082. } else if (test == BASE_SENDPAGE) {
  1083. options->base = true;
  1084. options->sendpage = true;
  1085. err = sendmsg_test(options);
  1086. } else
  1087. fprintf(stderr, "unknown test\n");
  1088. out:
  1089. /* Detatch and zero all the maps */
  1090. bpf_prog_detach2(prog_fd[3], cg_fd, BPF_CGROUP_SOCK_OPS);
  1091. bpf_prog_detach2(prog_fd[0], map_fd[0], BPF_SK_SKB_STREAM_PARSER);
  1092. bpf_prog_detach2(prog_fd[1], map_fd[0], BPF_SK_SKB_STREAM_VERDICT);
  1093. bpf_prog_detach2(prog_fd[0], map_fd[8], BPF_SK_SKB_STREAM_PARSER);
  1094. bpf_prog_detach2(prog_fd[2], map_fd[8], BPF_SK_SKB_STREAM_VERDICT);
  1095. if (tx_prog_fd >= 0)
  1096. bpf_prog_detach2(tx_prog_fd, map_fd[1], BPF_SK_MSG_VERDICT);
  1097. for (i = 0; i < 8; i++) {
  1098. key = next_key = 0;
  1099. bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
  1100. while (bpf_map_get_next_key(map_fd[i], &key, &next_key) == 0) {
  1101. bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
  1102. key = next_key;
  1103. }
  1104. }
  1105. close(s1);
  1106. close(s2);
  1107. close(p1);
  1108. close(p2);
  1109. close(c1);
  1110. close(c2);
  1111. return err;
  1112. }
  1113. static char *test_to_str(int test)
  1114. {
  1115. switch (test) {
  1116. case SENDMSG:
  1117. return "sendmsg";
  1118. case SENDPAGE:
  1119. return "sendpage";
  1120. }
  1121. return "unknown";
  1122. }
  1123. static void append_str(char *dst, const char *src, size_t dst_cap)
  1124. {
  1125. size_t avail = dst_cap - strlen(dst);
  1126. if (avail <= 1) /* just zero byte could be written */
  1127. return;
  1128. strncat(dst, src, avail - 1); /* strncat() adds + 1 for zero byte */
  1129. }
  1130. #define OPTSTRING 60
  1131. static void test_options(char *options)
  1132. {
  1133. char tstr[OPTSTRING];
  1134. memset(options, 0, OPTSTRING);
  1135. if (txmsg_pass)
  1136. append_str(options, "pass,", OPTSTRING);
  1137. if (txmsg_redir)
  1138. append_str(options, "redir,", OPTSTRING);
  1139. if (txmsg_drop)
  1140. append_str(options, "drop,", OPTSTRING);
  1141. if (txmsg_apply) {
  1142. snprintf(tstr, OPTSTRING, "apply %d,", txmsg_apply);
  1143. append_str(options, tstr, OPTSTRING);
  1144. }
  1145. if (txmsg_cork) {
  1146. snprintf(tstr, OPTSTRING, "cork %d,", txmsg_cork);
  1147. append_str(options, tstr, OPTSTRING);
  1148. }
  1149. if (txmsg_start) {
  1150. snprintf(tstr, OPTSTRING, "start %d,", txmsg_start);
  1151. append_str(options, tstr, OPTSTRING);
  1152. }
  1153. if (txmsg_end) {
  1154. snprintf(tstr, OPTSTRING, "end %d,", txmsg_end);
  1155. append_str(options, tstr, OPTSTRING);
  1156. }
  1157. if (txmsg_start_pop) {
  1158. snprintf(tstr, OPTSTRING, "pop (%d,%d),",
  1159. txmsg_start_pop, txmsg_start_pop + txmsg_pop);
  1160. append_str(options, tstr, OPTSTRING);
  1161. }
  1162. if (txmsg_ingress)
  1163. append_str(options, "ingress,", OPTSTRING);
  1164. if (txmsg_redir_skb)
  1165. append_str(options, "redir_skb,", OPTSTRING);
  1166. if (txmsg_ktls_skb)
  1167. append_str(options, "ktls_skb,", OPTSTRING);
  1168. if (ktls)
  1169. append_str(options, "ktls,", OPTSTRING);
  1170. if (peek_flag)
  1171. append_str(options, "peek,", OPTSTRING);
  1172. }
  1173. static int __test_exec(int cgrp, int test, struct sockmap_options *opt)
  1174. {
  1175. char *options = calloc(OPTSTRING, sizeof(char));
  1176. int err;
  1177. if (test == SENDPAGE)
  1178. opt->sendpage = true;
  1179. else
  1180. opt->sendpage = false;
  1181. if (txmsg_drop)
  1182. opt->drop_expected = true;
  1183. else
  1184. opt->drop_expected = false;
  1185. test_options(options);
  1186. if (opt->verbose) {
  1187. fprintf(stdout,
  1188. " [TEST %i]: (%i, %i, %i, %s, %s): ",
  1189. test_cnt, opt->rate, opt->iov_count, opt->iov_length,
  1190. test_to_str(test), options);
  1191. fflush(stdout);
  1192. }
  1193. err = run_options(opt, cgrp, test);
  1194. if (opt->verbose)
  1195. fprintf(stdout, " %s\n", !err ? "PASS" : "FAILED");
  1196. test_cnt++;
  1197. !err ? passed++ : failed++;
  1198. free(options);
  1199. return err;
  1200. }
  1201. static void test_exec(int cgrp, struct sockmap_options *opt)
  1202. {
  1203. int type = strcmp(opt->map, BPF_SOCKMAP_FILENAME);
  1204. int err;
  1205. if (type == 0) {
  1206. test_start();
  1207. err = __test_exec(cgrp, SENDMSG, opt);
  1208. if (err)
  1209. test_fail();
  1210. } else {
  1211. test_start();
  1212. err = __test_exec(cgrp, SENDPAGE, opt);
  1213. if (err)
  1214. test_fail();
  1215. }
  1216. }
  1217. static void test_send_one(struct sockmap_options *opt, int cgrp)
  1218. {
  1219. opt->iov_length = 1;
  1220. opt->iov_count = 1;
  1221. opt->rate = 1;
  1222. test_exec(cgrp, opt);
  1223. opt->iov_length = 1;
  1224. opt->iov_count = 1024;
  1225. opt->rate = 1;
  1226. test_exec(cgrp, opt);
  1227. opt->iov_length = 1024;
  1228. opt->iov_count = 1;
  1229. opt->rate = 1;
  1230. test_exec(cgrp, opt);
  1231. }
  1232. static void test_send_many(struct sockmap_options *opt, int cgrp)
  1233. {
  1234. opt->iov_length = 3;
  1235. opt->iov_count = 1;
  1236. opt->rate = 512;
  1237. test_exec(cgrp, opt);
  1238. opt->rate = 100;
  1239. opt->iov_count = 1;
  1240. opt->iov_length = 5;
  1241. test_exec(cgrp, opt);
  1242. }
  1243. static void test_send_large(struct sockmap_options *opt, int cgrp)
  1244. {
  1245. opt->iov_length = 256;
  1246. opt->iov_count = 1024;
  1247. opt->rate = 2;
  1248. test_exec(cgrp, opt);
  1249. }
  1250. static void test_send(struct sockmap_options *opt, int cgrp)
  1251. {
  1252. test_send_one(opt, cgrp);
  1253. test_send_many(opt, cgrp);
  1254. test_send_large(opt, cgrp);
  1255. sched_yield();
  1256. }
  1257. static void test_txmsg_pass(int cgrp, struct sockmap_options *opt)
  1258. {
  1259. /* Test small and large iov_count values with pass/redir/apply/cork */
  1260. txmsg_pass = 1;
  1261. test_send(opt, cgrp);
  1262. }
  1263. static void test_txmsg_redir(int cgrp, struct sockmap_options *opt)
  1264. {
  1265. txmsg_redir = 1;
  1266. test_send(opt, cgrp);
  1267. }
  1268. static void test_txmsg_drop(int cgrp, struct sockmap_options *opt)
  1269. {
  1270. txmsg_drop = 1;
  1271. test_send(opt, cgrp);
  1272. }
  1273. static void test_txmsg_ingress_redir(int cgrp, struct sockmap_options *opt)
  1274. {
  1275. txmsg_pass = txmsg_drop = 0;
  1276. txmsg_ingress = txmsg_redir = 1;
  1277. test_send(opt, cgrp);
  1278. }
  1279. static void test_txmsg_skb(int cgrp, struct sockmap_options *opt)
  1280. {
  1281. bool data = opt->data_test;
  1282. int k = ktls;
  1283. opt->data_test = true;
  1284. ktls = 1;
  1285. txmsg_pass = txmsg_drop = 0;
  1286. txmsg_ingress = txmsg_redir = 0;
  1287. txmsg_ktls_skb = 1;
  1288. txmsg_pass = 1;
  1289. /* Using data verification so ensure iov layout is
  1290. * expected from test receiver side. e.g. has enough
  1291. * bytes to write test code.
  1292. */
  1293. opt->iov_length = 100;
  1294. opt->iov_count = 1;
  1295. opt->rate = 1;
  1296. test_exec(cgrp, opt);
  1297. txmsg_ktls_skb_drop = 1;
  1298. test_exec(cgrp, opt);
  1299. txmsg_ktls_skb_drop = 0;
  1300. txmsg_ktls_skb_redir = 1;
  1301. test_exec(cgrp, opt);
  1302. txmsg_ktls_skb_redir = 0;
  1303. /* Tests that omit skb_parser */
  1304. txmsg_omit_skb_parser = 1;
  1305. ktls = 0;
  1306. txmsg_ktls_skb = 0;
  1307. test_exec(cgrp, opt);
  1308. txmsg_ktls_skb_drop = 1;
  1309. test_exec(cgrp, opt);
  1310. txmsg_ktls_skb_drop = 0;
  1311. txmsg_ktls_skb_redir = 1;
  1312. test_exec(cgrp, opt);
  1313. ktls = 1;
  1314. test_exec(cgrp, opt);
  1315. txmsg_omit_skb_parser = 0;
  1316. opt->data_test = data;
  1317. ktls = k;
  1318. }
  1319. /* Test cork with hung data. This tests poor usage patterns where
  1320. * cork can leave data on the ring if user program is buggy and
  1321. * doesn't flush them somehow. They do take some time however
  1322. * because they wait for a timeout. Test pass, redir and cork with
  1323. * apply logic. Use cork size of 4097 with send_large to avoid
  1324. * aligning cork size with send size.
  1325. */
  1326. static void test_txmsg_cork_hangs(int cgrp, struct sockmap_options *opt)
  1327. {
  1328. txmsg_pass = 1;
  1329. txmsg_redir = 0;
  1330. txmsg_cork = 4097;
  1331. txmsg_apply = 4097;
  1332. test_send_large(opt, cgrp);
  1333. txmsg_pass = 0;
  1334. txmsg_redir = 1;
  1335. txmsg_apply = 0;
  1336. txmsg_cork = 4097;
  1337. test_send_large(opt, cgrp);
  1338. txmsg_pass = 0;
  1339. txmsg_redir = 1;
  1340. txmsg_apply = 4097;
  1341. txmsg_cork = 4097;
  1342. test_send_large(opt, cgrp);
  1343. }
  1344. static void test_txmsg_pull(int cgrp, struct sockmap_options *opt)
  1345. {
  1346. /* Test basic start/end */
  1347. txmsg_start = 1;
  1348. txmsg_end = 2;
  1349. test_send(opt, cgrp);
  1350. /* Test >4k pull */
  1351. txmsg_start = 4096;
  1352. txmsg_end = 9182;
  1353. test_send_large(opt, cgrp);
  1354. /* Test pull + redirect */
  1355. txmsg_redir = 0;
  1356. txmsg_start = 1;
  1357. txmsg_end = 2;
  1358. test_send(opt, cgrp);
  1359. /* Test pull + cork */
  1360. txmsg_redir = 0;
  1361. txmsg_cork = 512;
  1362. txmsg_start = 1;
  1363. txmsg_end = 2;
  1364. test_send_many(opt, cgrp);
  1365. /* Test pull + cork + redirect */
  1366. txmsg_redir = 1;
  1367. txmsg_cork = 512;
  1368. txmsg_start = 1;
  1369. txmsg_end = 2;
  1370. test_send_many(opt, cgrp);
  1371. }
  1372. static void test_txmsg_pop(int cgrp, struct sockmap_options *opt)
  1373. {
  1374. /* Test basic pop */
  1375. txmsg_start_pop = 1;
  1376. txmsg_pop = 2;
  1377. test_send_many(opt, cgrp);
  1378. /* Test pop with >4k */
  1379. txmsg_start_pop = 4096;
  1380. txmsg_pop = 4096;
  1381. test_send_large(opt, cgrp);
  1382. /* Test pop + redirect */
  1383. txmsg_redir = 1;
  1384. txmsg_start_pop = 1;
  1385. txmsg_pop = 2;
  1386. test_send_many(opt, cgrp);
  1387. /* Test pop + cork */
  1388. txmsg_redir = 0;
  1389. txmsg_cork = 512;
  1390. txmsg_start_pop = 1;
  1391. txmsg_pop = 2;
  1392. test_send_many(opt, cgrp);
  1393. /* Test pop + redirect + cork */
  1394. txmsg_redir = 1;
  1395. txmsg_cork = 4;
  1396. txmsg_start_pop = 1;
  1397. txmsg_pop = 2;
  1398. test_send_many(opt, cgrp);
  1399. }
  1400. static void test_txmsg_push(int cgrp, struct sockmap_options *opt)
  1401. {
  1402. /* Test basic push */
  1403. txmsg_start_push = 1;
  1404. txmsg_end_push = 1;
  1405. test_send(opt, cgrp);
  1406. /* Test push 4kB >4k */
  1407. txmsg_start_push = 4096;
  1408. txmsg_end_push = 4096;
  1409. test_send_large(opt, cgrp);
  1410. /* Test push + redirect */
  1411. txmsg_redir = 1;
  1412. txmsg_start_push = 1;
  1413. txmsg_end_push = 2;
  1414. test_send_many(opt, cgrp);
  1415. /* Test push + cork */
  1416. txmsg_redir = 0;
  1417. txmsg_cork = 512;
  1418. txmsg_start_push = 1;
  1419. txmsg_end_push = 2;
  1420. test_send_many(opt, cgrp);
  1421. }
  1422. static void test_txmsg_push_pop(int cgrp, struct sockmap_options *opt)
  1423. {
  1424. txmsg_start_push = 1;
  1425. txmsg_end_push = 10;
  1426. txmsg_start_pop = 5;
  1427. txmsg_pop = 4;
  1428. test_send_large(opt, cgrp);
  1429. }
  1430. static void test_txmsg_apply(int cgrp, struct sockmap_options *opt)
  1431. {
  1432. txmsg_pass = 1;
  1433. txmsg_redir = 0;
  1434. txmsg_apply = 1;
  1435. txmsg_cork = 0;
  1436. test_send_one(opt, cgrp);
  1437. txmsg_pass = 0;
  1438. txmsg_redir = 1;
  1439. txmsg_apply = 1;
  1440. txmsg_cork = 0;
  1441. test_send_one(opt, cgrp);
  1442. txmsg_pass = 1;
  1443. txmsg_redir = 0;
  1444. txmsg_apply = 1024;
  1445. txmsg_cork = 0;
  1446. test_send_large(opt, cgrp);
  1447. txmsg_pass = 0;
  1448. txmsg_redir = 1;
  1449. txmsg_apply = 1024;
  1450. txmsg_cork = 0;
  1451. test_send_large(opt, cgrp);
  1452. }
  1453. static void test_txmsg_cork(int cgrp, struct sockmap_options *opt)
  1454. {
  1455. txmsg_pass = 1;
  1456. txmsg_redir = 0;
  1457. txmsg_apply = 0;
  1458. txmsg_cork = 1;
  1459. test_send(opt, cgrp);
  1460. txmsg_pass = 1;
  1461. txmsg_redir = 0;
  1462. txmsg_apply = 1;
  1463. txmsg_cork = 1;
  1464. test_send(opt, cgrp);
  1465. }
  1466. static void test_txmsg_ingress_parser(int cgrp, struct sockmap_options *opt)
  1467. {
  1468. txmsg_pass = 1;
  1469. skb_use_parser = 512;
  1470. opt->iov_length = 256;
  1471. opt->iov_count = 1;
  1472. opt->rate = 2;
  1473. test_exec(cgrp, opt);
  1474. }
  1475. char *map_names[] = {
  1476. "sock_map",
  1477. "sock_map_txmsg",
  1478. "sock_map_redir",
  1479. "sock_apply_bytes",
  1480. "sock_cork_bytes",
  1481. "sock_bytes",
  1482. "sock_redir_flags",
  1483. "sock_skb_opts",
  1484. "tls_sock_map",
  1485. };
  1486. int prog_attach_type[] = {
  1487. BPF_SK_SKB_STREAM_PARSER,
  1488. BPF_SK_SKB_STREAM_VERDICT,
  1489. BPF_SK_SKB_STREAM_VERDICT,
  1490. BPF_CGROUP_SOCK_OPS,
  1491. BPF_SK_MSG_VERDICT,
  1492. BPF_SK_MSG_VERDICT,
  1493. BPF_SK_MSG_VERDICT,
  1494. BPF_SK_MSG_VERDICT,
  1495. BPF_SK_MSG_VERDICT,
  1496. BPF_SK_MSG_VERDICT,
  1497. BPF_SK_MSG_VERDICT,
  1498. };
  1499. int prog_type[] = {
  1500. BPF_PROG_TYPE_SK_SKB,
  1501. BPF_PROG_TYPE_SK_SKB,
  1502. BPF_PROG_TYPE_SK_SKB,
  1503. BPF_PROG_TYPE_SOCK_OPS,
  1504. BPF_PROG_TYPE_SK_MSG,
  1505. BPF_PROG_TYPE_SK_MSG,
  1506. BPF_PROG_TYPE_SK_MSG,
  1507. BPF_PROG_TYPE_SK_MSG,
  1508. BPF_PROG_TYPE_SK_MSG,
  1509. BPF_PROG_TYPE_SK_MSG,
  1510. BPF_PROG_TYPE_SK_MSG,
  1511. };
  1512. static int populate_progs(char *bpf_file)
  1513. {
  1514. struct bpf_program *prog;
  1515. struct bpf_object *obj;
  1516. int i = 0;
  1517. long err;
  1518. obj = bpf_object__open(bpf_file);
  1519. err = libbpf_get_error(obj);
  1520. if (err) {
  1521. char err_buf[256];
  1522. libbpf_strerror(err, err_buf, sizeof(err_buf));
  1523. printf("Unable to load eBPF objects in file '%s' : %s\n",
  1524. bpf_file, err_buf);
  1525. return -1;
  1526. }
  1527. bpf_object__for_each_program(prog, obj) {
  1528. bpf_program__set_type(prog, prog_type[i]);
  1529. bpf_program__set_expected_attach_type(prog,
  1530. prog_attach_type[i]);
  1531. i++;
  1532. }
  1533. i = bpf_object__load(obj);
  1534. i = 0;
  1535. bpf_object__for_each_program(prog, obj) {
  1536. prog_fd[i] = bpf_program__fd(prog);
  1537. i++;
  1538. }
  1539. for (i = 0; i < sizeof(map_fd)/sizeof(int); i++) {
  1540. maps[i] = bpf_object__find_map_by_name(obj, map_names[i]);
  1541. map_fd[i] = bpf_map__fd(maps[i]);
  1542. if (map_fd[i] < 0) {
  1543. fprintf(stderr, "load_bpf_file: (%i) %s\n",
  1544. map_fd[i], strerror(errno));
  1545. return -1;
  1546. }
  1547. }
  1548. return 0;
  1549. }
  1550. struct _test test[] = {
  1551. {"txmsg test passthrough", test_txmsg_pass},
  1552. {"txmsg test redirect", test_txmsg_redir},
  1553. {"txmsg test drop", test_txmsg_drop},
  1554. {"txmsg test ingress redirect", test_txmsg_ingress_redir},
  1555. {"txmsg test skb", test_txmsg_skb},
  1556. {"txmsg test apply", test_txmsg_apply},
  1557. {"txmsg test cork", test_txmsg_cork},
  1558. {"txmsg test hanging corks", test_txmsg_cork_hangs},
  1559. {"txmsg test push_data", test_txmsg_push},
  1560. {"txmsg test pull-data", test_txmsg_pull},
  1561. {"txmsg test pop-data", test_txmsg_pop},
  1562. {"txmsg test push/pop data", test_txmsg_push_pop},
  1563. {"txmsg text ingress parser", test_txmsg_ingress_parser},
  1564. };
  1565. static int check_whitelist(struct _test *t, struct sockmap_options *opt)
  1566. {
  1567. char *entry, *ptr;
  1568. if (!opt->whitelist)
  1569. return 0;
  1570. ptr = strdup(opt->whitelist);
  1571. if (!ptr)
  1572. return -ENOMEM;
  1573. entry = strtok(ptr, ",");
  1574. while (entry) {
  1575. if ((opt->prepend && strstr(opt->prepend, entry) != 0) ||
  1576. strstr(opt->map, entry) != 0 ||
  1577. strstr(t->title, entry) != 0)
  1578. return 0;
  1579. entry = strtok(NULL, ",");
  1580. }
  1581. return -EINVAL;
  1582. }
  1583. static int check_blacklist(struct _test *t, struct sockmap_options *opt)
  1584. {
  1585. char *entry, *ptr;
  1586. if (!opt->blacklist)
  1587. return -EINVAL;
  1588. ptr = strdup(opt->blacklist);
  1589. if (!ptr)
  1590. return -ENOMEM;
  1591. entry = strtok(ptr, ",");
  1592. while (entry) {
  1593. if ((opt->prepend && strstr(opt->prepend, entry) != 0) ||
  1594. strstr(opt->map, entry) != 0 ||
  1595. strstr(t->title, entry) != 0)
  1596. return 0;
  1597. entry = strtok(NULL, ",");
  1598. }
  1599. return -EINVAL;
  1600. }
  1601. static int __test_selftests(int cg_fd, struct sockmap_options *opt)
  1602. {
  1603. int i, err;
  1604. err = populate_progs(opt->map);
  1605. if (err < 0) {
  1606. fprintf(stderr, "ERROR: (%i) load bpf failed\n", err);
  1607. return err;
  1608. }
  1609. /* Tests basic commands and APIs */
  1610. for (i = 0; i < sizeof(test)/sizeof(struct _test); i++) {
  1611. struct _test t = test[i];
  1612. if (check_whitelist(&t, opt) != 0)
  1613. continue;
  1614. if (check_blacklist(&t, opt) == 0)
  1615. continue;
  1616. test_start_subtest(&t, opt);
  1617. t.tester(cg_fd, opt);
  1618. test_end_subtest();
  1619. }
  1620. return err;
  1621. }
  1622. static void test_selftests_sockmap(int cg_fd, struct sockmap_options *opt)
  1623. {
  1624. opt->map = BPF_SOCKMAP_FILENAME;
  1625. __test_selftests(cg_fd, opt);
  1626. }
  1627. static void test_selftests_sockhash(int cg_fd, struct sockmap_options *opt)
  1628. {
  1629. opt->map = BPF_SOCKHASH_FILENAME;
  1630. __test_selftests(cg_fd, opt);
  1631. }
  1632. static void test_selftests_ktls(int cg_fd, struct sockmap_options *opt)
  1633. {
  1634. opt->map = BPF_SOCKHASH_FILENAME;
  1635. opt->prepend = "ktls";
  1636. ktls = 1;
  1637. __test_selftests(cg_fd, opt);
  1638. ktls = 0;
  1639. }
  1640. static int test_selftest(int cg_fd, struct sockmap_options *opt)
  1641. {
  1642. test_selftests_sockmap(cg_fd, opt);
  1643. test_selftests_sockhash(cg_fd, opt);
  1644. test_selftests_ktls(cg_fd, opt);
  1645. test_print_results();
  1646. return 0;
  1647. }
  1648. int main(int argc, char **argv)
  1649. {
  1650. int iov_count = 1, length = 1024, rate = 1;
  1651. struct sockmap_options options = {0};
  1652. int opt, longindex, err, cg_fd = 0;
  1653. char *bpf_file = BPF_SOCKMAP_FILENAME;
  1654. int test = SELFTESTS;
  1655. bool cg_created = 0;
  1656. while ((opt = getopt_long(argc, argv, ":dhv:c:r:i:l:t:p:q:n:b:",
  1657. long_options, &longindex)) != -1) {
  1658. switch (opt) {
  1659. case 's':
  1660. txmsg_start = atoi(optarg);
  1661. break;
  1662. case 'e':
  1663. txmsg_end = atoi(optarg);
  1664. break;
  1665. case 'p':
  1666. txmsg_start_push = atoi(optarg);
  1667. break;
  1668. case 'q':
  1669. txmsg_end_push = atoi(optarg);
  1670. break;
  1671. case 'w':
  1672. txmsg_start_pop = atoi(optarg);
  1673. break;
  1674. case 'x':
  1675. txmsg_pop = atoi(optarg);
  1676. break;
  1677. case 'a':
  1678. txmsg_apply = atoi(optarg);
  1679. break;
  1680. case 'k':
  1681. txmsg_cork = atoi(optarg);
  1682. break;
  1683. case 'c':
  1684. cg_fd = open(optarg, O_DIRECTORY, O_RDONLY);
  1685. if (cg_fd < 0) {
  1686. fprintf(stderr,
  1687. "ERROR: (%i) open cg path failed: %s\n",
  1688. cg_fd, optarg);
  1689. return cg_fd;
  1690. }
  1691. break;
  1692. case 'r':
  1693. rate = atoi(optarg);
  1694. break;
  1695. case 'v':
  1696. options.verbose = 1;
  1697. if (optarg)
  1698. options.verbose = atoi(optarg);
  1699. break;
  1700. case 'i':
  1701. iov_count = atoi(optarg);
  1702. break;
  1703. case 'l':
  1704. length = atoi(optarg);
  1705. break;
  1706. case 'd':
  1707. options.data_test = true;
  1708. break;
  1709. case 't':
  1710. if (strcmp(optarg, "ping") == 0) {
  1711. test = PING_PONG;
  1712. } else if (strcmp(optarg, "sendmsg") == 0) {
  1713. test = SENDMSG;
  1714. } else if (strcmp(optarg, "base") == 0) {
  1715. test = BASE;
  1716. } else if (strcmp(optarg, "base_sendpage") == 0) {
  1717. test = BASE_SENDPAGE;
  1718. } else if (strcmp(optarg, "sendpage") == 0) {
  1719. test = SENDPAGE;
  1720. } else {
  1721. usage(argv);
  1722. return -1;
  1723. }
  1724. break;
  1725. case 'n':
  1726. options.whitelist = strdup(optarg);
  1727. if (!options.whitelist)
  1728. return -ENOMEM;
  1729. break;
  1730. case 'b':
  1731. options.blacklist = strdup(optarg);
  1732. if (!options.blacklist)
  1733. return -ENOMEM;
  1734. case 0:
  1735. break;
  1736. case 'h':
  1737. default:
  1738. usage(argv);
  1739. return -1;
  1740. }
  1741. }
  1742. if (!cg_fd) {
  1743. cg_fd = cgroup_setup_and_join(CG_PATH);
  1744. if (cg_fd < 0)
  1745. return cg_fd;
  1746. cg_created = 1;
  1747. }
  1748. if (test == SELFTESTS) {
  1749. err = test_selftest(cg_fd, &options);
  1750. goto out;
  1751. }
  1752. err = populate_progs(bpf_file);
  1753. if (err) {
  1754. fprintf(stderr, "populate program: (%s) %s\n",
  1755. bpf_file, strerror(errno));
  1756. return 1;
  1757. }
  1758. running = 1;
  1759. /* catch SIGINT */
  1760. signal(SIGINT, running_handler);
  1761. options.iov_count = iov_count;
  1762. options.iov_length = length;
  1763. options.rate = rate;
  1764. err = run_options(&options, cg_fd, test);
  1765. out:
  1766. if (options.whitelist)
  1767. free(options.whitelist);
  1768. if (options.blacklist)
  1769. free(options.blacklist);
  1770. if (cg_created)
  1771. cleanup_cgroup_environment();
  1772. close(cg_fd);
  1773. return err;
  1774. }
  1775. void running_handler(int a)
  1776. {
  1777. running = 0;
  1778. }