PageRenderTime 58ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

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

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