xdp_features.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <uapi/linux/bpf.h>
  3. #include <uapi/linux/netdev.h>
  4. #include <linux/if_link.h>
  5. #include <signal.h>
  6. #include <argp.h>
  7. #include <net/if.h>
  8. #include <sys/socket.h>
  9. #include <netinet/in.h>
  10. #include <netinet/tcp.h>
  11. #include <unistd.h>
  12. #include <arpa/inet.h>
  13. #include <bpf/bpf.h>
  14. #include <bpf/libbpf.h>
  15. #include <pthread.h>
  16. #include <network_helpers.h>
  17. #include "xdp_features.skel.h"
  18. #include "xdp_features.h"
  19. #define RED(str) "\033[0;31m" str "\033[0m"
  20. #define GREEN(str) "\033[0;32m" str "\033[0m"
  21. #define YELLOW(str) "\033[0;33m" str "\033[0m"
  22. static struct env {
  23. bool verbosity;
  24. char ifname[IF_NAMESIZE];
  25. int ifindex;
  26. bool is_tester;
  27. struct {
  28. enum netdev_xdp_act drv_feature;
  29. enum xdp_action action;
  30. } feature;
  31. struct sockaddr_storage dut_ctrl_addr;
  32. struct sockaddr_storage dut_addr;
  33. struct sockaddr_storage tester_addr;
  34. } env;
  35. #define BUFSIZE 128
  36. void test__fail(void) { /* for network_helpers.c */ }
  37. static int libbpf_print_fn(enum libbpf_print_level level,
  38. const char *format, va_list args)
  39. {
  40. if (level == LIBBPF_DEBUG && !env.verbosity)
  41. return 0;
  42. return vfprintf(stderr, format, args);
  43. }
  44. static volatile bool exiting;
  45. static void sig_handler(int sig)
  46. {
  47. exiting = true;
  48. }
  49. const char *argp_program_version = "xdp-features 0.0";
  50. const char argp_program_doc[] =
  51. "XDP features detection application.\n"
  52. "\n"
  53. "XDP features application checks the XDP advertised features match detected ones.\n"
  54. "\n"
  55. "USAGE: ./xdp-features [-vt] [-f <xdp-feature>] [-D <dut-data-ip>] [-T <tester-data-ip>] [-C <dut-ctrl-ip>] <iface-name>\n"
  56. "\n"
  57. "dut-data-ip, tester-data-ip, dut-ctrl-ip: IPv6 or IPv4-mapped-IPv6 addresses;\n"
  58. "\n"
  59. "XDP features\n:"
  60. "- XDP_PASS\n"
  61. "- XDP_DROP\n"
  62. "- XDP_ABORTED\n"
  63. "- XDP_REDIRECT\n"
  64. "- XDP_NDO_XMIT\n"
  65. "- XDP_TX\n";
  66. static const struct argp_option opts[] = {
  67. { "verbose", 'v', NULL, 0, "Verbose debug output" },
  68. { "tester", 't', NULL, 0, "Tester mode" },
  69. { "feature", 'f', "XDP-FEATURE", 0, "XDP feature to test" },
  70. { "dut_data_ip", 'D', "DUT-DATA-IP", 0, "DUT IP data channel" },
  71. { "dut_ctrl_ip", 'C', "DUT-CTRL-IP", 0, "DUT IP control channel" },
  72. { "tester_data_ip", 'T', "TESTER-DATA-IP", 0, "Tester IP data channel" },
  73. {},
  74. };
  75. static int get_xdp_feature(const char *arg)
  76. {
  77. if (!strcmp(arg, "XDP_PASS")) {
  78. env.feature.action = XDP_PASS;
  79. env.feature.drv_feature = NETDEV_XDP_ACT_BASIC;
  80. } else if (!strcmp(arg, "XDP_DROP")) {
  81. env.feature.drv_feature = NETDEV_XDP_ACT_BASIC;
  82. env.feature.action = XDP_DROP;
  83. } else if (!strcmp(arg, "XDP_ABORTED")) {
  84. env.feature.drv_feature = NETDEV_XDP_ACT_BASIC;
  85. env.feature.action = XDP_ABORTED;
  86. } else if (!strcmp(arg, "XDP_TX")) {
  87. env.feature.drv_feature = NETDEV_XDP_ACT_BASIC;
  88. env.feature.action = XDP_TX;
  89. } else if (!strcmp(arg, "XDP_REDIRECT")) {
  90. env.feature.drv_feature = NETDEV_XDP_ACT_REDIRECT;
  91. env.feature.action = XDP_REDIRECT;
  92. } else if (!strcmp(arg, "XDP_NDO_XMIT")) {
  93. env.feature.drv_feature = NETDEV_XDP_ACT_NDO_XMIT;
  94. } else {
  95. return -EINVAL;
  96. }
  97. return 0;
  98. }
  99. static char *get_xdp_feature_str(void)
  100. {
  101. switch (env.feature.action) {
  102. case XDP_PASS:
  103. return YELLOW("XDP_PASS");
  104. case XDP_DROP:
  105. return YELLOW("XDP_DROP");
  106. case XDP_ABORTED:
  107. return YELLOW("XDP_ABORTED");
  108. case XDP_TX:
  109. return YELLOW("XDP_TX");
  110. case XDP_REDIRECT:
  111. return YELLOW("XDP_REDIRECT");
  112. default:
  113. break;
  114. }
  115. if (env.feature.drv_feature == NETDEV_XDP_ACT_NDO_XMIT)
  116. return YELLOW("XDP_NDO_XMIT");
  117. return "";
  118. }
  119. static error_t parse_arg(int key, char *arg, struct argp_state *state)
  120. {
  121. switch (key) {
  122. case 'v':
  123. env.verbosity = true;
  124. break;
  125. case 't':
  126. env.is_tester = true;
  127. break;
  128. case 'f':
  129. if (get_xdp_feature(arg) < 0) {
  130. fprintf(stderr, "Invalid xdp feature: %s\n", arg);
  131. argp_usage(state);
  132. return ARGP_ERR_UNKNOWN;
  133. }
  134. break;
  135. case 'D':
  136. if (make_sockaddr(AF_INET6, arg, DUT_ECHO_PORT,
  137. &env.dut_addr, NULL)) {
  138. fprintf(stderr,
  139. "Invalid address assigned to the Device Under Test: %s\n",
  140. arg);
  141. return ARGP_ERR_UNKNOWN;
  142. }
  143. break;
  144. case 'C':
  145. if (make_sockaddr(AF_INET6, arg, DUT_CTRL_PORT,
  146. &env.dut_ctrl_addr, NULL)) {
  147. fprintf(stderr,
  148. "Invalid address assigned to the Device Under Test: %s\n",
  149. arg);
  150. return ARGP_ERR_UNKNOWN;
  151. }
  152. break;
  153. case 'T':
  154. if (make_sockaddr(AF_INET6, arg, 0, &env.tester_addr, NULL)) {
  155. fprintf(stderr,
  156. "Invalid address assigned to the Tester device: %s\n",
  157. arg);
  158. return ARGP_ERR_UNKNOWN;
  159. }
  160. break;
  161. case ARGP_KEY_ARG:
  162. errno = 0;
  163. if (strlen(arg) >= IF_NAMESIZE) {
  164. fprintf(stderr, "Invalid device name: %s\n", arg);
  165. argp_usage(state);
  166. return ARGP_ERR_UNKNOWN;
  167. }
  168. env.ifindex = if_nametoindex(arg);
  169. if (!env.ifindex)
  170. env.ifindex = strtoul(arg, NULL, 0);
  171. if (!env.ifindex || !if_indextoname(env.ifindex, env.ifname)) {
  172. fprintf(stderr,
  173. "Bad interface index or name (%d): %s\n",
  174. errno, strerror(errno));
  175. argp_usage(state);
  176. return ARGP_ERR_UNKNOWN;
  177. }
  178. break;
  179. default:
  180. return ARGP_ERR_UNKNOWN;
  181. }
  182. return 0;
  183. }
  184. static const struct argp argp = {
  185. .options = opts,
  186. .parser = parse_arg,
  187. .doc = argp_program_doc,
  188. };
  189. static void set_env_default(void)
  190. {
  191. env.feature.drv_feature = NETDEV_XDP_ACT_NDO_XMIT;
  192. env.feature.action = -EINVAL;
  193. env.ifindex = -ENODEV;
  194. strcpy(env.ifname, "unknown");
  195. make_sockaddr(AF_INET6, "::ffff:127.0.0.1", DUT_CTRL_PORT,
  196. &env.dut_ctrl_addr, NULL);
  197. make_sockaddr(AF_INET6, "::ffff:127.0.0.1", DUT_ECHO_PORT,
  198. &env.dut_addr, NULL);
  199. make_sockaddr(AF_INET6, "::ffff:127.0.0.1", 0, &env.tester_addr, NULL);
  200. }
  201. static void *dut_echo_thread(void *arg)
  202. {
  203. unsigned char buf[sizeof(struct tlv_hdr)];
  204. int sockfd = *(int *)arg;
  205. while (!exiting) {
  206. struct tlv_hdr *tlv = (struct tlv_hdr *)buf;
  207. struct sockaddr_storage addr;
  208. socklen_t addrlen;
  209. size_t n;
  210. n = recvfrom(sockfd, buf, sizeof(buf), MSG_WAITALL,
  211. (struct sockaddr *)&addr, &addrlen);
  212. if (n != ntohs(tlv->len))
  213. continue;
  214. if (ntohs(tlv->type) != CMD_ECHO)
  215. continue;
  216. sendto(sockfd, buf, sizeof(buf), MSG_NOSIGNAL | MSG_CONFIRM,
  217. (struct sockaddr *)&addr, addrlen);
  218. }
  219. pthread_exit((void *)0);
  220. close(sockfd);
  221. return NULL;
  222. }
  223. static int dut_run_echo_thread(pthread_t *t, int *sockfd)
  224. {
  225. int err;
  226. sockfd = start_reuseport_server(AF_INET6, SOCK_DGRAM, NULL,
  227. DUT_ECHO_PORT, 0, 1);
  228. if (!sockfd) {
  229. fprintf(stderr,
  230. "Failed creating data UDP socket on device %s\n",
  231. env.ifname);
  232. return -errno;
  233. }
  234. /* start echo channel */
  235. err = pthread_create(t, NULL, dut_echo_thread, sockfd);
  236. if (err) {
  237. fprintf(stderr,
  238. "Failed creating data UDP thread on device %s: %s\n",
  239. env.ifname, strerror(-err));
  240. free_fds(sockfd, 1);
  241. return -EINVAL;
  242. }
  243. return 0;
  244. }
  245. static int dut_attach_xdp_prog(struct xdp_features *skel, int flags)
  246. {
  247. enum xdp_action action = env.feature.action;
  248. struct bpf_program *prog;
  249. unsigned int key = 0;
  250. int err, fd = 0;
  251. if (env.feature.drv_feature == NETDEV_XDP_ACT_NDO_XMIT) {
  252. struct bpf_devmap_val entry = {
  253. .ifindex = env.ifindex,
  254. };
  255. err = bpf_map__update_elem(skel->maps.dev_map,
  256. &key, sizeof(key),
  257. &entry, sizeof(entry), 0);
  258. if (err < 0)
  259. return err;
  260. fd = bpf_program__fd(skel->progs.xdp_do_redirect_cpumap);
  261. action = XDP_REDIRECT;
  262. }
  263. switch (action) {
  264. case XDP_TX:
  265. prog = skel->progs.xdp_do_tx;
  266. break;
  267. case XDP_DROP:
  268. prog = skel->progs.xdp_do_drop;
  269. break;
  270. case XDP_ABORTED:
  271. prog = skel->progs.xdp_do_aborted;
  272. break;
  273. case XDP_PASS:
  274. prog = skel->progs.xdp_do_pass;
  275. break;
  276. case XDP_REDIRECT: {
  277. struct bpf_cpumap_val entry = {
  278. .qsize = 2048,
  279. .bpf_prog.fd = fd,
  280. };
  281. err = bpf_map__update_elem(skel->maps.cpu_map,
  282. &key, sizeof(key),
  283. &entry, sizeof(entry), 0);
  284. if (err < 0)
  285. return err;
  286. prog = skel->progs.xdp_do_redirect;
  287. break;
  288. }
  289. default:
  290. return -EINVAL;
  291. }
  292. err = bpf_xdp_attach(env.ifindex, bpf_program__fd(prog), flags, NULL);
  293. if (err)
  294. fprintf(stderr, "Failed attaching XDP program to device %s\n",
  295. env.ifname);
  296. return err;
  297. }
  298. static int recv_msg(int sockfd, void *buf, size_t bufsize, void *val,
  299. size_t val_size)
  300. {
  301. struct tlv_hdr *tlv = (struct tlv_hdr *)buf;
  302. size_t len;
  303. len = recv(sockfd, buf, bufsize, 0);
  304. if (len != ntohs(tlv->len) || len < sizeof(*tlv))
  305. return -EINVAL;
  306. if (val) {
  307. len -= sizeof(*tlv);
  308. if (len > val_size)
  309. return -ENOMEM;
  310. memcpy(val, tlv->data, len);
  311. }
  312. return 0;
  313. }
  314. static int dut_run(struct xdp_features *skel)
  315. {
  316. int flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE;
  317. int state, err = 0, *sockfd, ctrl_sockfd, echo_sockfd;
  318. struct sockaddr_storage ctrl_addr;
  319. pthread_t dut_thread = 0;
  320. socklen_t addrlen;
  321. sockfd = start_reuseport_server(AF_INET6, SOCK_STREAM, NULL,
  322. DUT_CTRL_PORT, 0, 1);
  323. if (!sockfd) {
  324. fprintf(stderr,
  325. "Failed creating control socket on device %s\n", env.ifname);
  326. return -errno;
  327. }
  328. ctrl_sockfd = accept(*sockfd, (struct sockaddr *)&ctrl_addr, &addrlen);
  329. if (ctrl_sockfd < 0) {
  330. fprintf(stderr,
  331. "Failed accepting connections on device %s control socket\n",
  332. env.ifname);
  333. free_fds(sockfd, 1);
  334. return -errno;
  335. }
  336. /* CTRL loop */
  337. while (!exiting) {
  338. unsigned char buf[BUFSIZE] = {};
  339. struct tlv_hdr *tlv = (struct tlv_hdr *)buf;
  340. err = recv_msg(ctrl_sockfd, buf, BUFSIZE, NULL, 0);
  341. if (err)
  342. continue;
  343. switch (ntohs(tlv->type)) {
  344. case CMD_START: {
  345. if (state == CMD_START)
  346. continue;
  347. state = CMD_START;
  348. /* Load the XDP program on the DUT */
  349. err = dut_attach_xdp_prog(skel, flags);
  350. if (err)
  351. goto out;
  352. err = dut_run_echo_thread(&dut_thread, &echo_sockfd);
  353. if (err < 0)
  354. goto out;
  355. tlv->type = htons(CMD_ACK);
  356. tlv->len = htons(sizeof(*tlv));
  357. err = send(ctrl_sockfd, buf, sizeof(*tlv), 0);
  358. if (err < 0)
  359. goto end_thread;
  360. break;
  361. }
  362. case CMD_STOP:
  363. if (state != CMD_START)
  364. break;
  365. state = CMD_STOP;
  366. exiting = true;
  367. bpf_xdp_detach(env.ifindex, flags, NULL);
  368. tlv->type = htons(CMD_ACK);
  369. tlv->len = htons(sizeof(*tlv));
  370. err = send(ctrl_sockfd, buf, sizeof(*tlv), 0);
  371. goto end_thread;
  372. case CMD_GET_XDP_CAP: {
  373. LIBBPF_OPTS(bpf_xdp_query_opts, opts);
  374. unsigned long long val;
  375. size_t n;
  376. err = bpf_xdp_query(env.ifindex, XDP_FLAGS_DRV_MODE,
  377. &opts);
  378. if (err) {
  379. fprintf(stderr,
  380. "Failed querying XDP cap for device %s\n",
  381. env.ifname);
  382. goto end_thread;
  383. }
  384. tlv->type = htons(CMD_ACK);
  385. n = sizeof(*tlv) + sizeof(opts.feature_flags);
  386. tlv->len = htons(n);
  387. val = htobe64(opts.feature_flags);
  388. memcpy(tlv->data, &val, sizeof(val));
  389. err = send(ctrl_sockfd, buf, n, 0);
  390. if (err < 0)
  391. goto end_thread;
  392. break;
  393. }
  394. case CMD_GET_STATS: {
  395. unsigned int key = 0, val;
  396. size_t n;
  397. err = bpf_map__lookup_elem(skel->maps.dut_stats,
  398. &key, sizeof(key),
  399. &val, sizeof(val), 0);
  400. if (err) {
  401. fprintf(stderr,
  402. "bpf_map_lookup_elem failed (%d)\n", err);
  403. goto end_thread;
  404. }
  405. tlv->type = htons(CMD_ACK);
  406. n = sizeof(*tlv) + sizeof(val);
  407. tlv->len = htons(n);
  408. val = htonl(val);
  409. memcpy(tlv->data, &val, sizeof(val));
  410. err = send(ctrl_sockfd, buf, n, 0);
  411. if (err < 0)
  412. goto end_thread;
  413. break;
  414. }
  415. default:
  416. break;
  417. }
  418. }
  419. end_thread:
  420. pthread_join(dut_thread, NULL);
  421. out:
  422. bpf_xdp_detach(env.ifindex, flags, NULL);
  423. close(ctrl_sockfd);
  424. free_fds(sockfd, 1);
  425. return err;
  426. }
  427. static bool tester_collect_detected_cap(struct xdp_features *skel,
  428. unsigned int dut_stats)
  429. {
  430. unsigned int err, key = 0, val;
  431. if (!dut_stats)
  432. return false;
  433. err = bpf_map__lookup_elem(skel->maps.stats, &key, sizeof(key),
  434. &val, sizeof(val), 0);
  435. if (err) {
  436. fprintf(stderr, "bpf_map_lookup_elem failed (%d)\n", err);
  437. return false;
  438. }
  439. switch (env.feature.action) {
  440. case XDP_PASS:
  441. case XDP_TX:
  442. case XDP_REDIRECT:
  443. return val > 0;
  444. case XDP_DROP:
  445. case XDP_ABORTED:
  446. return val == 0;
  447. default:
  448. break;
  449. }
  450. if (env.feature.drv_feature == NETDEV_XDP_ACT_NDO_XMIT)
  451. return val > 0;
  452. return false;
  453. }
  454. static int send_and_recv_msg(int sockfd, enum test_commands cmd, void *val,
  455. size_t val_size)
  456. {
  457. unsigned char buf[BUFSIZE] = {};
  458. struct tlv_hdr *tlv = (struct tlv_hdr *)buf;
  459. int err;
  460. tlv->type = htons(cmd);
  461. tlv->len = htons(sizeof(*tlv));
  462. err = send(sockfd, buf, sizeof(*tlv), 0);
  463. if (err < 0)
  464. return err;
  465. err = recv_msg(sockfd, buf, BUFSIZE, val, val_size);
  466. if (err < 0)
  467. return err;
  468. return ntohs(tlv->type) == CMD_ACK ? 0 : -EINVAL;
  469. }
  470. static int send_echo_msg(void)
  471. {
  472. unsigned char buf[sizeof(struct tlv_hdr)];
  473. struct tlv_hdr *tlv = (struct tlv_hdr *)buf;
  474. int sockfd, n;
  475. sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
  476. if (sockfd < 0) {
  477. fprintf(stderr,
  478. "Failed creating data UDP socket on device %s\n",
  479. env.ifname);
  480. return -errno;
  481. }
  482. tlv->type = htons(CMD_ECHO);
  483. tlv->len = htons(sizeof(*tlv));
  484. n = sendto(sockfd, buf, sizeof(*tlv), MSG_NOSIGNAL | MSG_CONFIRM,
  485. (struct sockaddr *)&env.dut_addr, sizeof(env.dut_addr));
  486. close(sockfd);
  487. return n == ntohs(tlv->len) ? 0 : -EINVAL;
  488. }
  489. static int tester_run(struct xdp_features *skel)
  490. {
  491. int flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE;
  492. unsigned long long advertised_feature;
  493. struct bpf_program *prog;
  494. unsigned int stats;
  495. int i, err, sockfd;
  496. bool detected_cap;
  497. sockfd = socket(AF_INET6, SOCK_STREAM, 0);
  498. if (sockfd < 0) {
  499. fprintf(stderr,
  500. "Failed creating tester service control socket\n");
  501. return -errno;
  502. }
  503. if (settimeo(sockfd, 1000) < 0)
  504. return -EINVAL;
  505. err = connect(sockfd, (struct sockaddr *)&env.dut_ctrl_addr,
  506. sizeof(env.dut_ctrl_addr));
  507. if (err) {
  508. fprintf(stderr,
  509. "Failed connecting to the Device Under Test control socket\n");
  510. return -errno;
  511. }
  512. err = send_and_recv_msg(sockfd, CMD_GET_XDP_CAP, &advertised_feature,
  513. sizeof(advertised_feature));
  514. if (err < 0) {
  515. close(sockfd);
  516. return err;
  517. }
  518. advertised_feature = be64toh(advertised_feature);
  519. if (env.feature.drv_feature == NETDEV_XDP_ACT_NDO_XMIT ||
  520. env.feature.action == XDP_TX)
  521. prog = skel->progs.xdp_tester_check_tx;
  522. else
  523. prog = skel->progs.xdp_tester_check_rx;
  524. err = bpf_xdp_attach(env.ifindex, bpf_program__fd(prog), flags, NULL);
  525. if (err) {
  526. fprintf(stderr, "Failed attaching XDP program to device %s\n",
  527. env.ifname);
  528. goto out;
  529. }
  530. err = send_and_recv_msg(sockfd, CMD_START, NULL, 0);
  531. if (err)
  532. goto out;
  533. for (i = 0; i < 10 && !exiting; i++) {
  534. err = send_echo_msg();
  535. if (err < 0)
  536. goto out;
  537. sleep(1);
  538. }
  539. err = send_and_recv_msg(sockfd, CMD_GET_STATS, &stats, sizeof(stats));
  540. if (err)
  541. goto out;
  542. /* stop the test */
  543. err = send_and_recv_msg(sockfd, CMD_STOP, NULL, 0);
  544. /* send a new echo message to wake echo thread of the dut */
  545. send_echo_msg();
  546. detected_cap = tester_collect_detected_cap(skel, ntohl(stats));
  547. fprintf(stdout, "Feature %s: [%s][%s]\n", get_xdp_feature_str(),
  548. detected_cap ? GREEN("DETECTED") : RED("NOT DETECTED"),
  549. env.feature.drv_feature & advertised_feature ? GREEN("ADVERTISED")
  550. : RED("NOT ADVERTISED"));
  551. out:
  552. bpf_xdp_detach(env.ifindex, flags, NULL);
  553. close(sockfd);
  554. return err < 0 ? err : 0;
  555. }
  556. int main(int argc, char **argv)
  557. {
  558. struct xdp_features *skel;
  559. int err;
  560. libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
  561. libbpf_set_print(libbpf_print_fn);
  562. signal(SIGINT, sig_handler);
  563. signal(SIGTERM, sig_handler);
  564. set_env_default();
  565. /* Parse command line arguments */
  566. err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
  567. if (err)
  568. return err;
  569. if (env.ifindex < 0) {
  570. fprintf(stderr, "Invalid device name %s\n", env.ifname);
  571. return -ENODEV;
  572. }
  573. /* Load and verify BPF application */
  574. skel = xdp_features__open();
  575. if (!skel) {
  576. fprintf(stderr, "Failed to open and load BPF skeleton\n");
  577. return -EINVAL;
  578. }
  579. skel->rodata->tester_addr =
  580. ((struct sockaddr_in6 *)&env.tester_addr)->sin6_addr;
  581. skel->rodata->dut_addr =
  582. ((struct sockaddr_in6 *)&env.dut_addr)->sin6_addr;
  583. /* Load & verify BPF programs */
  584. err = xdp_features__load(skel);
  585. if (err) {
  586. fprintf(stderr, "Failed to load and verify BPF skeleton\n");
  587. goto cleanup;
  588. }
  589. err = xdp_features__attach(skel);
  590. if (err) {
  591. fprintf(stderr, "Failed to attach BPF skeleton\n");
  592. goto cleanup;
  593. }
  594. if (env.is_tester) {
  595. /* Tester */
  596. fprintf(stdout, "Starting tester service on device %s\n",
  597. env.ifname);
  598. err = tester_run(skel);
  599. } else {
  600. /* DUT */
  601. fprintf(stdout, "Starting test on device %s\n", env.ifname);
  602. err = dut_run(skel);
  603. }
  604. cleanup:
  605. xdp_features__destroy(skel);
  606. return err < 0 ? -err : 0;
  607. }