xdp_features.c 16 KB

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