PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

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

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