test_sockmap.c 35 KB

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