test_sockmap.c 30 KB

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