xdp_router_ipv4_user.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (C) 2017 Cavium, Inc.
  3. */
  4. #include <linux/bpf.h>
  5. #include <linux/netlink.h>
  6. #include <linux/rtnetlink.h>
  7. #include <assert.h>
  8. #include <errno.h>
  9. #include <signal.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <sys/socket.h>
  14. #include <unistd.h>
  15. #include <bpf/bpf.h>
  16. #include <arpa/inet.h>
  17. #include <fcntl.h>
  18. #include <poll.h>
  19. #include <net/if.h>
  20. #include <netdb.h>
  21. #include <sys/ioctl.h>
  22. #include <sys/syscall.h>
  23. #include "bpf_util.h"
  24. #include <bpf/libbpf.h>
  25. #include <libgen.h>
  26. #include <getopt.h>
  27. #include <pthread.h>
  28. #include "xdp_sample_user.h"
  29. #include "xdp_router_ipv4.skel.h"
  30. static const char *__doc__ =
  31. "XDP IPv4 router implementation\n"
  32. "Usage: xdp_router_ipv4 <IFNAME-0> ... <IFNAME-N>\n";
  33. static char buf[8192];
  34. static int lpm_map_fd;
  35. static int arp_table_map_fd;
  36. static int exact_match_map_fd;
  37. static int tx_port_map_fd;
  38. static bool routes_thread_exit;
  39. static int interval = 5;
  40. static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_MAP_CNT |
  41. SAMPLE_DEVMAP_XMIT_CNT_MULTI | SAMPLE_EXCEPTION_CNT;
  42. DEFINE_SAMPLE_INIT(xdp_router_ipv4);
  43. static const struct option long_options[] = {
  44. { "help", no_argument, NULL, 'h' },
  45. { "skb-mode", no_argument, NULL, 'S' },
  46. { "force", no_argument, NULL, 'F' },
  47. { "interval", required_argument, NULL, 'i' },
  48. { "verbose", no_argument, NULL, 'v' },
  49. { "stats", no_argument, NULL, 's' },
  50. {}
  51. };
  52. static int get_route_table(int rtm_family);
  53. static int recv_msg(struct sockaddr_nl sock_addr, int sock)
  54. {
  55. struct nlmsghdr *nh;
  56. int len, nll = 0;
  57. char *buf_ptr;
  58. buf_ptr = buf;
  59. while (1) {
  60. len = recv(sock, buf_ptr, sizeof(buf) - nll, 0);
  61. if (len < 0)
  62. return len;
  63. nh = (struct nlmsghdr *)buf_ptr;
  64. if (nh->nlmsg_type == NLMSG_DONE)
  65. break;
  66. buf_ptr += len;
  67. nll += len;
  68. if ((sock_addr.nl_groups & RTMGRP_NEIGH) == RTMGRP_NEIGH)
  69. break;
  70. if ((sock_addr.nl_groups & RTMGRP_IPV4_ROUTE) == RTMGRP_IPV4_ROUTE)
  71. break;
  72. }
  73. return nll;
  74. }
  75. /* Function to parse the route entry returned by netlink
  76. * Updates the route entry related map entries
  77. */
  78. static void read_route(struct nlmsghdr *nh, int nll)
  79. {
  80. char dsts[24], gws[24], ifs[16], dsts_len[24], metrics[24];
  81. struct bpf_lpm_trie_key *prefix_key;
  82. struct rtattr *rt_attr;
  83. struct rtmsg *rt_msg;
  84. int rtm_family;
  85. int rtl;
  86. int i;
  87. struct route_table {
  88. int dst_len, iface, metric;
  89. __be32 dst, gw;
  90. __be64 mac;
  91. } route;
  92. struct arp_table {
  93. __be64 mac;
  94. __be32 dst;
  95. };
  96. struct direct_map {
  97. struct arp_table arp;
  98. int ifindex;
  99. __be64 mac;
  100. } direct_entry;
  101. memset(&route, 0, sizeof(route));
  102. for (; NLMSG_OK(nh, nll); nh = NLMSG_NEXT(nh, nll)) {
  103. rt_msg = (struct rtmsg *)NLMSG_DATA(nh);
  104. rtm_family = rt_msg->rtm_family;
  105. if (rtm_family == AF_INET)
  106. if (rt_msg->rtm_table != RT_TABLE_MAIN)
  107. continue;
  108. rt_attr = (struct rtattr *)RTM_RTA(rt_msg);
  109. rtl = RTM_PAYLOAD(nh);
  110. for (; RTA_OK(rt_attr, rtl); rt_attr = RTA_NEXT(rt_attr, rtl)) {
  111. switch (rt_attr->rta_type) {
  112. case NDA_DST:
  113. sprintf(dsts, "%u",
  114. (*((__be32 *)RTA_DATA(rt_attr))));
  115. break;
  116. case RTA_GATEWAY:
  117. sprintf(gws, "%u",
  118. *((__be32 *)RTA_DATA(rt_attr)));
  119. break;
  120. case RTA_OIF:
  121. sprintf(ifs, "%u",
  122. *((int *)RTA_DATA(rt_attr)));
  123. break;
  124. case RTA_METRICS:
  125. sprintf(metrics, "%u",
  126. *((int *)RTA_DATA(rt_attr)));
  127. default:
  128. break;
  129. }
  130. }
  131. sprintf(dsts_len, "%d", rt_msg->rtm_dst_len);
  132. route.dst = atoi(dsts);
  133. route.dst_len = atoi(dsts_len);
  134. route.gw = atoi(gws);
  135. route.iface = atoi(ifs);
  136. route.metric = atoi(metrics);
  137. assert(get_mac_addr(route.iface, &route.mac) == 0);
  138. assert(bpf_map_update_elem(tx_port_map_fd,
  139. &route.iface, &route.iface, 0) == 0);
  140. if (rtm_family == AF_INET) {
  141. struct trie_value {
  142. __u8 prefix[4];
  143. __be64 value;
  144. int ifindex;
  145. int metric;
  146. __be32 gw;
  147. } *prefix_value;
  148. prefix_key = alloca(sizeof(*prefix_key) + 3);
  149. prefix_value = alloca(sizeof(*prefix_value));
  150. prefix_key->prefixlen = 32;
  151. prefix_key->prefixlen = route.dst_len;
  152. direct_entry.mac = route.mac & 0xffffffffffff;
  153. direct_entry.ifindex = route.iface;
  154. direct_entry.arp.mac = 0;
  155. direct_entry.arp.dst = 0;
  156. if (route.dst_len == 32) {
  157. if (nh->nlmsg_type == RTM_DELROUTE) {
  158. assert(bpf_map_delete_elem(exact_match_map_fd,
  159. &route.dst) == 0);
  160. } else {
  161. if (bpf_map_lookup_elem(arp_table_map_fd,
  162. &route.dst,
  163. &direct_entry.arp.mac) == 0)
  164. direct_entry.arp.dst = route.dst;
  165. assert(bpf_map_update_elem(exact_match_map_fd,
  166. &route.dst,
  167. &direct_entry, 0) == 0);
  168. }
  169. }
  170. for (i = 0; i < 4; i++)
  171. prefix_key->data[i] = (route.dst >> i * 8) & 0xff;
  172. if (bpf_map_lookup_elem(lpm_map_fd, prefix_key,
  173. prefix_value) < 0) {
  174. for (i = 0; i < 4; i++)
  175. prefix_value->prefix[i] = prefix_key->data[i];
  176. prefix_value->value = route.mac & 0xffffffffffff;
  177. prefix_value->ifindex = route.iface;
  178. prefix_value->gw = route.gw;
  179. prefix_value->metric = route.metric;
  180. assert(bpf_map_update_elem(lpm_map_fd,
  181. prefix_key,
  182. prefix_value, 0
  183. ) == 0);
  184. } else {
  185. if (nh->nlmsg_type == RTM_DELROUTE) {
  186. assert(bpf_map_delete_elem(lpm_map_fd,
  187. prefix_key
  188. ) == 0);
  189. /* Rereading the route table to check if
  190. * there is an entry with the same
  191. * prefix but a different metric as the
  192. * deleted entry.
  193. */
  194. get_route_table(AF_INET);
  195. } else if (prefix_key->data[0] ==
  196. prefix_value->prefix[0] &&
  197. prefix_key->data[1] ==
  198. prefix_value->prefix[1] &&
  199. prefix_key->data[2] ==
  200. prefix_value->prefix[2] &&
  201. prefix_key->data[3] ==
  202. prefix_value->prefix[3] &&
  203. route.metric >= prefix_value->metric) {
  204. continue;
  205. } else {
  206. for (i = 0; i < 4; i++)
  207. prefix_value->prefix[i] =
  208. prefix_key->data[i];
  209. prefix_value->value =
  210. route.mac & 0xffffffffffff;
  211. prefix_value->ifindex = route.iface;
  212. prefix_value->gw = route.gw;
  213. prefix_value->metric = route.metric;
  214. assert(bpf_map_update_elem(lpm_map_fd,
  215. prefix_key,
  216. prefix_value,
  217. 0) == 0);
  218. }
  219. }
  220. }
  221. memset(&route, 0, sizeof(route));
  222. memset(dsts, 0, sizeof(dsts));
  223. memset(dsts_len, 0, sizeof(dsts_len));
  224. memset(gws, 0, sizeof(gws));
  225. memset(ifs, 0, sizeof(ifs));
  226. memset(&route, 0, sizeof(route));
  227. }
  228. }
  229. /* Function to read the existing route table when the process is launched*/
  230. static int get_route_table(int rtm_family)
  231. {
  232. struct sockaddr_nl sa;
  233. struct nlmsghdr *nh;
  234. int sock, seq = 0;
  235. struct msghdr msg;
  236. struct iovec iov;
  237. int ret = 0;
  238. int nll;
  239. struct {
  240. struct nlmsghdr nl;
  241. struct rtmsg rt;
  242. char buf[8192];
  243. } req;
  244. sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  245. if (sock < 0) {
  246. fprintf(stderr, "open netlink socket: %s\n", strerror(errno));
  247. return -errno;
  248. }
  249. memset(&sa, 0, sizeof(sa));
  250. sa.nl_family = AF_NETLINK;
  251. if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
  252. fprintf(stderr, "bind netlink socket: %s\n", strerror(errno));
  253. ret = -errno;
  254. goto cleanup;
  255. }
  256. memset(&req, 0, sizeof(req));
  257. req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
  258. req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
  259. req.nl.nlmsg_type = RTM_GETROUTE;
  260. req.rt.rtm_family = rtm_family;
  261. req.rt.rtm_table = RT_TABLE_MAIN;
  262. req.nl.nlmsg_pid = 0;
  263. req.nl.nlmsg_seq = ++seq;
  264. memset(&msg, 0, sizeof(msg));
  265. iov.iov_base = (void *)&req.nl;
  266. iov.iov_len = req.nl.nlmsg_len;
  267. msg.msg_iov = &iov;
  268. msg.msg_iovlen = 1;
  269. ret = sendmsg(sock, &msg, 0);
  270. if (ret < 0) {
  271. fprintf(stderr, "send to netlink: %s\n", strerror(errno));
  272. ret = -errno;
  273. goto cleanup;
  274. }
  275. memset(buf, 0, sizeof(buf));
  276. nll = recv_msg(sa, sock);
  277. if (nll < 0) {
  278. fprintf(stderr, "recv from netlink: %s\n", strerror(nll));
  279. ret = nll;
  280. goto cleanup;
  281. }
  282. nh = (struct nlmsghdr *)buf;
  283. read_route(nh, nll);
  284. cleanup:
  285. close(sock);
  286. return ret;
  287. }
  288. /* Function to parse the arp entry returned by netlink
  289. * Updates the arp entry related map entries
  290. */
  291. static void read_arp(struct nlmsghdr *nh, int nll)
  292. {
  293. struct rtattr *rt_attr;
  294. char dsts[24], mac[24];
  295. struct ndmsg *rt_msg;
  296. int rtl, ndm_family;
  297. struct arp_table {
  298. __be64 mac;
  299. __be32 dst;
  300. } arp_entry;
  301. struct direct_map {
  302. struct arp_table arp;
  303. int ifindex;
  304. __be64 mac;
  305. } direct_entry;
  306. for (; NLMSG_OK(nh, nll); nh = NLMSG_NEXT(nh, nll)) {
  307. rt_msg = (struct ndmsg *)NLMSG_DATA(nh);
  308. rt_attr = (struct rtattr *)RTM_RTA(rt_msg);
  309. ndm_family = rt_msg->ndm_family;
  310. rtl = RTM_PAYLOAD(nh);
  311. for (; RTA_OK(rt_attr, rtl); rt_attr = RTA_NEXT(rt_attr, rtl)) {
  312. switch (rt_attr->rta_type) {
  313. case NDA_DST:
  314. sprintf(dsts, "%u",
  315. *((__be32 *)RTA_DATA(rt_attr)));
  316. break;
  317. case NDA_LLADDR:
  318. sprintf(mac, "%lld",
  319. *((__be64 *)RTA_DATA(rt_attr)));
  320. break;
  321. default:
  322. break;
  323. }
  324. }
  325. arp_entry.dst = atoi(dsts);
  326. arp_entry.mac = atol(mac);
  327. if (ndm_family == AF_INET) {
  328. if (bpf_map_lookup_elem(exact_match_map_fd,
  329. &arp_entry.dst,
  330. &direct_entry) == 0) {
  331. if (nh->nlmsg_type == RTM_DELNEIGH) {
  332. direct_entry.arp.dst = 0;
  333. direct_entry.arp.mac = 0;
  334. } else if (nh->nlmsg_type == RTM_NEWNEIGH) {
  335. direct_entry.arp.dst = arp_entry.dst;
  336. direct_entry.arp.mac = arp_entry.mac;
  337. }
  338. assert(bpf_map_update_elem(exact_match_map_fd,
  339. &arp_entry.dst,
  340. &direct_entry, 0
  341. ) == 0);
  342. memset(&direct_entry, 0, sizeof(direct_entry));
  343. }
  344. if (nh->nlmsg_type == RTM_DELNEIGH) {
  345. assert(bpf_map_delete_elem(arp_table_map_fd,
  346. &arp_entry.dst) == 0);
  347. } else if (nh->nlmsg_type == RTM_NEWNEIGH) {
  348. assert(bpf_map_update_elem(arp_table_map_fd,
  349. &arp_entry.dst,
  350. &arp_entry.mac, 0
  351. ) == 0);
  352. }
  353. }
  354. memset(&arp_entry, 0, sizeof(arp_entry));
  355. memset(dsts, 0, sizeof(dsts));
  356. }
  357. }
  358. /* Function to read the existing arp table when the process is launched*/
  359. static int get_arp_table(int rtm_family)
  360. {
  361. struct sockaddr_nl sa;
  362. struct nlmsghdr *nh;
  363. int sock, seq = 0;
  364. struct msghdr msg;
  365. struct iovec iov;
  366. int ret = 0;
  367. int nll;
  368. struct {
  369. struct nlmsghdr nl;
  370. struct ndmsg rt;
  371. char buf[8192];
  372. } req;
  373. sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  374. if (sock < 0) {
  375. fprintf(stderr, "open netlink socket: %s\n", strerror(errno));
  376. return -errno;
  377. }
  378. memset(&sa, 0, sizeof(sa));
  379. sa.nl_family = AF_NETLINK;
  380. if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
  381. fprintf(stderr, "bind netlink socket: %s\n", strerror(errno));
  382. ret = -errno;
  383. goto cleanup;
  384. }
  385. memset(&req, 0, sizeof(req));
  386. req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
  387. req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
  388. req.nl.nlmsg_type = RTM_GETNEIGH;
  389. req.rt.ndm_state = NUD_REACHABLE;
  390. req.rt.ndm_family = rtm_family;
  391. req.nl.nlmsg_pid = 0;
  392. req.nl.nlmsg_seq = ++seq;
  393. memset(&msg, 0, sizeof(msg));
  394. iov.iov_base = (void *)&req.nl;
  395. iov.iov_len = req.nl.nlmsg_len;
  396. msg.msg_iov = &iov;
  397. msg.msg_iovlen = 1;
  398. ret = sendmsg(sock, &msg, 0);
  399. if (ret < 0) {
  400. fprintf(stderr, "send to netlink: %s\n", strerror(errno));
  401. ret = -errno;
  402. goto cleanup;
  403. }
  404. memset(buf, 0, sizeof(buf));
  405. nll = recv_msg(sa, sock);
  406. if (nll < 0) {
  407. fprintf(stderr, "recv from netlink: %s\n", strerror(nll));
  408. ret = nll;
  409. goto cleanup;
  410. }
  411. nh = (struct nlmsghdr *)buf;
  412. read_arp(nh, nll);
  413. cleanup:
  414. close(sock);
  415. return ret;
  416. }
  417. /* Function to keep track and update changes in route and arp table
  418. * Give regular statistics of packets forwarded
  419. */
  420. static void *monitor_routes_thread(void *arg)
  421. {
  422. struct pollfd fds_route, fds_arp;
  423. struct sockaddr_nl la, lr;
  424. int sock, sock_arp, nll;
  425. struct nlmsghdr *nh;
  426. sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  427. if (sock < 0) {
  428. fprintf(stderr, "open netlink socket: %s\n", strerror(errno));
  429. return NULL;
  430. }
  431. fcntl(sock, F_SETFL, O_NONBLOCK);
  432. memset(&lr, 0, sizeof(lr));
  433. lr.nl_family = AF_NETLINK;
  434. lr.nl_groups = RTMGRP_IPV6_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_NOTIFY;
  435. if (bind(sock, (struct sockaddr *)&lr, sizeof(lr)) < 0) {
  436. fprintf(stderr, "bind netlink socket: %s\n", strerror(errno));
  437. close(sock);
  438. return NULL;
  439. }
  440. fds_route.fd = sock;
  441. fds_route.events = POLL_IN;
  442. sock_arp = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  443. if (sock_arp < 0) {
  444. fprintf(stderr, "open netlink socket: %s\n", strerror(errno));
  445. close(sock);
  446. return NULL;
  447. }
  448. fcntl(sock_arp, F_SETFL, O_NONBLOCK);
  449. memset(&la, 0, sizeof(la));
  450. la.nl_family = AF_NETLINK;
  451. la.nl_groups = RTMGRP_NEIGH | RTMGRP_NOTIFY;
  452. if (bind(sock_arp, (struct sockaddr *)&la, sizeof(la)) < 0) {
  453. fprintf(stderr, "bind netlink socket: %s\n", strerror(errno));
  454. goto cleanup;
  455. }
  456. fds_arp.fd = sock_arp;
  457. fds_arp.events = POLL_IN;
  458. /* dump route and arp tables */
  459. if (get_arp_table(AF_INET) < 0) {
  460. fprintf(stderr, "Failed reading arp table\n");
  461. goto cleanup;
  462. }
  463. if (get_route_table(AF_INET) < 0) {
  464. fprintf(stderr, "Failed reading route table\n");
  465. goto cleanup;
  466. }
  467. while (!routes_thread_exit) {
  468. memset(buf, 0, sizeof(buf));
  469. if (poll(&fds_route, 1, 3) == POLL_IN) {
  470. nll = recv_msg(lr, sock);
  471. if (nll < 0) {
  472. fprintf(stderr, "recv from netlink: %s\n",
  473. strerror(nll));
  474. goto cleanup;
  475. }
  476. nh = (struct nlmsghdr *)buf;
  477. read_route(nh, nll);
  478. }
  479. memset(buf, 0, sizeof(buf));
  480. if (poll(&fds_arp, 1, 3) == POLL_IN) {
  481. nll = recv_msg(la, sock_arp);
  482. if (nll < 0) {
  483. fprintf(stderr, "recv from netlink: %s\n",
  484. strerror(nll));
  485. goto cleanup;
  486. }
  487. nh = (struct nlmsghdr *)buf;
  488. read_arp(nh, nll);
  489. }
  490. sleep(interval);
  491. }
  492. cleanup:
  493. close(sock_arp);
  494. close(sock);
  495. return NULL;
  496. }
  497. static void usage(char *argv[], const struct option *long_options,
  498. const char *doc, int mask, bool error,
  499. struct bpf_object *obj)
  500. {
  501. sample_usage(argv, long_options, doc, mask, error);
  502. }
  503. int main(int argc, char **argv)
  504. {
  505. bool error = true, generic = false, force = false;
  506. int opt, ret = EXIT_FAIL_BPF;
  507. struct xdp_router_ipv4 *skel;
  508. int i, total_ifindex = argc - 1;
  509. char **ifname_list = argv + 1;
  510. pthread_t routes_thread;
  511. int longindex = 0;
  512. if (libbpf_set_strict_mode(LIBBPF_STRICT_ALL) < 0) {
  513. fprintf(stderr, "Failed to set libbpf strict mode: %s\n",
  514. strerror(errno));
  515. goto end;
  516. }
  517. skel = xdp_router_ipv4__open();
  518. if (!skel) {
  519. fprintf(stderr, "Failed to xdp_router_ipv4__open: %s\n",
  520. strerror(errno));
  521. goto end;
  522. }
  523. ret = sample_init_pre_load(skel);
  524. if (ret < 0) {
  525. fprintf(stderr, "Failed to sample_init_pre_load: %s\n",
  526. strerror(-ret));
  527. ret = EXIT_FAIL_BPF;
  528. goto end_destroy;
  529. }
  530. ret = xdp_router_ipv4__load(skel);
  531. if (ret < 0) {
  532. fprintf(stderr, "Failed to xdp_router_ipv4__load: %s\n",
  533. strerror(errno));
  534. goto end_destroy;
  535. }
  536. ret = sample_init(skel, mask);
  537. if (ret < 0) {
  538. fprintf(stderr, "Failed to initialize sample: %s\n", strerror(-ret));
  539. ret = EXIT_FAIL;
  540. goto end_destroy;
  541. }
  542. while ((opt = getopt_long(argc, argv, "si:SFvh",
  543. long_options, &longindex)) != -1) {
  544. switch (opt) {
  545. case 's':
  546. mask |= SAMPLE_REDIRECT_MAP_CNT;
  547. total_ifindex--;
  548. ifname_list++;
  549. break;
  550. case 'i':
  551. interval = strtoul(optarg, NULL, 0);
  552. total_ifindex -= 2;
  553. ifname_list += 2;
  554. break;
  555. case 'S':
  556. generic = true;
  557. total_ifindex--;
  558. ifname_list++;
  559. break;
  560. case 'F':
  561. force = true;
  562. total_ifindex--;
  563. ifname_list++;
  564. break;
  565. case 'v':
  566. sample_switch_mode();
  567. total_ifindex--;
  568. ifname_list++;
  569. break;
  570. case 'h':
  571. error = false;
  572. default:
  573. usage(argv, long_options, __doc__, mask, error, skel->obj);
  574. goto end_destroy;
  575. }
  576. }
  577. ret = EXIT_FAIL_OPTION;
  578. if (optind == argc) {
  579. usage(argv, long_options, __doc__, mask, true, skel->obj);
  580. goto end_destroy;
  581. }
  582. lpm_map_fd = bpf_map__fd(skel->maps.lpm_map);
  583. if (lpm_map_fd < 0) {
  584. fprintf(stderr, "Failed loading lpm_map %s\n",
  585. strerror(-lpm_map_fd));
  586. goto end_destroy;
  587. }
  588. arp_table_map_fd = bpf_map__fd(skel->maps.arp_table);
  589. if (arp_table_map_fd < 0) {
  590. fprintf(stderr, "Failed loading arp_table_map_fd %s\n",
  591. strerror(-arp_table_map_fd));
  592. goto end_destroy;
  593. }
  594. exact_match_map_fd = bpf_map__fd(skel->maps.exact_match);
  595. if (exact_match_map_fd < 0) {
  596. fprintf(stderr, "Failed loading exact_match_map_fd %s\n",
  597. strerror(-exact_match_map_fd));
  598. goto end_destroy;
  599. }
  600. tx_port_map_fd = bpf_map__fd(skel->maps.tx_port);
  601. if (tx_port_map_fd < 0) {
  602. fprintf(stderr, "Failed loading tx_port_map_fd %s\n",
  603. strerror(-tx_port_map_fd));
  604. goto end_destroy;
  605. }
  606. ret = EXIT_FAIL_XDP;
  607. for (i = 0; i < total_ifindex; i++) {
  608. int index = if_nametoindex(ifname_list[i]);
  609. if (!index) {
  610. fprintf(stderr, "Interface %s not found %s\n",
  611. ifname_list[i], strerror(-tx_port_map_fd));
  612. goto end_destroy;
  613. }
  614. if (sample_install_xdp(skel->progs.xdp_router_ipv4_prog,
  615. index, generic, force) < 0)
  616. goto end_destroy;
  617. }
  618. ret = pthread_create(&routes_thread, NULL, monitor_routes_thread, NULL);
  619. if (ret) {
  620. fprintf(stderr, "Failed creating routes_thread: %s\n", strerror(-ret));
  621. ret = EXIT_FAIL;
  622. goto end_destroy;
  623. }
  624. ret = sample_run(interval, NULL, NULL);
  625. routes_thread_exit = true;
  626. if (ret < 0) {
  627. fprintf(stderr, "Failed during sample run: %s\n", strerror(-ret));
  628. ret = EXIT_FAIL;
  629. goto end_thread_wait;
  630. }
  631. ret = EXIT_OK;
  632. end_thread_wait:
  633. pthread_join(routes_thread, NULL);
  634. end_destroy:
  635. xdp_router_ipv4__destroy(skel);
  636. end:
  637. sample_exit(ret);
  638. }