test_sockmap.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477
  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 cnt = opt->rate;
  376. int status;
  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(1);
  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. exit(1);
  406. } else if (rxpid == -1) {
  407. perror("msg_loop_rx: ");
  408. return errno;
  409. }
  410. txpid = fork();
  411. if (txpid == 0) {
  412. if (opt->sendpage)
  413. err = msg_loop_sendpage(c1, iov_buf, cnt, &s, opt);
  414. else
  415. err = msg_loop(c1, iov_count, iov_buf,
  416. cnt, &s, true, opt);
  417. if (err)
  418. fprintf(stderr,
  419. "msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n",
  420. iov_count, iov_buf, cnt, err);
  421. shutdown(c1, SHUT_RDWR);
  422. if (s.end.tv_sec - s.start.tv_sec) {
  423. sent_Bps = sentBps(s);
  424. recvd_Bps = recvdBps(s);
  425. }
  426. if (opt->verbose)
  427. fprintf(stdout,
  428. "tx_sendmsg: TX: %zuB %fB/s %f GB/s RX: %zuB %fB/s %fGB/s\n",
  429. s.bytes_sent, sent_Bps, sent_Bps/giga,
  430. s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
  431. exit(1);
  432. } else if (txpid == -1) {
  433. perror("msg_loop_tx: ");
  434. return errno;
  435. }
  436. assert(waitpid(rxpid, &status, 0) == rxpid);
  437. assert(waitpid(txpid, &status, 0) == txpid);
  438. return err;
  439. }
  440. static int forever_ping_pong(int rate, struct sockmap_options *opt)
  441. {
  442. struct timeval timeout;
  443. char buf[1024] = {0};
  444. int sc;
  445. timeout.tv_sec = 10;
  446. timeout.tv_usec = 0;
  447. /* Ping/Pong data from client to server */
  448. sc = send(c1, buf, sizeof(buf), 0);
  449. if (sc < 0) {
  450. perror("send failed()\n");
  451. return sc;
  452. }
  453. do {
  454. int s, rc, i, max_fd = p2;
  455. fd_set w;
  456. /* FD sets */
  457. FD_ZERO(&w);
  458. FD_SET(c1, &w);
  459. FD_SET(c2, &w);
  460. FD_SET(p1, &w);
  461. FD_SET(p2, &w);
  462. s = select(max_fd + 1, &w, NULL, NULL, &timeout);
  463. if (s == -1) {
  464. perror("select()");
  465. break;
  466. } else if (!s) {
  467. fprintf(stderr, "unexpected timeout\n");
  468. break;
  469. }
  470. for (i = 0; i <= max_fd && s > 0; ++i) {
  471. if (!FD_ISSET(i, &w))
  472. continue;
  473. s--;
  474. rc = recv(i, buf, sizeof(buf), 0);
  475. if (rc < 0) {
  476. if (errno != EWOULDBLOCK) {
  477. perror("recv failed()\n");
  478. return rc;
  479. }
  480. }
  481. if (rc == 0) {
  482. close(i);
  483. break;
  484. }
  485. sc = send(i, buf, rc, 0);
  486. if (sc < 0) {
  487. perror("send failed()\n");
  488. return sc;
  489. }
  490. }
  491. if (rate)
  492. sleep(rate);
  493. if (opt->verbose) {
  494. printf(".");
  495. fflush(stdout);
  496. }
  497. } while (running);
  498. return 0;
  499. }
  500. enum {
  501. PING_PONG,
  502. SENDMSG,
  503. BASE,
  504. BASE_SENDPAGE,
  505. SENDPAGE,
  506. };
  507. static int run_options(struct sockmap_options *options, int cg_fd, int test)
  508. {
  509. int i, key, next_key, err, tx_prog_fd = -1, zero = 0;
  510. /* If base test skip BPF setup */
  511. if (test == BASE || test == BASE_SENDPAGE)
  512. goto run;
  513. /* Attach programs to sockmap */
  514. err = bpf_prog_attach(prog_fd[0], map_fd[0],
  515. BPF_SK_SKB_STREAM_PARSER, 0);
  516. if (err) {
  517. fprintf(stderr,
  518. "ERROR: bpf_prog_attach (sockmap %i->%i): %d (%s)\n",
  519. prog_fd[0], map_fd[0], err, strerror(errno));
  520. return err;
  521. }
  522. err = bpf_prog_attach(prog_fd[1], map_fd[0],
  523. BPF_SK_SKB_STREAM_VERDICT, 0);
  524. if (err) {
  525. fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n",
  526. err, strerror(errno));
  527. return err;
  528. }
  529. /* Attach to cgroups */
  530. err = bpf_prog_attach(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS, 0);
  531. if (err) {
  532. fprintf(stderr, "ERROR: bpf_prog_attach (groups): %d (%s)\n",
  533. err, strerror(errno));
  534. return err;
  535. }
  536. run:
  537. err = sockmap_init_sockets(options->verbose);
  538. if (err) {
  539. fprintf(stderr, "ERROR: test socket failed: %d\n", err);
  540. goto out;
  541. }
  542. /* Attach txmsg program to sockmap */
  543. if (txmsg_pass)
  544. tx_prog_fd = prog_fd[3];
  545. else if (txmsg_noisy)
  546. tx_prog_fd = prog_fd[4];
  547. else if (txmsg_redir)
  548. tx_prog_fd = prog_fd[5];
  549. else if (txmsg_redir_noisy)
  550. tx_prog_fd = prog_fd[6];
  551. else if (txmsg_drop)
  552. tx_prog_fd = prog_fd[9];
  553. /* apply and cork must be last */
  554. else if (txmsg_apply)
  555. tx_prog_fd = prog_fd[7];
  556. else if (txmsg_cork)
  557. tx_prog_fd = prog_fd[8];
  558. else
  559. tx_prog_fd = 0;
  560. if (tx_prog_fd) {
  561. int redir_fd, i = 0;
  562. err = bpf_prog_attach(tx_prog_fd,
  563. map_fd[1], BPF_SK_MSG_VERDICT, 0);
  564. if (err) {
  565. fprintf(stderr,
  566. "ERROR: bpf_prog_attach (txmsg): %d (%s)\n",
  567. err, strerror(errno));
  568. goto out;
  569. }
  570. err = bpf_map_update_elem(map_fd[1], &i, &c1, BPF_ANY);
  571. if (err) {
  572. fprintf(stderr,
  573. "ERROR: bpf_map_update_elem (txmsg): %d (%s\n",
  574. err, strerror(errno));
  575. goto out;
  576. }
  577. if (txmsg_redir || txmsg_redir_noisy)
  578. redir_fd = c2;
  579. else
  580. redir_fd = c1;
  581. err = bpf_map_update_elem(map_fd[2], &i, &redir_fd, BPF_ANY);
  582. if (err) {
  583. fprintf(stderr,
  584. "ERROR: bpf_map_update_elem (txmsg): %d (%s\n",
  585. err, strerror(errno));
  586. goto out;
  587. }
  588. if (txmsg_apply) {
  589. err = bpf_map_update_elem(map_fd[3],
  590. &i, &txmsg_apply, BPF_ANY);
  591. if (err) {
  592. fprintf(stderr,
  593. "ERROR: bpf_map_update_elem (apply_bytes): %d (%s\n",
  594. err, strerror(errno));
  595. goto out;
  596. }
  597. }
  598. if (txmsg_cork) {
  599. err = bpf_map_update_elem(map_fd[4],
  600. &i, &txmsg_cork, BPF_ANY);
  601. if (err) {
  602. fprintf(stderr,
  603. "ERROR: bpf_map_update_elem (cork_bytes): %d (%s\n",
  604. err, strerror(errno));
  605. goto out;
  606. }
  607. }
  608. if (txmsg_start) {
  609. err = bpf_map_update_elem(map_fd[5],
  610. &i, &txmsg_start, BPF_ANY);
  611. if (err) {
  612. fprintf(stderr,
  613. "ERROR: bpf_map_update_elem (txmsg_start): %d (%s)\n",
  614. err, strerror(errno));
  615. goto out;
  616. }
  617. }
  618. if (txmsg_end) {
  619. i = 1;
  620. err = bpf_map_update_elem(map_fd[5],
  621. &i, &txmsg_end, BPF_ANY);
  622. if (err) {
  623. fprintf(stderr,
  624. "ERROR: bpf_map_update_elem (txmsg_end): %d (%s)\n",
  625. err, strerror(errno));
  626. goto out;
  627. }
  628. }
  629. if (txmsg_ingress) {
  630. int in = BPF_F_INGRESS;
  631. i = 0;
  632. err = bpf_map_update_elem(map_fd[6], &i, &in, BPF_ANY);
  633. if (err) {
  634. fprintf(stderr,
  635. "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
  636. err, strerror(errno));
  637. }
  638. i = 1;
  639. err = bpf_map_update_elem(map_fd[1], &i, &p1, BPF_ANY);
  640. if (err) {
  641. fprintf(stderr,
  642. "ERROR: bpf_map_update_elem (p1 txmsg): %d (%s)\n",
  643. err, strerror(errno));
  644. }
  645. err = bpf_map_update_elem(map_fd[2], &i, &p1, BPF_ANY);
  646. if (err) {
  647. fprintf(stderr,
  648. "ERROR: bpf_map_update_elem (p1 redir): %d (%s)\n",
  649. err, strerror(errno));
  650. }
  651. i = 2;
  652. err = bpf_map_update_elem(map_fd[2], &i, &p2, BPF_ANY);
  653. if (err) {
  654. fprintf(stderr,
  655. "ERROR: bpf_map_update_elem (p2 txmsg): %d (%s)\n",
  656. err, strerror(errno));
  657. }
  658. }
  659. if (txmsg_skb) {
  660. int skb_fd = (test == SENDMSG || test == SENDPAGE) ?
  661. p2 : p1;
  662. int ingress = BPF_F_INGRESS;
  663. i = 0;
  664. err = bpf_map_update_elem(map_fd[7],
  665. &i, &ingress, BPF_ANY);
  666. if (err) {
  667. fprintf(stderr,
  668. "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
  669. err, strerror(errno));
  670. }
  671. i = 3;
  672. err = bpf_map_update_elem(map_fd[0],
  673. &i, &skb_fd, BPF_ANY);
  674. if (err) {
  675. fprintf(stderr,
  676. "ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n",
  677. err, strerror(errno));
  678. }
  679. }
  680. }
  681. if (txmsg_drop)
  682. options->drop_expected = true;
  683. if (test == PING_PONG)
  684. err = forever_ping_pong(options->rate, options);
  685. else if (test == SENDMSG) {
  686. options->base = false;
  687. options->sendpage = false;
  688. err = sendmsg_test(options);
  689. } else if (test == SENDPAGE) {
  690. options->base = false;
  691. options->sendpage = true;
  692. err = sendmsg_test(options);
  693. } else if (test == BASE) {
  694. options->base = true;
  695. options->sendpage = false;
  696. err = sendmsg_test(options);
  697. } else if (test == BASE_SENDPAGE) {
  698. options->base = true;
  699. options->sendpage = true;
  700. err = sendmsg_test(options);
  701. } else
  702. fprintf(stderr, "unknown test\n");
  703. out:
  704. /* Detatch and zero all the maps */
  705. bpf_prog_detach2(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS);
  706. bpf_prog_detach2(prog_fd[0], map_fd[0], BPF_SK_SKB_STREAM_PARSER);
  707. bpf_prog_detach2(prog_fd[1], map_fd[0], BPF_SK_SKB_STREAM_VERDICT);
  708. if (tx_prog_fd >= 0)
  709. bpf_prog_detach2(tx_prog_fd, map_fd[1], BPF_SK_MSG_VERDICT);
  710. for (i = 0; i < 8; i++) {
  711. key = next_key = 0;
  712. bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
  713. while (bpf_map_get_next_key(map_fd[i], &key, &next_key) == 0) {
  714. bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
  715. key = next_key;
  716. }
  717. }
  718. close(s1);
  719. close(s2);
  720. close(p1);
  721. close(p2);
  722. close(c1);
  723. close(c2);
  724. return err;
  725. }
  726. static char *test_to_str(int test)
  727. {
  728. switch (test) {
  729. case SENDMSG:
  730. return "sendmsg";
  731. case SENDPAGE:
  732. return "sendpage";
  733. }
  734. return "unknown";
  735. }
  736. #define OPTSTRING 60
  737. static void test_options(char *options)
  738. {
  739. memset(options, 0, OPTSTRING);
  740. if (txmsg_pass)
  741. strncat(options, "pass,", OPTSTRING);
  742. if (txmsg_noisy)
  743. strncat(options, "pass_noisy,", OPTSTRING);
  744. if (txmsg_redir)
  745. strncat(options, "redir,", OPTSTRING);
  746. if (txmsg_redir_noisy)
  747. strncat(options, "redir_noisy,", OPTSTRING);
  748. if (txmsg_drop)
  749. strncat(options, "drop,", OPTSTRING);
  750. if (txmsg_apply)
  751. strncat(options, "apply,", OPTSTRING);
  752. if (txmsg_cork)
  753. strncat(options, "cork,", OPTSTRING);
  754. if (txmsg_start)
  755. strncat(options, "start,", OPTSTRING);
  756. if (txmsg_end)
  757. strncat(options, "end,", OPTSTRING);
  758. if (txmsg_ingress)
  759. strncat(options, "ingress,", OPTSTRING);
  760. if (txmsg_skb)
  761. strncat(options, "skb,", OPTSTRING);
  762. }
  763. static int __test_exec(int cgrp, int test, struct sockmap_options *opt)
  764. {
  765. char *options = calloc(60, sizeof(char));
  766. int err;
  767. if (test == SENDPAGE)
  768. opt->sendpage = true;
  769. else
  770. opt->sendpage = false;
  771. if (txmsg_drop)
  772. opt->drop_expected = true;
  773. else
  774. opt->drop_expected = false;
  775. test_options(options);
  776. fprintf(stdout,
  777. "[TEST %i]: (%i, %i, %i, %s, %s): ",
  778. test_cnt, opt->rate, opt->iov_count, opt->iov_length,
  779. test_to_str(test), options);
  780. fflush(stdout);
  781. err = run_options(opt, cgrp, test);
  782. fprintf(stdout, "%s\n", !err ? "PASS" : "FAILED");
  783. test_cnt++;
  784. !err ? passed++ : failed++;
  785. free(options);
  786. return err;
  787. }
  788. static int test_exec(int cgrp, struct sockmap_options *opt)
  789. {
  790. int err = __test_exec(cgrp, SENDMSG, opt);
  791. if (err)
  792. goto out;
  793. err = __test_exec(cgrp, SENDPAGE, opt);
  794. out:
  795. return err;
  796. }
  797. static int test_loop(int cgrp)
  798. {
  799. struct sockmap_options opt;
  800. int err, i, l, r;
  801. opt.verbose = 0;
  802. opt.base = false;
  803. opt.sendpage = false;
  804. opt.data_test = false;
  805. opt.drop_expected = false;
  806. opt.iov_count = 0;
  807. opt.iov_length = 0;
  808. opt.rate = 0;
  809. r = 1;
  810. for (i = 1; i < 100; i += 33) {
  811. for (l = 1; l < 100; l += 33) {
  812. opt.rate = r;
  813. opt.iov_count = i;
  814. opt.iov_length = l;
  815. err = test_exec(cgrp, &opt);
  816. if (err)
  817. goto out;
  818. }
  819. }
  820. sched_yield();
  821. out:
  822. return err;
  823. }
  824. static int test_txmsg(int cgrp)
  825. {
  826. int err;
  827. txmsg_pass = txmsg_noisy = txmsg_redir_noisy = txmsg_drop = 0;
  828. txmsg_apply = txmsg_cork = 0;
  829. txmsg_ingress = txmsg_skb = 0;
  830. txmsg_pass = 1;
  831. err = test_loop(cgrp);
  832. txmsg_pass = 0;
  833. if (err)
  834. goto out;
  835. txmsg_redir = 1;
  836. err = test_loop(cgrp);
  837. txmsg_redir = 0;
  838. if (err)
  839. goto out;
  840. txmsg_drop = 1;
  841. err = test_loop(cgrp);
  842. txmsg_drop = 0;
  843. if (err)
  844. goto out;
  845. txmsg_redir = 1;
  846. txmsg_ingress = 1;
  847. err = test_loop(cgrp);
  848. txmsg_redir = 0;
  849. txmsg_ingress = 0;
  850. if (err)
  851. goto out;
  852. out:
  853. txmsg_pass = 0;
  854. txmsg_redir = 0;
  855. txmsg_drop = 0;
  856. return err;
  857. }
  858. static int test_send(struct sockmap_options *opt, int cgrp)
  859. {
  860. int err;
  861. opt->iov_length = 1;
  862. opt->iov_count = 1;
  863. opt->rate = 1;
  864. err = test_exec(cgrp, opt);
  865. if (err)
  866. goto out;
  867. opt->iov_length = 1;
  868. opt->iov_count = 1024;
  869. opt->rate = 1;
  870. err = test_exec(cgrp, opt);
  871. if (err)
  872. goto out;
  873. opt->iov_length = 1024;
  874. opt->iov_count = 1;
  875. opt->rate = 1;
  876. err = test_exec(cgrp, opt);
  877. if (err)
  878. goto out;
  879. opt->iov_length = 1;
  880. opt->iov_count = 1;
  881. opt->rate = 1024;
  882. err = test_exec(cgrp, opt);
  883. if (err)
  884. goto out;
  885. opt->iov_length = 256;
  886. opt->iov_count = 1024;
  887. opt->rate = 10;
  888. err = test_exec(cgrp, opt);
  889. if (err)
  890. goto out;
  891. opt->rate = 100;
  892. opt->iov_count = 1;
  893. opt->iov_length = 5;
  894. err = test_exec(cgrp, opt);
  895. if (err)
  896. goto out;
  897. out:
  898. sched_yield();
  899. return err;
  900. }
  901. static int test_mixed(int cgrp)
  902. {
  903. struct sockmap_options opt = {0};
  904. int err;
  905. txmsg_pass = txmsg_noisy = txmsg_redir_noisy = txmsg_drop = 0;
  906. txmsg_apply = txmsg_cork = 0;
  907. txmsg_start = txmsg_end = 0;
  908. /* Test small and large iov_count values with pass/redir/apply/cork */
  909. txmsg_pass = 1;
  910. txmsg_redir = 0;
  911. txmsg_apply = 1;
  912. txmsg_cork = 0;
  913. err = test_send(&opt, cgrp);
  914. if (err)
  915. goto out;
  916. txmsg_pass = 1;
  917. txmsg_redir = 0;
  918. txmsg_apply = 0;
  919. txmsg_cork = 1;
  920. err = test_send(&opt, cgrp);
  921. if (err)
  922. goto out;
  923. txmsg_pass = 1;
  924. txmsg_redir = 0;
  925. txmsg_apply = 1;
  926. txmsg_cork = 1;
  927. err = test_send(&opt, cgrp);
  928. if (err)
  929. goto out;
  930. txmsg_pass = 1;
  931. txmsg_redir = 0;
  932. txmsg_apply = 1024;
  933. txmsg_cork = 0;
  934. err = test_send(&opt, cgrp);
  935. if (err)
  936. goto out;
  937. txmsg_pass = 1;
  938. txmsg_redir = 0;
  939. txmsg_apply = 0;
  940. txmsg_cork = 1024;
  941. err = test_send(&opt, cgrp);
  942. if (err)
  943. goto out;
  944. txmsg_pass = 1;
  945. txmsg_redir = 0;
  946. txmsg_apply = 1024;
  947. txmsg_cork = 1024;
  948. err = test_send(&opt, cgrp);
  949. if (err)
  950. goto out;
  951. txmsg_pass = 1;
  952. txmsg_redir = 0;
  953. txmsg_cork = 4096;
  954. txmsg_apply = 4096;
  955. err = test_send(&opt, cgrp);
  956. if (err)
  957. goto out;
  958. txmsg_pass = 0;
  959. txmsg_redir = 1;
  960. txmsg_apply = 1;
  961. txmsg_cork = 0;
  962. err = test_send(&opt, cgrp);
  963. if (err)
  964. goto out;
  965. txmsg_pass = 0;
  966. txmsg_redir = 1;
  967. txmsg_apply = 0;
  968. txmsg_cork = 1;
  969. err = test_send(&opt, cgrp);
  970. if (err)
  971. goto out;
  972. txmsg_pass = 0;
  973. txmsg_redir = 1;
  974. txmsg_apply = 1024;
  975. txmsg_cork = 0;
  976. err = test_send(&opt, cgrp);
  977. if (err)
  978. goto out;
  979. txmsg_pass = 0;
  980. txmsg_redir = 1;
  981. txmsg_apply = 0;
  982. txmsg_cork = 1024;
  983. err = test_send(&opt, cgrp);
  984. if (err)
  985. goto out;
  986. txmsg_pass = 0;
  987. txmsg_redir = 1;
  988. txmsg_apply = 1024;
  989. txmsg_cork = 1024;
  990. err = test_send(&opt, cgrp);
  991. if (err)
  992. goto out;
  993. txmsg_pass = 0;
  994. txmsg_redir = 1;
  995. txmsg_cork = 4096;
  996. txmsg_apply = 4096;
  997. err = test_send(&opt, cgrp);
  998. if (err)
  999. goto out;
  1000. out:
  1001. return err;
  1002. }
  1003. static int test_start_end(int cgrp)
  1004. {
  1005. struct sockmap_options opt = {0};
  1006. int err, i;
  1007. /* Test basic start/end with lots of iov_count and iov_lengths */
  1008. txmsg_start = 1;
  1009. txmsg_end = 2;
  1010. err = test_txmsg(cgrp);
  1011. if (err)
  1012. goto out;
  1013. /* Test start/end with cork */
  1014. opt.rate = 16;
  1015. opt.iov_count = 1;
  1016. opt.iov_length = 100;
  1017. txmsg_cork = 1600;
  1018. for (i = 99; i <= 1600; i += 500) {
  1019. txmsg_start = 0;
  1020. txmsg_end = i;
  1021. err = test_exec(cgrp, &opt);
  1022. if (err)
  1023. goto out;
  1024. }
  1025. /* Test start/end with cork but pull data in middle */
  1026. for (i = 199; i <= 1600; i += 500) {
  1027. txmsg_start = 100;
  1028. txmsg_end = i;
  1029. err = test_exec(cgrp, &opt);
  1030. if (err)
  1031. goto out;
  1032. }
  1033. /* Test start/end with cork pulling last sg entry */
  1034. txmsg_start = 1500;
  1035. txmsg_end = 1600;
  1036. err = test_exec(cgrp, &opt);
  1037. if (err)
  1038. goto out;
  1039. /* Test start/end pull of single byte in last page */
  1040. txmsg_start = 1111;
  1041. txmsg_end = 1112;
  1042. err = test_exec(cgrp, &opt);
  1043. if (err)
  1044. goto out;
  1045. /* Test start/end with end < start */
  1046. txmsg_start = 1111;
  1047. txmsg_end = 0;
  1048. err = test_exec(cgrp, &opt);
  1049. if (err)
  1050. goto out;
  1051. /* Test start/end with end > data */
  1052. txmsg_start = 0;
  1053. txmsg_end = 1601;
  1054. err = test_exec(cgrp, &opt);
  1055. if (err)
  1056. goto out;
  1057. /* Test start/end with start > data */
  1058. txmsg_start = 1601;
  1059. txmsg_end = 1600;
  1060. err = test_exec(cgrp, &opt);
  1061. out:
  1062. txmsg_start = 0;
  1063. txmsg_end = 0;
  1064. sched_yield();
  1065. return err;
  1066. }
  1067. char *map_names[] = {
  1068. "sock_map",
  1069. "sock_map_txmsg",
  1070. "sock_map_redir",
  1071. "sock_apply_bytes",
  1072. "sock_cork_bytes",
  1073. "sock_pull_bytes",
  1074. "sock_redir_flags",
  1075. "sock_skb_opts",
  1076. };
  1077. int prog_attach_type[] = {
  1078. BPF_SK_SKB_STREAM_PARSER,
  1079. BPF_SK_SKB_STREAM_VERDICT,
  1080. BPF_CGROUP_SOCK_OPS,
  1081. BPF_SK_MSG_VERDICT,
  1082. BPF_SK_MSG_VERDICT,
  1083. BPF_SK_MSG_VERDICT,
  1084. BPF_SK_MSG_VERDICT,
  1085. BPF_SK_MSG_VERDICT,
  1086. BPF_SK_MSG_VERDICT,
  1087. BPF_SK_MSG_VERDICT,
  1088. };
  1089. int prog_type[] = {
  1090. BPF_PROG_TYPE_SK_SKB,
  1091. BPF_PROG_TYPE_SK_SKB,
  1092. BPF_PROG_TYPE_SOCK_OPS,
  1093. BPF_PROG_TYPE_SK_MSG,
  1094. BPF_PROG_TYPE_SK_MSG,
  1095. BPF_PROG_TYPE_SK_MSG,
  1096. BPF_PROG_TYPE_SK_MSG,
  1097. BPF_PROG_TYPE_SK_MSG,
  1098. BPF_PROG_TYPE_SK_MSG,
  1099. BPF_PROG_TYPE_SK_MSG,
  1100. };
  1101. static int populate_progs(char *bpf_file)
  1102. {
  1103. struct bpf_program *prog;
  1104. struct bpf_object *obj;
  1105. int i = 0;
  1106. long err;
  1107. obj = bpf_object__open(bpf_file);
  1108. err = libbpf_get_error(obj);
  1109. if (err) {
  1110. char err_buf[256];
  1111. libbpf_strerror(err, err_buf, sizeof(err_buf));
  1112. printf("Unable to load eBPF objects in file '%s' : %s\n",
  1113. bpf_file, err_buf);
  1114. return -1;
  1115. }
  1116. bpf_object__for_each_program(prog, obj) {
  1117. bpf_program__set_type(prog, prog_type[i]);
  1118. bpf_program__set_expected_attach_type(prog,
  1119. prog_attach_type[i]);
  1120. i++;
  1121. }
  1122. i = bpf_object__load(obj);
  1123. i = 0;
  1124. bpf_object__for_each_program(prog, obj) {
  1125. prog_fd[i] = bpf_program__fd(prog);
  1126. i++;
  1127. }
  1128. for (i = 0; i < sizeof(map_fd)/sizeof(int); i++) {
  1129. maps[i] = bpf_object__find_map_by_name(obj, map_names[i]);
  1130. map_fd[i] = bpf_map__fd(maps[i]);
  1131. if (map_fd[i] < 0) {
  1132. fprintf(stderr, "load_bpf_file: (%i) %s\n",
  1133. map_fd[i], strerror(errno));
  1134. return -1;
  1135. }
  1136. }
  1137. return 0;
  1138. }
  1139. static int __test_suite(char *bpf_file)
  1140. {
  1141. int cg_fd, err;
  1142. err = populate_progs(bpf_file);
  1143. if (err < 0) {
  1144. fprintf(stderr, "ERROR: (%i) load bpf failed\n", err);
  1145. return err;
  1146. }
  1147. if (setup_cgroup_environment()) {
  1148. fprintf(stderr, "ERROR: cgroup env failed\n");
  1149. return -EINVAL;
  1150. }
  1151. cg_fd = create_and_get_cgroup(CG_PATH);
  1152. if (cg_fd < 0) {
  1153. fprintf(stderr,
  1154. "ERROR: (%i) open cg path failed: %s\n",
  1155. cg_fd, optarg);
  1156. return cg_fd;
  1157. }
  1158. /* Tests basic commands and APIs with range of iov values */
  1159. txmsg_start = txmsg_end = 0;
  1160. err = test_txmsg(cg_fd);
  1161. if (err)
  1162. goto out;
  1163. /* Tests interesting combinations of APIs used together */
  1164. err = test_mixed(cg_fd);
  1165. if (err)
  1166. goto out;
  1167. /* Tests pull_data API using start/end API */
  1168. err = test_start_end(cg_fd);
  1169. if (err)
  1170. goto out;
  1171. out:
  1172. printf("Summary: %i PASSED %i FAILED\n", passed, failed);
  1173. cleanup_cgroup_environment();
  1174. close(cg_fd);
  1175. return err;
  1176. }
  1177. static int test_suite(void)
  1178. {
  1179. int err;
  1180. err = __test_suite(BPF_SOCKMAP_FILENAME);
  1181. if (err)
  1182. goto out;
  1183. err = __test_suite(BPF_SOCKHASH_FILENAME);
  1184. out:
  1185. return err;
  1186. }
  1187. int main(int argc, char **argv)
  1188. {
  1189. struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY};
  1190. int iov_count = 1, length = 1024, rate = 1;
  1191. struct sockmap_options options = {0};
  1192. int opt, longindex, err, cg_fd = 0;
  1193. char *bpf_file = BPF_SOCKMAP_FILENAME;
  1194. int test = PING_PONG;
  1195. if (setrlimit(RLIMIT_MEMLOCK, &r)) {
  1196. perror("setrlimit(RLIMIT_MEMLOCK)");
  1197. return 1;
  1198. }
  1199. if (argc < 2)
  1200. return test_suite();
  1201. while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:",
  1202. long_options, &longindex)) != -1) {
  1203. switch (opt) {
  1204. case 's':
  1205. txmsg_start = atoi(optarg);
  1206. break;
  1207. case 'e':
  1208. txmsg_end = atoi(optarg);
  1209. break;
  1210. case 'a':
  1211. txmsg_apply = atoi(optarg);
  1212. break;
  1213. case 'k':
  1214. txmsg_cork = atoi(optarg);
  1215. break;
  1216. case 'c':
  1217. cg_fd = open(optarg, O_DIRECTORY, O_RDONLY);
  1218. if (cg_fd < 0) {
  1219. fprintf(stderr,
  1220. "ERROR: (%i) open cg path failed: %s\n",
  1221. cg_fd, optarg);
  1222. return cg_fd;
  1223. }
  1224. break;
  1225. case 'r':
  1226. rate = atoi(optarg);
  1227. break;
  1228. case 'v':
  1229. options.verbose = 1;
  1230. break;
  1231. case 'i':
  1232. iov_count = atoi(optarg);
  1233. break;
  1234. case 'l':
  1235. length = atoi(optarg);
  1236. break;
  1237. case 'd':
  1238. options.data_test = true;
  1239. break;
  1240. case 't':
  1241. if (strcmp(optarg, "ping") == 0) {
  1242. test = PING_PONG;
  1243. } else if (strcmp(optarg, "sendmsg") == 0) {
  1244. test = SENDMSG;
  1245. } else if (strcmp(optarg, "base") == 0) {
  1246. test = BASE;
  1247. } else if (strcmp(optarg, "base_sendpage") == 0) {
  1248. test = BASE_SENDPAGE;
  1249. } else if (strcmp(optarg, "sendpage") == 0) {
  1250. test = SENDPAGE;
  1251. } else {
  1252. usage(argv);
  1253. return -1;
  1254. }
  1255. break;
  1256. case 0:
  1257. break;
  1258. case 'h':
  1259. default:
  1260. usage(argv);
  1261. return -1;
  1262. }
  1263. }
  1264. if (!cg_fd) {
  1265. fprintf(stderr, "%s requires cgroup option: --cgroup <path>\n",
  1266. argv[0]);
  1267. return -1;
  1268. }
  1269. err = populate_progs(bpf_file);
  1270. if (err) {
  1271. fprintf(stderr, "populate program: (%s) %s\n",
  1272. bpf_file, strerror(errno));
  1273. return 1;
  1274. }
  1275. running = 1;
  1276. /* catch SIGINT */
  1277. signal(SIGINT, running_handler);
  1278. options.iov_count = iov_count;
  1279. options.iov_length = length;
  1280. options.rate = rate;
  1281. err = run_options(&options, cg_fd, test);
  1282. close(cg_fd);
  1283. return err;
  1284. }
  1285. void running_handler(int a)
  1286. {
  1287. running = 0;
  1288. }