xdpsock_user.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright(c) 2017 - 2018 Intel Corporation. */
  3. #include <asm/barrier.h>
  4. #include <errno.h>
  5. #include <getopt.h>
  6. #include <libgen.h>
  7. #include <linux/bpf.h>
  8. #include <linux/compiler.h>
  9. #include <linux/if_link.h>
  10. #include <linux/if_xdp.h>
  11. #include <linux/if_ether.h>
  12. #include <linux/ip.h>
  13. #include <linux/limits.h>
  14. #include <linux/udp.h>
  15. #include <arpa/inet.h>
  16. #include <locale.h>
  17. #include <net/ethernet.h>
  18. #include <net/if.h>
  19. #include <poll.h>
  20. #include <pthread.h>
  21. #include <signal.h>
  22. #include <stdbool.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <sys/mman.h>
  27. #include <sys/resource.h>
  28. #include <sys/socket.h>
  29. #include <sys/types.h>
  30. #include <time.h>
  31. #include <unistd.h>
  32. #include <bpf/libbpf.h>
  33. #include <bpf/xsk.h>
  34. #include <bpf/bpf.h>
  35. #include "xdpsock.h"
  36. #ifndef SOL_XDP
  37. #define SOL_XDP 283
  38. #endif
  39. #ifndef AF_XDP
  40. #define AF_XDP 44
  41. #endif
  42. #ifndef PF_XDP
  43. #define PF_XDP AF_XDP
  44. #endif
  45. #define NUM_FRAMES (4 * 1024)
  46. #define MIN_PKT_SIZE 64
  47. #define DEBUG_HEXDUMP 0
  48. typedef __u64 u64;
  49. typedef __u32 u32;
  50. typedef __u16 u16;
  51. typedef __u8 u8;
  52. static unsigned long prev_time;
  53. enum benchmark_type {
  54. BENCH_RXDROP = 0,
  55. BENCH_TXONLY = 1,
  56. BENCH_L2FWD = 2,
  57. };
  58. static enum benchmark_type opt_bench = BENCH_RXDROP;
  59. static u32 opt_xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
  60. static const char *opt_if = "";
  61. static int opt_ifindex;
  62. static int opt_queue;
  63. static unsigned long opt_duration;
  64. static unsigned long start_time;
  65. static bool benchmark_done;
  66. static u32 opt_batch_size = 64;
  67. static int opt_pkt_count;
  68. static u16 opt_pkt_size = MIN_PKT_SIZE;
  69. static u32 opt_pkt_fill_pattern = 0x12345678;
  70. static bool opt_extra_stats;
  71. static bool opt_quiet;
  72. static bool opt_app_stats;
  73. static const char *opt_irq_str = "";
  74. static u32 irq_no;
  75. static int irqs_at_init = -1;
  76. static int opt_poll;
  77. static int opt_interval = 1;
  78. static u32 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP;
  79. static u32 opt_umem_flags;
  80. static int opt_unaligned_chunks;
  81. static int opt_mmap_flags;
  82. static int opt_xsk_frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
  83. static int opt_timeout = 1000;
  84. static bool opt_need_wakeup = true;
  85. static u32 opt_num_xsks = 1;
  86. static u32 prog_id;
  87. struct xsk_ring_stats {
  88. unsigned long rx_npkts;
  89. unsigned long tx_npkts;
  90. unsigned long rx_dropped_npkts;
  91. unsigned long rx_invalid_npkts;
  92. unsigned long tx_invalid_npkts;
  93. unsigned long rx_full_npkts;
  94. unsigned long rx_fill_empty_npkts;
  95. unsigned long tx_empty_npkts;
  96. unsigned long prev_rx_npkts;
  97. unsigned long prev_tx_npkts;
  98. unsigned long prev_rx_dropped_npkts;
  99. unsigned long prev_rx_invalid_npkts;
  100. unsigned long prev_tx_invalid_npkts;
  101. unsigned long prev_rx_full_npkts;
  102. unsigned long prev_rx_fill_empty_npkts;
  103. unsigned long prev_tx_empty_npkts;
  104. };
  105. struct xsk_driver_stats {
  106. unsigned long intrs;
  107. unsigned long prev_intrs;
  108. };
  109. struct xsk_app_stats {
  110. unsigned long rx_empty_polls;
  111. unsigned long fill_fail_polls;
  112. unsigned long copy_tx_sendtos;
  113. unsigned long tx_wakeup_sendtos;
  114. unsigned long opt_polls;
  115. unsigned long prev_rx_empty_polls;
  116. unsigned long prev_fill_fail_polls;
  117. unsigned long prev_copy_tx_sendtos;
  118. unsigned long prev_tx_wakeup_sendtos;
  119. unsigned long prev_opt_polls;
  120. };
  121. struct xsk_umem_info {
  122. struct xsk_ring_prod fq;
  123. struct xsk_ring_cons cq;
  124. struct xsk_umem *umem;
  125. void *buffer;
  126. };
  127. struct xsk_socket_info {
  128. struct xsk_ring_cons rx;
  129. struct xsk_ring_prod tx;
  130. struct xsk_umem_info *umem;
  131. struct xsk_socket *xsk;
  132. struct xsk_ring_stats ring_stats;
  133. struct xsk_app_stats app_stats;
  134. struct xsk_driver_stats drv_stats;
  135. u32 outstanding_tx;
  136. };
  137. static int num_socks;
  138. struct xsk_socket_info *xsks[MAX_SOCKS];
  139. static unsigned long get_nsecs(void)
  140. {
  141. struct timespec ts;
  142. clock_gettime(CLOCK_MONOTONIC, &ts);
  143. return ts.tv_sec * 1000000000UL + ts.tv_nsec;
  144. }
  145. static void print_benchmark(bool running)
  146. {
  147. const char *bench_str = "INVALID";
  148. if (opt_bench == BENCH_RXDROP)
  149. bench_str = "rxdrop";
  150. else if (opt_bench == BENCH_TXONLY)
  151. bench_str = "txonly";
  152. else if (opt_bench == BENCH_L2FWD)
  153. bench_str = "l2fwd";
  154. printf("%s:%d %s ", opt_if, opt_queue, bench_str);
  155. if (opt_xdp_flags & XDP_FLAGS_SKB_MODE)
  156. printf("xdp-skb ");
  157. else if (opt_xdp_flags & XDP_FLAGS_DRV_MODE)
  158. printf("xdp-drv ");
  159. else
  160. printf(" ");
  161. if (opt_poll)
  162. printf("poll() ");
  163. if (running) {
  164. printf("running...");
  165. fflush(stdout);
  166. }
  167. }
  168. static int xsk_get_xdp_stats(int fd, struct xsk_socket_info *xsk)
  169. {
  170. struct xdp_statistics stats;
  171. socklen_t optlen;
  172. int err;
  173. optlen = sizeof(stats);
  174. err = getsockopt(fd, SOL_XDP, XDP_STATISTICS, &stats, &optlen);
  175. if (err)
  176. return err;
  177. if (optlen == sizeof(struct xdp_statistics)) {
  178. xsk->ring_stats.rx_dropped_npkts = stats.rx_dropped;
  179. xsk->ring_stats.rx_invalid_npkts = stats.rx_invalid_descs;
  180. xsk->ring_stats.tx_invalid_npkts = stats.tx_invalid_descs;
  181. xsk->ring_stats.rx_full_npkts = stats.rx_ring_full;
  182. xsk->ring_stats.rx_fill_empty_npkts = stats.rx_fill_ring_empty_descs;
  183. xsk->ring_stats.tx_empty_npkts = stats.tx_ring_empty_descs;
  184. return 0;
  185. }
  186. return -EINVAL;
  187. }
  188. static void dump_app_stats(long dt)
  189. {
  190. int i;
  191. for (i = 0; i < num_socks && xsks[i]; i++) {
  192. char *fmt = "%-18s %'-14.0f %'-14lu\n";
  193. double rx_empty_polls_ps, fill_fail_polls_ps, copy_tx_sendtos_ps,
  194. tx_wakeup_sendtos_ps, opt_polls_ps;
  195. rx_empty_polls_ps = (xsks[i]->app_stats.rx_empty_polls -
  196. xsks[i]->app_stats.prev_rx_empty_polls) * 1000000000. / dt;
  197. fill_fail_polls_ps = (xsks[i]->app_stats.fill_fail_polls -
  198. xsks[i]->app_stats.prev_fill_fail_polls) * 1000000000. / dt;
  199. copy_tx_sendtos_ps = (xsks[i]->app_stats.copy_tx_sendtos -
  200. xsks[i]->app_stats.prev_copy_tx_sendtos) * 1000000000. / dt;
  201. tx_wakeup_sendtos_ps = (xsks[i]->app_stats.tx_wakeup_sendtos -
  202. xsks[i]->app_stats.prev_tx_wakeup_sendtos)
  203. * 1000000000. / dt;
  204. opt_polls_ps = (xsks[i]->app_stats.opt_polls -
  205. xsks[i]->app_stats.prev_opt_polls) * 1000000000. / dt;
  206. printf("\n%-18s %-14s %-14s\n", "", "calls/s", "count");
  207. printf(fmt, "rx empty polls", rx_empty_polls_ps, xsks[i]->app_stats.rx_empty_polls);
  208. printf(fmt, "fill fail polls", fill_fail_polls_ps,
  209. xsks[i]->app_stats.fill_fail_polls);
  210. printf(fmt, "copy tx sendtos", copy_tx_sendtos_ps,
  211. xsks[i]->app_stats.copy_tx_sendtos);
  212. printf(fmt, "tx wakeup sendtos", tx_wakeup_sendtos_ps,
  213. xsks[i]->app_stats.tx_wakeup_sendtos);
  214. printf(fmt, "opt polls", opt_polls_ps, xsks[i]->app_stats.opt_polls);
  215. xsks[i]->app_stats.prev_rx_empty_polls = xsks[i]->app_stats.rx_empty_polls;
  216. xsks[i]->app_stats.prev_fill_fail_polls = xsks[i]->app_stats.fill_fail_polls;
  217. xsks[i]->app_stats.prev_copy_tx_sendtos = xsks[i]->app_stats.copy_tx_sendtos;
  218. xsks[i]->app_stats.prev_tx_wakeup_sendtos = xsks[i]->app_stats.tx_wakeup_sendtos;
  219. xsks[i]->app_stats.prev_opt_polls = xsks[i]->app_stats.opt_polls;
  220. }
  221. }
  222. static bool get_interrupt_number(void)
  223. {
  224. FILE *f_int_proc;
  225. char line[4096];
  226. bool found = false;
  227. f_int_proc = fopen("/proc/interrupts", "r");
  228. if (f_int_proc == NULL) {
  229. printf("Failed to open /proc/interrupts.\n");
  230. return found;
  231. }
  232. while (!feof(f_int_proc) && !found) {
  233. /* Make sure to read a full line at a time */
  234. if (fgets(line, sizeof(line), f_int_proc) == NULL ||
  235. line[strlen(line) - 1] != '\n') {
  236. printf("Error reading from interrupts file\n");
  237. break;
  238. }
  239. /* Extract interrupt number from line */
  240. if (strstr(line, opt_irq_str) != NULL) {
  241. irq_no = atoi(line);
  242. found = true;
  243. break;
  244. }
  245. }
  246. fclose(f_int_proc);
  247. return found;
  248. }
  249. static int get_irqs(void)
  250. {
  251. char count_path[PATH_MAX];
  252. int total_intrs = -1;
  253. FILE *f_count_proc;
  254. char line[4096];
  255. snprintf(count_path, sizeof(count_path),
  256. "/sys/kernel/irq/%i/per_cpu_count", irq_no);
  257. f_count_proc = fopen(count_path, "r");
  258. if (f_count_proc == NULL) {
  259. printf("Failed to open %s\n", count_path);
  260. return total_intrs;
  261. }
  262. if (fgets(line, sizeof(line), f_count_proc) == NULL ||
  263. line[strlen(line) - 1] != '\n') {
  264. printf("Error reading from %s\n", count_path);
  265. } else {
  266. static const char com[2] = ",";
  267. char *token;
  268. total_intrs = 0;
  269. token = strtok(line, com);
  270. while (token != NULL) {
  271. /* sum up interrupts across all cores */
  272. total_intrs += atoi(token);
  273. token = strtok(NULL, com);
  274. }
  275. }
  276. fclose(f_count_proc);
  277. return total_intrs;
  278. }
  279. static void dump_driver_stats(long dt)
  280. {
  281. int i;
  282. for (i = 0; i < num_socks && xsks[i]; i++) {
  283. char *fmt = "%-18s %'-14.0f %'-14lu\n";
  284. double intrs_ps;
  285. int n_ints = get_irqs();
  286. if (n_ints < 0) {
  287. printf("error getting intr info for intr %i\n", irq_no);
  288. return;
  289. }
  290. xsks[i]->drv_stats.intrs = n_ints - irqs_at_init;
  291. intrs_ps = (xsks[i]->drv_stats.intrs - xsks[i]->drv_stats.prev_intrs) *
  292. 1000000000. / dt;
  293. printf("\n%-18s %-14s %-14s\n", "", "intrs/s", "count");
  294. printf(fmt, "irqs", intrs_ps, xsks[i]->drv_stats.intrs);
  295. xsks[i]->drv_stats.prev_intrs = xsks[i]->drv_stats.intrs;
  296. }
  297. }
  298. static void dump_stats(void)
  299. {
  300. unsigned long now = get_nsecs();
  301. long dt = now - prev_time;
  302. int i;
  303. prev_time = now;
  304. for (i = 0; i < num_socks && xsks[i]; i++) {
  305. char *fmt = "%-18s %'-14.0f %'-14lu\n";
  306. double rx_pps, tx_pps, dropped_pps, rx_invalid_pps, full_pps, fill_empty_pps,
  307. tx_invalid_pps, tx_empty_pps;
  308. rx_pps = (xsks[i]->ring_stats.rx_npkts - xsks[i]->ring_stats.prev_rx_npkts) *
  309. 1000000000. / dt;
  310. tx_pps = (xsks[i]->ring_stats.tx_npkts - xsks[i]->ring_stats.prev_tx_npkts) *
  311. 1000000000. / dt;
  312. printf("\n sock%d@", i);
  313. print_benchmark(false);
  314. printf("\n");
  315. printf("%-18s %-14s %-14s %-14.2f\n", "", "pps", "pkts",
  316. dt / 1000000000.);
  317. printf(fmt, "rx", rx_pps, xsks[i]->ring_stats.rx_npkts);
  318. printf(fmt, "tx", tx_pps, xsks[i]->ring_stats.tx_npkts);
  319. xsks[i]->ring_stats.prev_rx_npkts = xsks[i]->ring_stats.rx_npkts;
  320. xsks[i]->ring_stats.prev_tx_npkts = xsks[i]->ring_stats.tx_npkts;
  321. if (opt_extra_stats) {
  322. if (!xsk_get_xdp_stats(xsk_socket__fd(xsks[i]->xsk), xsks[i])) {
  323. dropped_pps = (xsks[i]->ring_stats.rx_dropped_npkts -
  324. xsks[i]->ring_stats.prev_rx_dropped_npkts) *
  325. 1000000000. / dt;
  326. rx_invalid_pps = (xsks[i]->ring_stats.rx_invalid_npkts -
  327. xsks[i]->ring_stats.prev_rx_invalid_npkts) *
  328. 1000000000. / dt;
  329. tx_invalid_pps = (xsks[i]->ring_stats.tx_invalid_npkts -
  330. xsks[i]->ring_stats.prev_tx_invalid_npkts) *
  331. 1000000000. / dt;
  332. full_pps = (xsks[i]->ring_stats.rx_full_npkts -
  333. xsks[i]->ring_stats.prev_rx_full_npkts) *
  334. 1000000000. / dt;
  335. fill_empty_pps = (xsks[i]->ring_stats.rx_fill_empty_npkts -
  336. xsks[i]->ring_stats.prev_rx_fill_empty_npkts) *
  337. 1000000000. / dt;
  338. tx_empty_pps = (xsks[i]->ring_stats.tx_empty_npkts -
  339. xsks[i]->ring_stats.prev_tx_empty_npkts) *
  340. 1000000000. / dt;
  341. printf(fmt, "rx dropped", dropped_pps,
  342. xsks[i]->ring_stats.rx_dropped_npkts);
  343. printf(fmt, "rx invalid", rx_invalid_pps,
  344. xsks[i]->ring_stats.rx_invalid_npkts);
  345. printf(fmt, "tx invalid", tx_invalid_pps,
  346. xsks[i]->ring_stats.tx_invalid_npkts);
  347. printf(fmt, "rx queue full", full_pps,
  348. xsks[i]->ring_stats.rx_full_npkts);
  349. printf(fmt, "fill ring empty", fill_empty_pps,
  350. xsks[i]->ring_stats.rx_fill_empty_npkts);
  351. printf(fmt, "tx ring empty", tx_empty_pps,
  352. xsks[i]->ring_stats.tx_empty_npkts);
  353. xsks[i]->ring_stats.prev_rx_dropped_npkts =
  354. xsks[i]->ring_stats.rx_dropped_npkts;
  355. xsks[i]->ring_stats.prev_rx_invalid_npkts =
  356. xsks[i]->ring_stats.rx_invalid_npkts;
  357. xsks[i]->ring_stats.prev_tx_invalid_npkts =
  358. xsks[i]->ring_stats.tx_invalid_npkts;
  359. xsks[i]->ring_stats.prev_rx_full_npkts =
  360. xsks[i]->ring_stats.rx_full_npkts;
  361. xsks[i]->ring_stats.prev_rx_fill_empty_npkts =
  362. xsks[i]->ring_stats.rx_fill_empty_npkts;
  363. xsks[i]->ring_stats.prev_tx_empty_npkts =
  364. xsks[i]->ring_stats.tx_empty_npkts;
  365. } else {
  366. printf("%-15s\n", "Error retrieving extra stats");
  367. }
  368. }
  369. }
  370. if (opt_app_stats)
  371. dump_app_stats(dt);
  372. if (irq_no)
  373. dump_driver_stats(dt);
  374. }
  375. static bool is_benchmark_done(void)
  376. {
  377. if (opt_duration > 0) {
  378. unsigned long dt = (get_nsecs() - start_time);
  379. if (dt >= opt_duration)
  380. benchmark_done = true;
  381. }
  382. return benchmark_done;
  383. }
  384. static void *poller(void *arg)
  385. {
  386. (void)arg;
  387. while (!is_benchmark_done()) {
  388. sleep(opt_interval);
  389. dump_stats();
  390. }
  391. return NULL;
  392. }
  393. static void remove_xdp_program(void)
  394. {
  395. u32 curr_prog_id = 0;
  396. if (bpf_get_link_xdp_id(opt_ifindex, &curr_prog_id, opt_xdp_flags)) {
  397. printf("bpf_get_link_xdp_id failed\n");
  398. exit(EXIT_FAILURE);
  399. }
  400. if (prog_id == curr_prog_id)
  401. bpf_set_link_xdp_fd(opt_ifindex, -1, opt_xdp_flags);
  402. else if (!curr_prog_id)
  403. printf("couldn't find a prog id on a given interface\n");
  404. else
  405. printf("program on interface changed, not removing\n");
  406. }
  407. static void int_exit(int sig)
  408. {
  409. benchmark_done = true;
  410. }
  411. static void xdpsock_cleanup(void)
  412. {
  413. struct xsk_umem *umem = xsks[0]->umem->umem;
  414. int i;
  415. dump_stats();
  416. for (i = 0; i < num_socks; i++)
  417. xsk_socket__delete(xsks[i]->xsk);
  418. (void)xsk_umem__delete(umem);
  419. remove_xdp_program();
  420. }
  421. static void __exit_with_error(int error, const char *file, const char *func,
  422. int line)
  423. {
  424. fprintf(stderr, "%s:%s:%i: errno: %d/\"%s\"\n", file, func,
  425. line, error, strerror(error));
  426. dump_stats();
  427. remove_xdp_program();
  428. exit(EXIT_FAILURE);
  429. }
  430. #define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, \
  431. __LINE__)
  432. static void swap_mac_addresses(void *data)
  433. {
  434. struct ether_header *eth = (struct ether_header *)data;
  435. struct ether_addr *src_addr = (struct ether_addr *)&eth->ether_shost;
  436. struct ether_addr *dst_addr = (struct ether_addr *)&eth->ether_dhost;
  437. struct ether_addr tmp;
  438. tmp = *src_addr;
  439. *src_addr = *dst_addr;
  440. *dst_addr = tmp;
  441. }
  442. static void hex_dump(void *pkt, size_t length, u64 addr)
  443. {
  444. const unsigned char *address = (unsigned char *)pkt;
  445. const unsigned char *line = address;
  446. size_t line_size = 32;
  447. unsigned char c;
  448. char buf[32];
  449. int i = 0;
  450. if (!DEBUG_HEXDUMP)
  451. return;
  452. sprintf(buf, "addr=%llu", addr);
  453. printf("length = %zu\n", length);
  454. printf("%s | ", buf);
  455. while (length-- > 0) {
  456. printf("%02X ", *address++);
  457. if (!(++i % line_size) || (length == 0 && i % line_size)) {
  458. if (length == 0) {
  459. while (i++ % line_size)
  460. printf("__ ");
  461. }
  462. printf(" | "); /* right close */
  463. while (line < address) {
  464. c = *line++;
  465. printf("%c", (c < 33 || c == 255) ? 0x2E : c);
  466. }
  467. printf("\n");
  468. if (length > 0)
  469. printf("%s | ", buf);
  470. }
  471. }
  472. printf("\n");
  473. }
  474. static void *memset32_htonl(void *dest, u32 val, u32 size)
  475. {
  476. u32 *ptr = (u32 *)dest;
  477. int i;
  478. val = htonl(val);
  479. for (i = 0; i < (size & (~0x3)); i += 4)
  480. ptr[i >> 2] = val;
  481. for (; i < size; i++)
  482. ((char *)dest)[i] = ((char *)&val)[i & 3];
  483. return dest;
  484. }
  485. /*
  486. * This function code has been taken from
  487. * Linux kernel lib/checksum.c
  488. */
  489. static inline unsigned short from32to16(unsigned int x)
  490. {
  491. /* add up 16-bit and 16-bit for 16+c bit */
  492. x = (x & 0xffff) + (x >> 16);
  493. /* add up carry.. */
  494. x = (x & 0xffff) + (x >> 16);
  495. return x;
  496. }
  497. /*
  498. * This function code has been taken from
  499. * Linux kernel lib/checksum.c
  500. */
  501. static unsigned int do_csum(const unsigned char *buff, int len)
  502. {
  503. unsigned int result = 0;
  504. int odd;
  505. if (len <= 0)
  506. goto out;
  507. odd = 1 & (unsigned long)buff;
  508. if (odd) {
  509. #ifdef __LITTLE_ENDIAN
  510. result += (*buff << 8);
  511. #else
  512. result = *buff;
  513. #endif
  514. len--;
  515. buff++;
  516. }
  517. if (len >= 2) {
  518. if (2 & (unsigned long)buff) {
  519. result += *(unsigned short *)buff;
  520. len -= 2;
  521. buff += 2;
  522. }
  523. if (len >= 4) {
  524. const unsigned char *end = buff +
  525. ((unsigned int)len & ~3);
  526. unsigned int carry = 0;
  527. do {
  528. unsigned int w = *(unsigned int *)buff;
  529. buff += 4;
  530. result += carry;
  531. result += w;
  532. carry = (w > result);
  533. } while (buff < end);
  534. result += carry;
  535. result = (result & 0xffff) + (result >> 16);
  536. }
  537. if (len & 2) {
  538. result += *(unsigned short *)buff;
  539. buff += 2;
  540. }
  541. }
  542. if (len & 1)
  543. #ifdef __LITTLE_ENDIAN
  544. result += *buff;
  545. #else
  546. result += (*buff << 8);
  547. #endif
  548. result = from32to16(result);
  549. if (odd)
  550. result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
  551. out:
  552. return result;
  553. }
  554. __sum16 ip_fast_csum(const void *iph, unsigned int ihl);
  555. /*
  556. * This is a version of ip_compute_csum() optimized for IP headers,
  557. * which always checksum on 4 octet boundaries.
  558. * This function code has been taken from
  559. * Linux kernel lib/checksum.c
  560. */
  561. __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
  562. {
  563. return (__force __sum16)~do_csum(iph, ihl * 4);
  564. }
  565. /*
  566. * Fold a partial checksum
  567. * This function code has been taken from
  568. * Linux kernel include/asm-generic/checksum.h
  569. */
  570. static inline __sum16 csum_fold(__wsum csum)
  571. {
  572. u32 sum = (__force u32)csum;
  573. sum = (sum & 0xffff) + (sum >> 16);
  574. sum = (sum & 0xffff) + (sum >> 16);
  575. return (__force __sum16)~sum;
  576. }
  577. /*
  578. * This function code has been taken from
  579. * Linux kernel lib/checksum.c
  580. */
  581. static inline u32 from64to32(u64 x)
  582. {
  583. /* add up 32-bit and 32-bit for 32+c bit */
  584. x = (x & 0xffffffff) + (x >> 32);
  585. /* add up carry.. */
  586. x = (x & 0xffffffff) + (x >> 32);
  587. return (u32)x;
  588. }
  589. __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
  590. __u32 len, __u8 proto, __wsum sum);
  591. /*
  592. * This function code has been taken from
  593. * Linux kernel lib/checksum.c
  594. */
  595. __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
  596. __u32 len, __u8 proto, __wsum sum)
  597. {
  598. unsigned long long s = (__force u32)sum;
  599. s += (__force u32)saddr;
  600. s += (__force u32)daddr;
  601. #ifdef __BIG_ENDIAN__
  602. s += proto + len;
  603. #else
  604. s += (proto + len) << 8;
  605. #endif
  606. return (__force __wsum)from64to32(s);
  607. }
  608. /*
  609. * This function has been taken from
  610. * Linux kernel include/asm-generic/checksum.h
  611. */
  612. static inline __sum16
  613. csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
  614. __u8 proto, __wsum sum)
  615. {
  616. return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
  617. }
  618. static inline u16 udp_csum(u32 saddr, u32 daddr, u32 len,
  619. u8 proto, u16 *udp_pkt)
  620. {
  621. u32 csum = 0;
  622. u32 cnt = 0;
  623. /* udp hdr and data */
  624. for (; cnt < len; cnt += 2)
  625. csum += udp_pkt[cnt >> 1];
  626. return csum_tcpudp_magic(saddr, daddr, len, proto, csum);
  627. }
  628. #define ETH_FCS_SIZE 4
  629. #define PKT_HDR_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \
  630. sizeof(struct udphdr))
  631. #define PKT_SIZE (opt_pkt_size - ETH_FCS_SIZE)
  632. #define IP_PKT_SIZE (PKT_SIZE - sizeof(struct ethhdr))
  633. #define UDP_PKT_SIZE (IP_PKT_SIZE - sizeof(struct iphdr))
  634. #define UDP_PKT_DATA_SIZE (UDP_PKT_SIZE - sizeof(struct udphdr))
  635. static u8 pkt_data[XSK_UMEM__DEFAULT_FRAME_SIZE];
  636. static void gen_eth_hdr_data(void)
  637. {
  638. struct udphdr *udp_hdr = (struct udphdr *)(pkt_data +
  639. sizeof(struct ethhdr) +
  640. sizeof(struct iphdr));
  641. struct iphdr *ip_hdr = (struct iphdr *)(pkt_data +
  642. sizeof(struct ethhdr));
  643. struct ethhdr *eth_hdr = (struct ethhdr *)pkt_data;
  644. /* ethernet header */
  645. memcpy(eth_hdr->h_dest, "\x3c\xfd\xfe\x9e\x7f\x71", ETH_ALEN);
  646. memcpy(eth_hdr->h_source, "\xec\xb1\xd7\x98\x3a\xc0", ETH_ALEN);
  647. eth_hdr->h_proto = htons(ETH_P_IP);
  648. /* IP header */
  649. ip_hdr->version = IPVERSION;
  650. ip_hdr->ihl = 0x5; /* 20 byte header */
  651. ip_hdr->tos = 0x0;
  652. ip_hdr->tot_len = htons(IP_PKT_SIZE);
  653. ip_hdr->id = 0;
  654. ip_hdr->frag_off = 0;
  655. ip_hdr->ttl = IPDEFTTL;
  656. ip_hdr->protocol = IPPROTO_UDP;
  657. ip_hdr->saddr = htonl(0x0a0a0a10);
  658. ip_hdr->daddr = htonl(0x0a0a0a20);
  659. /* IP header checksum */
  660. ip_hdr->check = 0;
  661. ip_hdr->check = ip_fast_csum((const void *)ip_hdr, ip_hdr->ihl);
  662. /* UDP header */
  663. udp_hdr->source = htons(0x1000);
  664. udp_hdr->dest = htons(0x1000);
  665. udp_hdr->len = htons(UDP_PKT_SIZE);
  666. /* UDP data */
  667. memset32_htonl(pkt_data + PKT_HDR_SIZE, opt_pkt_fill_pattern,
  668. UDP_PKT_DATA_SIZE);
  669. /* UDP header checksum */
  670. udp_hdr->check = 0;
  671. udp_hdr->check = udp_csum(ip_hdr->saddr, ip_hdr->daddr, UDP_PKT_SIZE,
  672. IPPROTO_UDP, (u16 *)udp_hdr);
  673. }
  674. static void gen_eth_frame(struct xsk_umem_info *umem, u64 addr)
  675. {
  676. memcpy(xsk_umem__get_data(umem->buffer, addr), pkt_data,
  677. PKT_SIZE);
  678. }
  679. static struct xsk_umem_info *xsk_configure_umem(void *buffer, u64 size)
  680. {
  681. struct xsk_umem_info *umem;
  682. struct xsk_umem_config cfg = {
  683. /* We recommend that you set the fill ring size >= HW RX ring size +
  684. * AF_XDP RX ring size. Make sure you fill up the fill ring
  685. * with buffers at regular intervals, and you will with this setting
  686. * avoid allocation failures in the driver. These are usually quite
  687. * expensive since drivers have not been written to assume that
  688. * allocation failures are common. For regular sockets, kernel
  689. * allocated memory is used that only runs out in OOM situations
  690. * that should be rare.
  691. */
  692. .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS * 2,
  693. .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
  694. .frame_size = opt_xsk_frame_size,
  695. .frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM,
  696. .flags = opt_umem_flags
  697. };
  698. int ret;
  699. umem = calloc(1, sizeof(*umem));
  700. if (!umem)
  701. exit_with_error(errno);
  702. ret = xsk_umem__create(&umem->umem, buffer, size, &umem->fq, &umem->cq,
  703. &cfg);
  704. if (ret)
  705. exit_with_error(-ret);
  706. umem->buffer = buffer;
  707. return umem;
  708. }
  709. static void xsk_populate_fill_ring(struct xsk_umem_info *umem)
  710. {
  711. int ret, i;
  712. u32 idx;
  713. ret = xsk_ring_prod__reserve(&umem->fq,
  714. XSK_RING_PROD__DEFAULT_NUM_DESCS * 2, &idx);
  715. if (ret != XSK_RING_PROD__DEFAULT_NUM_DESCS * 2)
  716. exit_with_error(-ret);
  717. for (i = 0; i < XSK_RING_PROD__DEFAULT_NUM_DESCS * 2; i++)
  718. *xsk_ring_prod__fill_addr(&umem->fq, idx++) =
  719. i * opt_xsk_frame_size;
  720. xsk_ring_prod__submit(&umem->fq, XSK_RING_PROD__DEFAULT_NUM_DESCS * 2);
  721. }
  722. static struct xsk_socket_info *xsk_configure_socket(struct xsk_umem_info *umem,
  723. bool rx, bool tx)
  724. {
  725. struct xsk_socket_config cfg;
  726. struct xsk_socket_info *xsk;
  727. struct xsk_ring_cons *rxr;
  728. struct xsk_ring_prod *txr;
  729. int ret;
  730. xsk = calloc(1, sizeof(*xsk));
  731. if (!xsk)
  732. exit_with_error(errno);
  733. xsk->umem = umem;
  734. cfg.rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
  735. cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
  736. if (opt_num_xsks > 1)
  737. cfg.libbpf_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
  738. else
  739. cfg.libbpf_flags = 0;
  740. cfg.xdp_flags = opt_xdp_flags;
  741. cfg.bind_flags = opt_xdp_bind_flags;
  742. rxr = rx ? &xsk->rx : NULL;
  743. txr = tx ? &xsk->tx : NULL;
  744. ret = xsk_socket__create(&xsk->xsk, opt_if, opt_queue, umem->umem,
  745. rxr, txr, &cfg);
  746. if (ret)
  747. exit_with_error(-ret);
  748. ret = bpf_get_link_xdp_id(opt_ifindex, &prog_id, opt_xdp_flags);
  749. if (ret)
  750. exit_with_error(-ret);
  751. xsk->app_stats.rx_empty_polls = 0;
  752. xsk->app_stats.fill_fail_polls = 0;
  753. xsk->app_stats.copy_tx_sendtos = 0;
  754. xsk->app_stats.tx_wakeup_sendtos = 0;
  755. xsk->app_stats.opt_polls = 0;
  756. xsk->app_stats.prev_rx_empty_polls = 0;
  757. xsk->app_stats.prev_fill_fail_polls = 0;
  758. xsk->app_stats.prev_copy_tx_sendtos = 0;
  759. xsk->app_stats.prev_tx_wakeup_sendtos = 0;
  760. xsk->app_stats.prev_opt_polls = 0;
  761. return xsk;
  762. }
  763. static struct option long_options[] = {
  764. {"rxdrop", no_argument, 0, 'r'},
  765. {"txonly", no_argument, 0, 't'},
  766. {"l2fwd", no_argument, 0, 'l'},
  767. {"interface", required_argument, 0, 'i'},
  768. {"queue", required_argument, 0, 'q'},
  769. {"poll", no_argument, 0, 'p'},
  770. {"xdp-skb", no_argument, 0, 'S'},
  771. {"xdp-native", no_argument, 0, 'N'},
  772. {"interval", required_argument, 0, 'n'},
  773. {"zero-copy", no_argument, 0, 'z'},
  774. {"copy", no_argument, 0, 'c'},
  775. {"frame-size", required_argument, 0, 'f'},
  776. {"no-need-wakeup", no_argument, 0, 'm'},
  777. {"unaligned", no_argument, 0, 'u'},
  778. {"shared-umem", no_argument, 0, 'M'},
  779. {"force", no_argument, 0, 'F'},
  780. {"duration", required_argument, 0, 'd'},
  781. {"batch-size", required_argument, 0, 'b'},
  782. {"tx-pkt-count", required_argument, 0, 'C'},
  783. {"tx-pkt-size", required_argument, 0, 's'},
  784. {"tx-pkt-pattern", required_argument, 0, 'P'},
  785. {"extra-stats", no_argument, 0, 'x'},
  786. {"quiet", no_argument, 0, 'Q'},
  787. {"app-stats", no_argument, 0, 'a'},
  788. {"irq-string", no_argument, 0, 'I'},
  789. {0, 0, 0, 0}
  790. };
  791. static void usage(const char *prog)
  792. {
  793. const char *str =
  794. " Usage: %s [OPTIONS]\n"
  795. " Options:\n"
  796. " -r, --rxdrop Discard all incoming packets (default)\n"
  797. " -t, --txonly Only send packets\n"
  798. " -l, --l2fwd MAC swap L2 forwarding\n"
  799. " -i, --interface=n Run on interface n\n"
  800. " -q, --queue=n Use queue n (default 0)\n"
  801. " -p, --poll Use poll syscall\n"
  802. " -S, --xdp-skb=n Use XDP skb-mod\n"
  803. " -N, --xdp-native=n Enforce XDP native mode\n"
  804. " -n, --interval=n Specify statistics update interval (default 1 sec).\n"
  805. " -z, --zero-copy Force zero-copy mode.\n"
  806. " -c, --copy Force copy mode.\n"
  807. " -m, --no-need-wakeup Turn off use of driver need wakeup flag.\n"
  808. " -f, --frame-size=n Set the frame size (must be a power of two in aligned mode, default is %d).\n"
  809. " -u, --unaligned Enable unaligned chunk placement\n"
  810. " -M, --shared-umem Enable XDP_SHARED_UMEM\n"
  811. " -F, --force Force loading the XDP prog\n"
  812. " -d, --duration=n Duration in secs to run command.\n"
  813. " Default: forever.\n"
  814. " -b, --batch-size=n Batch size for sending or receiving\n"
  815. " packets. Default: %d\n"
  816. " -C, --tx-pkt-count=n Number of packets to send.\n"
  817. " Default: Continuous packets.\n"
  818. " -s, --tx-pkt-size=n Transmit packet size.\n"
  819. " (Default: %d bytes)\n"
  820. " Min size: %d, Max size %d.\n"
  821. " -P, --tx-pkt-pattern=nPacket fill pattern. Default: 0x%x\n"
  822. " -x, --extra-stats Display extra statistics.\n"
  823. " -Q, --quiet Do not display any stats.\n"
  824. " -a, --app-stats Display application (syscall) statistics.\n"
  825. " -I, --irq-string Display driver interrupt statistics for interface associated with irq-string.\n"
  826. "\n";
  827. fprintf(stderr, str, prog, XSK_UMEM__DEFAULT_FRAME_SIZE,
  828. opt_batch_size, MIN_PKT_SIZE, MIN_PKT_SIZE,
  829. XSK_UMEM__DEFAULT_FRAME_SIZE, opt_pkt_fill_pattern);
  830. exit(EXIT_FAILURE);
  831. }
  832. static void parse_command_line(int argc, char **argv)
  833. {
  834. int option_index, c;
  835. opterr = 0;
  836. for (;;) {
  837. c = getopt_long(argc, argv, "Frtli:q:pSNn:czf:muMd:b:C:s:P:xQaI:",
  838. long_options, &option_index);
  839. if (c == -1)
  840. break;
  841. switch (c) {
  842. case 'r':
  843. opt_bench = BENCH_RXDROP;
  844. break;
  845. case 't':
  846. opt_bench = BENCH_TXONLY;
  847. break;
  848. case 'l':
  849. opt_bench = BENCH_L2FWD;
  850. break;
  851. case 'i':
  852. opt_if = optarg;
  853. break;
  854. case 'q':
  855. opt_queue = atoi(optarg);
  856. break;
  857. case 'p':
  858. opt_poll = 1;
  859. break;
  860. case 'S':
  861. opt_xdp_flags |= XDP_FLAGS_SKB_MODE;
  862. opt_xdp_bind_flags |= XDP_COPY;
  863. break;
  864. case 'N':
  865. /* default, set below */
  866. break;
  867. case 'n':
  868. opt_interval = atoi(optarg);
  869. break;
  870. case 'z':
  871. opt_xdp_bind_flags |= XDP_ZEROCOPY;
  872. break;
  873. case 'c':
  874. opt_xdp_bind_flags |= XDP_COPY;
  875. break;
  876. case 'u':
  877. opt_umem_flags |= XDP_UMEM_UNALIGNED_CHUNK_FLAG;
  878. opt_unaligned_chunks = 1;
  879. opt_mmap_flags = MAP_HUGETLB;
  880. break;
  881. case 'F':
  882. opt_xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
  883. break;
  884. case 'f':
  885. opt_xsk_frame_size = atoi(optarg);
  886. break;
  887. case 'm':
  888. opt_need_wakeup = false;
  889. opt_xdp_bind_flags &= ~XDP_USE_NEED_WAKEUP;
  890. break;
  891. case 'M':
  892. opt_num_xsks = MAX_SOCKS;
  893. break;
  894. case 'd':
  895. opt_duration = atoi(optarg);
  896. opt_duration *= 1000000000;
  897. break;
  898. case 'b':
  899. opt_batch_size = atoi(optarg);
  900. break;
  901. case 'C':
  902. opt_pkt_count = atoi(optarg);
  903. break;
  904. case 's':
  905. opt_pkt_size = atoi(optarg);
  906. if (opt_pkt_size > (XSK_UMEM__DEFAULT_FRAME_SIZE) ||
  907. opt_pkt_size < MIN_PKT_SIZE) {
  908. fprintf(stderr,
  909. "ERROR: Invalid frame size %d\n",
  910. opt_pkt_size);
  911. usage(basename(argv[0]));
  912. }
  913. break;
  914. case 'P':
  915. opt_pkt_fill_pattern = strtol(optarg, NULL, 16);
  916. break;
  917. case 'x':
  918. opt_extra_stats = 1;
  919. break;
  920. case 'Q':
  921. opt_quiet = 1;
  922. break;
  923. case 'a':
  924. opt_app_stats = 1;
  925. break;
  926. case 'I':
  927. opt_irq_str = optarg;
  928. if (get_interrupt_number())
  929. irqs_at_init = get_irqs();
  930. if (irqs_at_init < 0) {
  931. fprintf(stderr, "ERROR: Failed to get irqs for %s\n", opt_irq_str);
  932. usage(basename(argv[0]));
  933. }
  934. break;
  935. default:
  936. usage(basename(argv[0]));
  937. }
  938. }
  939. if (!(opt_xdp_flags & XDP_FLAGS_SKB_MODE))
  940. opt_xdp_flags |= XDP_FLAGS_DRV_MODE;
  941. opt_ifindex = if_nametoindex(opt_if);
  942. if (!opt_ifindex) {
  943. fprintf(stderr, "ERROR: interface \"%s\" does not exist\n",
  944. opt_if);
  945. usage(basename(argv[0]));
  946. }
  947. if ((opt_xsk_frame_size & (opt_xsk_frame_size - 1)) &&
  948. !opt_unaligned_chunks) {
  949. fprintf(stderr, "--frame-size=%d is not a power of two\n",
  950. opt_xsk_frame_size);
  951. usage(basename(argv[0]));
  952. }
  953. }
  954. static void kick_tx(struct xsk_socket_info *xsk)
  955. {
  956. int ret;
  957. ret = sendto(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0);
  958. if (ret >= 0 || errno == ENOBUFS || errno == EAGAIN ||
  959. errno == EBUSY || errno == ENETDOWN)
  960. return;
  961. exit_with_error(errno);
  962. }
  963. static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk,
  964. struct pollfd *fds)
  965. {
  966. struct xsk_umem_info *umem = xsk->umem;
  967. u32 idx_cq = 0, idx_fq = 0;
  968. unsigned int rcvd;
  969. size_t ndescs;
  970. if (!xsk->outstanding_tx)
  971. return;
  972. /* In copy mode, Tx is driven by a syscall so we need to use e.g. sendto() to
  973. * really send the packets. In zero-copy mode we do not have to do this, since Tx
  974. * is driven by the NAPI loop. So as an optimization, we do not have to call
  975. * sendto() all the time in zero-copy mode for l2fwd.
  976. */
  977. if (opt_xdp_bind_flags & XDP_COPY) {
  978. xsk->app_stats.copy_tx_sendtos++;
  979. kick_tx(xsk);
  980. }
  981. ndescs = (xsk->outstanding_tx > opt_batch_size) ? opt_batch_size :
  982. xsk->outstanding_tx;
  983. /* re-add completed Tx buffers */
  984. rcvd = xsk_ring_cons__peek(&umem->cq, ndescs, &idx_cq);
  985. if (rcvd > 0) {
  986. unsigned int i;
  987. int ret;
  988. ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq);
  989. while (ret != rcvd) {
  990. if (ret < 0)
  991. exit_with_error(-ret);
  992. if (xsk_ring_prod__needs_wakeup(&umem->fq)) {
  993. xsk->app_stats.fill_fail_polls++;
  994. ret = poll(fds, num_socks, opt_timeout);
  995. }
  996. ret = xsk_ring_prod__reserve(&umem->fq, rcvd, &idx_fq);
  997. }
  998. for (i = 0; i < rcvd; i++)
  999. *xsk_ring_prod__fill_addr(&umem->fq, idx_fq++) =
  1000. *xsk_ring_cons__comp_addr(&umem->cq, idx_cq++);
  1001. xsk_ring_prod__submit(&xsk->umem->fq, rcvd);
  1002. xsk_ring_cons__release(&xsk->umem->cq, rcvd);
  1003. xsk->outstanding_tx -= rcvd;
  1004. xsk->ring_stats.tx_npkts += rcvd;
  1005. }
  1006. }
  1007. static inline void complete_tx_only(struct xsk_socket_info *xsk,
  1008. int batch_size)
  1009. {
  1010. unsigned int rcvd;
  1011. u32 idx;
  1012. if (!xsk->outstanding_tx)
  1013. return;
  1014. if (!opt_need_wakeup || xsk_ring_prod__needs_wakeup(&xsk->tx)) {
  1015. xsk->app_stats.tx_wakeup_sendtos++;
  1016. kick_tx(xsk);
  1017. }
  1018. rcvd = xsk_ring_cons__peek(&xsk->umem->cq, batch_size, &idx);
  1019. if (rcvd > 0) {
  1020. xsk_ring_cons__release(&xsk->umem->cq, rcvd);
  1021. xsk->outstanding_tx -= rcvd;
  1022. xsk->ring_stats.tx_npkts += rcvd;
  1023. }
  1024. }
  1025. static void rx_drop(struct xsk_socket_info *xsk, struct pollfd *fds)
  1026. {
  1027. unsigned int rcvd, i;
  1028. u32 idx_rx = 0, idx_fq = 0;
  1029. int ret;
  1030. rcvd = xsk_ring_cons__peek(&xsk->rx, opt_batch_size, &idx_rx);
  1031. if (!rcvd) {
  1032. if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
  1033. xsk->app_stats.rx_empty_polls++;
  1034. ret = poll(fds, num_socks, opt_timeout);
  1035. }
  1036. return;
  1037. }
  1038. ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
  1039. while (ret != rcvd) {
  1040. if (ret < 0)
  1041. exit_with_error(-ret);
  1042. if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
  1043. xsk->app_stats.fill_fail_polls++;
  1044. ret = poll(fds, num_socks, opt_timeout);
  1045. }
  1046. ret = xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
  1047. }
  1048. for (i = 0; i < rcvd; i++) {
  1049. u64 addr = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx)->addr;
  1050. u32 len = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++)->len;
  1051. u64 orig = xsk_umem__extract_addr(addr);
  1052. addr = xsk_umem__add_offset_to_addr(addr);
  1053. char *pkt = xsk_umem__get_data(xsk->umem->buffer, addr);
  1054. hex_dump(pkt, len, addr);
  1055. *xsk_ring_prod__fill_addr(&xsk->umem->fq, idx_fq++) = orig;
  1056. }
  1057. xsk_ring_prod__submit(&xsk->umem->fq, rcvd);
  1058. xsk_ring_cons__release(&xsk->rx, rcvd);
  1059. xsk->ring_stats.rx_npkts += rcvd;
  1060. }
  1061. static void rx_drop_all(void)
  1062. {
  1063. struct pollfd fds[MAX_SOCKS] = {};
  1064. int i, ret;
  1065. for (i = 0; i < num_socks; i++) {
  1066. fds[i].fd = xsk_socket__fd(xsks[i]->xsk);
  1067. fds[i].events = POLLIN;
  1068. }
  1069. for (;;) {
  1070. if (opt_poll) {
  1071. for (i = 0; i < num_socks; i++)
  1072. xsks[i]->app_stats.opt_polls++;
  1073. ret = poll(fds, num_socks, opt_timeout);
  1074. if (ret <= 0)
  1075. continue;
  1076. }
  1077. for (i = 0; i < num_socks; i++)
  1078. rx_drop(xsks[i], fds);
  1079. if (benchmark_done)
  1080. break;
  1081. }
  1082. }
  1083. static void tx_only(struct xsk_socket_info *xsk, u32 *frame_nb, int batch_size)
  1084. {
  1085. u32 idx;
  1086. unsigned int i;
  1087. while (xsk_ring_prod__reserve(&xsk->tx, batch_size, &idx) <
  1088. batch_size) {
  1089. complete_tx_only(xsk, batch_size);
  1090. if (benchmark_done)
  1091. return;
  1092. }
  1093. for (i = 0; i < batch_size; i++) {
  1094. struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx,
  1095. idx + i);
  1096. tx_desc->addr = (*frame_nb + i) * opt_xsk_frame_size;
  1097. tx_desc->len = PKT_SIZE;
  1098. }
  1099. xsk_ring_prod__submit(&xsk->tx, batch_size);
  1100. xsk->outstanding_tx += batch_size;
  1101. *frame_nb += batch_size;
  1102. *frame_nb %= NUM_FRAMES;
  1103. complete_tx_only(xsk, batch_size);
  1104. }
  1105. static inline int get_batch_size(int pkt_cnt)
  1106. {
  1107. if (!opt_pkt_count)
  1108. return opt_batch_size;
  1109. if (pkt_cnt + opt_batch_size <= opt_pkt_count)
  1110. return opt_batch_size;
  1111. return opt_pkt_count - pkt_cnt;
  1112. }
  1113. static void complete_tx_only_all(void)
  1114. {
  1115. bool pending;
  1116. int i;
  1117. do {
  1118. pending = false;
  1119. for (i = 0; i < num_socks; i++) {
  1120. if (xsks[i]->outstanding_tx) {
  1121. complete_tx_only(xsks[i], opt_batch_size);
  1122. pending = !!xsks[i]->outstanding_tx;
  1123. }
  1124. }
  1125. } while (pending);
  1126. }
  1127. static void tx_only_all(void)
  1128. {
  1129. struct pollfd fds[MAX_SOCKS] = {};
  1130. u32 frame_nb[MAX_SOCKS] = {};
  1131. int pkt_cnt = 0;
  1132. int i, ret;
  1133. for (i = 0; i < num_socks; i++) {
  1134. fds[0].fd = xsk_socket__fd(xsks[i]->xsk);
  1135. fds[0].events = POLLOUT;
  1136. }
  1137. while ((opt_pkt_count && pkt_cnt < opt_pkt_count) || !opt_pkt_count) {
  1138. int batch_size = get_batch_size(pkt_cnt);
  1139. if (opt_poll) {
  1140. for (i = 0; i < num_socks; i++)
  1141. xsks[i]->app_stats.opt_polls++;
  1142. ret = poll(fds, num_socks, opt_timeout);
  1143. if (ret <= 0)
  1144. continue;
  1145. if (!(fds[0].revents & POLLOUT))
  1146. continue;
  1147. }
  1148. for (i = 0; i < num_socks; i++)
  1149. tx_only(xsks[i], &frame_nb[i], batch_size);
  1150. pkt_cnt += batch_size;
  1151. if (benchmark_done)
  1152. break;
  1153. }
  1154. if (opt_pkt_count)
  1155. complete_tx_only_all();
  1156. }
  1157. static void l2fwd(struct xsk_socket_info *xsk, struct pollfd *fds)
  1158. {
  1159. unsigned int rcvd, i;
  1160. u32 idx_rx = 0, idx_tx = 0;
  1161. int ret;
  1162. complete_tx_l2fwd(xsk, fds);
  1163. rcvd = xsk_ring_cons__peek(&xsk->rx, opt_batch_size, &idx_rx);
  1164. if (!rcvd) {
  1165. if (xsk_ring_prod__needs_wakeup(&xsk->umem->fq)) {
  1166. xsk->app_stats.rx_empty_polls++;
  1167. ret = poll(fds, num_socks, opt_timeout);
  1168. }
  1169. return;
  1170. }
  1171. ret = xsk_ring_prod__reserve(&xsk->tx, rcvd, &idx_tx);
  1172. while (ret != rcvd) {
  1173. if (ret < 0)
  1174. exit_with_error(-ret);
  1175. complete_tx_l2fwd(xsk, fds);
  1176. if (xsk_ring_prod__needs_wakeup(&xsk->tx)) {
  1177. xsk->app_stats.tx_wakeup_sendtos++;
  1178. kick_tx(xsk);
  1179. }
  1180. ret = xsk_ring_prod__reserve(&xsk->tx, rcvd, &idx_tx);
  1181. }
  1182. for (i = 0; i < rcvd; i++) {
  1183. u64 addr = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx)->addr;
  1184. u32 len = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++)->len;
  1185. u64 orig = addr;
  1186. addr = xsk_umem__add_offset_to_addr(addr);
  1187. char *pkt = xsk_umem__get_data(xsk->umem->buffer, addr);
  1188. swap_mac_addresses(pkt);
  1189. hex_dump(pkt, len, addr);
  1190. xsk_ring_prod__tx_desc(&xsk->tx, idx_tx)->addr = orig;
  1191. xsk_ring_prod__tx_desc(&xsk->tx, idx_tx++)->len = len;
  1192. }
  1193. xsk_ring_prod__submit(&xsk->tx, rcvd);
  1194. xsk_ring_cons__release(&xsk->rx, rcvd);
  1195. xsk->ring_stats.rx_npkts += rcvd;
  1196. xsk->outstanding_tx += rcvd;
  1197. }
  1198. static void l2fwd_all(void)
  1199. {
  1200. struct pollfd fds[MAX_SOCKS] = {};
  1201. int i, ret;
  1202. for (i = 0; i < num_socks; i++) {
  1203. fds[i].fd = xsk_socket__fd(xsks[i]->xsk);
  1204. fds[i].events = POLLOUT | POLLIN;
  1205. }
  1206. for (;;) {
  1207. if (opt_poll) {
  1208. for (i = 0; i < num_socks; i++)
  1209. xsks[i]->app_stats.opt_polls++;
  1210. ret = poll(fds, num_socks, opt_timeout);
  1211. if (ret <= 0)
  1212. continue;
  1213. }
  1214. for (i = 0; i < num_socks; i++)
  1215. l2fwd(xsks[i], fds);
  1216. if (benchmark_done)
  1217. break;
  1218. }
  1219. }
  1220. static void load_xdp_program(char **argv, struct bpf_object **obj)
  1221. {
  1222. struct bpf_prog_load_attr prog_load_attr = {
  1223. .prog_type = BPF_PROG_TYPE_XDP,
  1224. };
  1225. char xdp_filename[256];
  1226. int prog_fd;
  1227. snprintf(xdp_filename, sizeof(xdp_filename), "%s_kern.o", argv[0]);
  1228. prog_load_attr.file = xdp_filename;
  1229. if (bpf_prog_load_xattr(&prog_load_attr, obj, &prog_fd))
  1230. exit(EXIT_FAILURE);
  1231. if (prog_fd < 0) {
  1232. fprintf(stderr, "ERROR: no program found: %s\n",
  1233. strerror(prog_fd));
  1234. exit(EXIT_FAILURE);
  1235. }
  1236. if (bpf_set_link_xdp_fd(opt_ifindex, prog_fd, opt_xdp_flags) < 0) {
  1237. fprintf(stderr, "ERROR: link set xdp fd failed\n");
  1238. exit(EXIT_FAILURE);
  1239. }
  1240. }
  1241. static void enter_xsks_into_map(struct bpf_object *obj)
  1242. {
  1243. struct bpf_map *map;
  1244. int i, xsks_map;
  1245. map = bpf_object__find_map_by_name(obj, "xsks_map");
  1246. xsks_map = bpf_map__fd(map);
  1247. if (xsks_map < 0) {
  1248. fprintf(stderr, "ERROR: no xsks map found: %s\n",
  1249. strerror(xsks_map));
  1250. exit(EXIT_FAILURE);
  1251. }
  1252. for (i = 0; i < num_socks; i++) {
  1253. int fd = xsk_socket__fd(xsks[i]->xsk);
  1254. int key, ret;
  1255. key = i;
  1256. ret = bpf_map_update_elem(xsks_map, &key, &fd, 0);
  1257. if (ret) {
  1258. fprintf(stderr, "ERROR: bpf_map_update_elem %d\n", i);
  1259. exit(EXIT_FAILURE);
  1260. }
  1261. }
  1262. }
  1263. int main(int argc, char **argv)
  1264. {
  1265. struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
  1266. bool rx = false, tx = false;
  1267. struct xsk_umem_info *umem;
  1268. struct bpf_object *obj;
  1269. pthread_t pt;
  1270. int i, ret;
  1271. void *bufs;
  1272. parse_command_line(argc, argv);
  1273. if (setrlimit(RLIMIT_MEMLOCK, &r)) {
  1274. fprintf(stderr, "ERROR: setrlimit(RLIMIT_MEMLOCK) \"%s\"\n",
  1275. strerror(errno));
  1276. exit(EXIT_FAILURE);
  1277. }
  1278. if (opt_num_xsks > 1)
  1279. load_xdp_program(argv, &obj);
  1280. /* Reserve memory for the umem. Use hugepages if unaligned chunk mode */
  1281. bufs = mmap(NULL, NUM_FRAMES * opt_xsk_frame_size,
  1282. PROT_READ | PROT_WRITE,
  1283. MAP_PRIVATE | MAP_ANONYMOUS | opt_mmap_flags, -1, 0);
  1284. if (bufs == MAP_FAILED) {
  1285. printf("ERROR: mmap failed\n");
  1286. exit(EXIT_FAILURE);
  1287. }
  1288. /* Create sockets... */
  1289. umem = xsk_configure_umem(bufs, NUM_FRAMES * opt_xsk_frame_size);
  1290. if (opt_bench == BENCH_RXDROP || opt_bench == BENCH_L2FWD) {
  1291. rx = true;
  1292. xsk_populate_fill_ring(umem);
  1293. }
  1294. if (opt_bench == BENCH_L2FWD || opt_bench == BENCH_TXONLY)
  1295. tx = true;
  1296. for (i = 0; i < opt_num_xsks; i++)
  1297. xsks[num_socks++] = xsk_configure_socket(umem, rx, tx);
  1298. if (opt_bench == BENCH_TXONLY) {
  1299. gen_eth_hdr_data();
  1300. for (i = 0; i < NUM_FRAMES; i++)
  1301. gen_eth_frame(umem, i * opt_xsk_frame_size);
  1302. }
  1303. if (opt_num_xsks > 1 && opt_bench != BENCH_TXONLY)
  1304. enter_xsks_into_map(obj);
  1305. signal(SIGINT, int_exit);
  1306. signal(SIGTERM, int_exit);
  1307. signal(SIGABRT, int_exit);
  1308. setlocale(LC_ALL, "");
  1309. prev_time = get_nsecs();
  1310. start_time = prev_time;
  1311. if (!opt_quiet) {
  1312. ret = pthread_create(&pt, NULL, poller, NULL);
  1313. if (ret)
  1314. exit_with_error(ret);
  1315. }
  1316. if (opt_bench == BENCH_RXDROP)
  1317. rx_drop_all();
  1318. else if (opt_bench == BENCH_TXONLY)
  1319. tx_only_all();
  1320. else
  1321. l2fwd_all();
  1322. benchmark_done = true;
  1323. if (!opt_quiet)
  1324. pthread_join(pt, NULL);
  1325. xdpsock_cleanup();
  1326. munmap(bufs, NUM_FRAMES * opt_xsk_frame_size);
  1327. return 0;
  1328. }