xdp_router_ipv4_user.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  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 <sys/resource.h>
  26. #include <libgen.h>
  27. int sock, sock_arp, flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
  28. static int total_ifindex;
  29. static int *ifindex_list;
  30. static __u32 *prog_id_list;
  31. char buf[8192];
  32. static int lpm_map_fd;
  33. static int rxcnt_map_fd;
  34. static int arp_table_map_fd;
  35. static int exact_match_map_fd;
  36. static int tx_port_map_fd;
  37. static int get_route_table(int rtm_family);
  38. static void int_exit(int sig)
  39. {
  40. __u32 prog_id = 0;
  41. int i = 0;
  42. for (i = 0; i < total_ifindex; i++) {
  43. if (bpf_get_link_xdp_id(ifindex_list[i], &prog_id, flags)) {
  44. printf("bpf_get_link_xdp_id on iface %d failed\n",
  45. ifindex_list[i]);
  46. exit(1);
  47. }
  48. if (prog_id_list[i] == prog_id)
  49. bpf_set_link_xdp_fd(ifindex_list[i], -1, flags);
  50. else if (!prog_id)
  51. printf("couldn't find a prog id on iface %d\n",
  52. ifindex_list[i]);
  53. else
  54. printf("program on iface %d changed, not removing\n",
  55. ifindex_list[i]);
  56. prog_id = 0;
  57. }
  58. exit(0);
  59. }
  60. static void close_and_exit(int sig)
  61. {
  62. close(sock);
  63. close(sock_arp);
  64. int_exit(0);
  65. }
  66. /* Get the mac address of the interface given interface name */
  67. static __be64 getmac(char *iface)
  68. {
  69. struct ifreq ifr;
  70. __be64 mac = 0;
  71. int fd, i;
  72. fd = socket(AF_INET, SOCK_DGRAM, 0);
  73. ifr.ifr_addr.sa_family = AF_INET;
  74. strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1);
  75. if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
  76. printf("ioctl failed leaving....\n");
  77. return -1;
  78. }
  79. for (i = 0; i < 6 ; i++)
  80. *((__u8 *)&mac + i) = (__u8)ifr.ifr_hwaddr.sa_data[i];
  81. close(fd);
  82. return mac;
  83. }
  84. static int recv_msg(struct sockaddr_nl sock_addr, int sock)
  85. {
  86. struct nlmsghdr *nh;
  87. int len, nll = 0;
  88. char *buf_ptr;
  89. buf_ptr = buf;
  90. while (1) {
  91. len = recv(sock, buf_ptr, sizeof(buf) - nll, 0);
  92. if (len < 0)
  93. return len;
  94. nh = (struct nlmsghdr *)buf_ptr;
  95. if (nh->nlmsg_type == NLMSG_DONE)
  96. break;
  97. buf_ptr += len;
  98. nll += len;
  99. if ((sock_addr.nl_groups & RTMGRP_NEIGH) == RTMGRP_NEIGH)
  100. break;
  101. if ((sock_addr.nl_groups & RTMGRP_IPV4_ROUTE) == RTMGRP_IPV4_ROUTE)
  102. break;
  103. }
  104. return nll;
  105. }
  106. /* Function to parse the route entry returned by netlink
  107. * Updates the route entry related map entries
  108. */
  109. static void read_route(struct nlmsghdr *nh, int nll)
  110. {
  111. char dsts[24], gws[24], ifs[16], dsts_len[24], metrics[24];
  112. struct bpf_lpm_trie_key *prefix_key;
  113. struct rtattr *rt_attr;
  114. struct rtmsg *rt_msg;
  115. int rtm_family;
  116. int rtl;
  117. int i;
  118. struct route_table {
  119. int dst_len, iface, metric;
  120. char *iface_name;
  121. __be32 dst, gw;
  122. __be64 mac;
  123. } route;
  124. struct arp_table {
  125. __be64 mac;
  126. __be32 dst;
  127. };
  128. struct direct_map {
  129. struct arp_table arp;
  130. int ifindex;
  131. __be64 mac;
  132. } direct_entry;
  133. if (nh->nlmsg_type == RTM_DELROUTE)
  134. printf("DELETING Route entry\n");
  135. else if (nh->nlmsg_type == RTM_GETROUTE)
  136. printf("READING Route entry\n");
  137. else if (nh->nlmsg_type == RTM_NEWROUTE)
  138. printf("NEW Route entry\n");
  139. else
  140. printf("%d\n", nh->nlmsg_type);
  141. memset(&route, 0, sizeof(route));
  142. printf("Destination\t\tGateway\t\tGenmask\t\tMetric\t\tIface\n");
  143. for (; NLMSG_OK(nh, nll); nh = NLMSG_NEXT(nh, nll)) {
  144. rt_msg = (struct rtmsg *)NLMSG_DATA(nh);
  145. rtm_family = rt_msg->rtm_family;
  146. if (rtm_family == AF_INET)
  147. if (rt_msg->rtm_table != RT_TABLE_MAIN)
  148. continue;
  149. rt_attr = (struct rtattr *)RTM_RTA(rt_msg);
  150. rtl = RTM_PAYLOAD(nh);
  151. for (; RTA_OK(rt_attr, rtl); rt_attr = RTA_NEXT(rt_attr, rtl)) {
  152. switch (rt_attr->rta_type) {
  153. case NDA_DST:
  154. sprintf(dsts, "%u",
  155. (*((__be32 *)RTA_DATA(rt_attr))));
  156. break;
  157. case RTA_GATEWAY:
  158. sprintf(gws, "%u",
  159. *((__be32 *)RTA_DATA(rt_attr)));
  160. break;
  161. case RTA_OIF:
  162. sprintf(ifs, "%u",
  163. *((int *)RTA_DATA(rt_attr)));
  164. break;
  165. case RTA_METRICS:
  166. sprintf(metrics, "%u",
  167. *((int *)RTA_DATA(rt_attr)));
  168. default:
  169. break;
  170. }
  171. }
  172. sprintf(dsts_len, "%d", rt_msg->rtm_dst_len);
  173. route.dst = atoi(dsts);
  174. route.dst_len = atoi(dsts_len);
  175. route.gw = atoi(gws);
  176. route.iface = atoi(ifs);
  177. route.metric = atoi(metrics);
  178. route.iface_name = alloca(sizeof(char *) * IFNAMSIZ);
  179. route.iface_name = if_indextoname(route.iface, route.iface_name);
  180. route.mac = getmac(route.iface_name);
  181. if (route.mac == -1)
  182. int_exit(0);
  183. assert(bpf_map_update_elem(tx_port_map_fd,
  184. &route.iface, &route.iface, 0) == 0);
  185. if (rtm_family == AF_INET) {
  186. struct trie_value {
  187. __u8 prefix[4];
  188. __be64 value;
  189. int ifindex;
  190. int metric;
  191. __be32 gw;
  192. } *prefix_value;
  193. prefix_key = alloca(sizeof(*prefix_key) + 3);
  194. prefix_value = alloca(sizeof(*prefix_value));
  195. prefix_key->prefixlen = 32;
  196. prefix_key->prefixlen = route.dst_len;
  197. direct_entry.mac = route.mac & 0xffffffffffff;
  198. direct_entry.ifindex = route.iface;
  199. direct_entry.arp.mac = 0;
  200. direct_entry.arp.dst = 0;
  201. if (route.dst_len == 32) {
  202. if (nh->nlmsg_type == RTM_DELROUTE) {
  203. assert(bpf_map_delete_elem(exact_match_map_fd,
  204. &route.dst) == 0);
  205. } else {
  206. if (bpf_map_lookup_elem(arp_table_map_fd,
  207. &route.dst,
  208. &direct_entry.arp.mac) == 0)
  209. direct_entry.arp.dst = route.dst;
  210. assert(bpf_map_update_elem(exact_match_map_fd,
  211. &route.dst,
  212. &direct_entry, 0) == 0);
  213. }
  214. }
  215. for (i = 0; i < 4; i++)
  216. prefix_key->data[i] = (route.dst >> i * 8) & 0xff;
  217. printf("%3d.%d.%d.%d\t\t%3x\t\t%d\t\t%d\t\t%s\n",
  218. (int)prefix_key->data[0],
  219. (int)prefix_key->data[1],
  220. (int)prefix_key->data[2],
  221. (int)prefix_key->data[3],
  222. route.gw, route.dst_len,
  223. route.metric,
  224. route.iface_name);
  225. if (bpf_map_lookup_elem(lpm_map_fd, prefix_key,
  226. prefix_value) < 0) {
  227. for (i = 0; i < 4; i++)
  228. prefix_value->prefix[i] = prefix_key->data[i];
  229. prefix_value->value = route.mac & 0xffffffffffff;
  230. prefix_value->ifindex = route.iface;
  231. prefix_value->gw = route.gw;
  232. prefix_value->metric = route.metric;
  233. assert(bpf_map_update_elem(lpm_map_fd,
  234. prefix_key,
  235. prefix_value, 0
  236. ) == 0);
  237. } else {
  238. if (nh->nlmsg_type == RTM_DELROUTE) {
  239. printf("deleting entry\n");
  240. printf("prefix key=%d.%d.%d.%d/%d",
  241. prefix_key->data[0],
  242. prefix_key->data[1],
  243. prefix_key->data[2],
  244. prefix_key->data[3],
  245. prefix_key->prefixlen);
  246. assert(bpf_map_delete_elem(lpm_map_fd,
  247. prefix_key
  248. ) == 0);
  249. /* Rereading the route table to check if
  250. * there is an entry with the same
  251. * prefix but a different metric as the
  252. * deleted enty.
  253. */
  254. get_route_table(AF_INET);
  255. } else if (prefix_key->data[0] ==
  256. prefix_value->prefix[0] &&
  257. prefix_key->data[1] ==
  258. prefix_value->prefix[1] &&
  259. prefix_key->data[2] ==
  260. prefix_value->prefix[2] &&
  261. prefix_key->data[3] ==
  262. prefix_value->prefix[3] &&
  263. route.metric >= prefix_value->metric) {
  264. continue;
  265. } else {
  266. for (i = 0; i < 4; i++)
  267. prefix_value->prefix[i] =
  268. prefix_key->data[i];
  269. prefix_value->value =
  270. route.mac & 0xffffffffffff;
  271. prefix_value->ifindex = route.iface;
  272. prefix_value->gw = route.gw;
  273. prefix_value->metric = route.metric;
  274. assert(bpf_map_update_elem(lpm_map_fd,
  275. prefix_key,
  276. prefix_value,
  277. 0) == 0);
  278. }
  279. }
  280. }
  281. memset(&route, 0, sizeof(route));
  282. memset(dsts, 0, sizeof(dsts));
  283. memset(dsts_len, 0, sizeof(dsts_len));
  284. memset(gws, 0, sizeof(gws));
  285. memset(ifs, 0, sizeof(ifs));
  286. memset(&route, 0, sizeof(route));
  287. }
  288. }
  289. /* Function to read the existing route table when the process is launched*/
  290. static int get_route_table(int rtm_family)
  291. {
  292. struct sockaddr_nl sa;
  293. struct nlmsghdr *nh;
  294. int sock, seq = 0;
  295. struct msghdr msg;
  296. struct iovec iov;
  297. int ret = 0;
  298. int nll;
  299. struct {
  300. struct nlmsghdr nl;
  301. struct rtmsg rt;
  302. char buf[8192];
  303. } req;
  304. sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  305. if (sock < 0) {
  306. printf("open netlink socket: %s\n", strerror(errno));
  307. return -1;
  308. }
  309. memset(&sa, 0, sizeof(sa));
  310. sa.nl_family = AF_NETLINK;
  311. if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
  312. printf("bind to netlink: %s\n", strerror(errno));
  313. ret = -1;
  314. goto cleanup;
  315. }
  316. memset(&req, 0, sizeof(req));
  317. req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
  318. req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
  319. req.nl.nlmsg_type = RTM_GETROUTE;
  320. req.rt.rtm_family = rtm_family;
  321. req.rt.rtm_table = RT_TABLE_MAIN;
  322. req.nl.nlmsg_pid = 0;
  323. req.nl.nlmsg_seq = ++seq;
  324. memset(&msg, 0, sizeof(msg));
  325. iov.iov_base = (void *)&req.nl;
  326. iov.iov_len = req.nl.nlmsg_len;
  327. msg.msg_iov = &iov;
  328. msg.msg_iovlen = 1;
  329. ret = sendmsg(sock, &msg, 0);
  330. if (ret < 0) {
  331. printf("send to netlink: %s\n", strerror(errno));
  332. ret = -1;
  333. goto cleanup;
  334. }
  335. memset(buf, 0, sizeof(buf));
  336. nll = recv_msg(sa, sock);
  337. if (nll < 0) {
  338. printf("recv from netlink: %s\n", strerror(nll));
  339. ret = -1;
  340. goto cleanup;
  341. }
  342. nh = (struct nlmsghdr *)buf;
  343. read_route(nh, nll);
  344. cleanup:
  345. close(sock);
  346. return ret;
  347. }
  348. /* Function to parse the arp entry returned by netlink
  349. * Updates the arp entry related map entries
  350. */
  351. static void read_arp(struct nlmsghdr *nh, int nll)
  352. {
  353. struct rtattr *rt_attr;
  354. char dsts[24], mac[24];
  355. struct ndmsg *rt_msg;
  356. int rtl, ndm_family;
  357. struct arp_table {
  358. __be64 mac;
  359. __be32 dst;
  360. } arp_entry;
  361. struct direct_map {
  362. struct arp_table arp;
  363. int ifindex;
  364. __be64 mac;
  365. } direct_entry;
  366. if (nh->nlmsg_type == RTM_GETNEIGH)
  367. printf("READING arp entry\n");
  368. printf("Address\tHwAddress\n");
  369. for (; NLMSG_OK(nh, nll); nh = NLMSG_NEXT(nh, nll)) {
  370. rt_msg = (struct ndmsg *)NLMSG_DATA(nh);
  371. rt_attr = (struct rtattr *)RTM_RTA(rt_msg);
  372. ndm_family = rt_msg->ndm_family;
  373. rtl = RTM_PAYLOAD(nh);
  374. for (; RTA_OK(rt_attr, rtl); rt_attr = RTA_NEXT(rt_attr, rtl)) {
  375. switch (rt_attr->rta_type) {
  376. case NDA_DST:
  377. sprintf(dsts, "%u",
  378. *((__be32 *)RTA_DATA(rt_attr)));
  379. break;
  380. case NDA_LLADDR:
  381. sprintf(mac, "%lld",
  382. *((__be64 *)RTA_DATA(rt_attr)));
  383. break;
  384. default:
  385. break;
  386. }
  387. }
  388. arp_entry.dst = atoi(dsts);
  389. arp_entry.mac = atol(mac);
  390. printf("%x\t\t%llx\n", arp_entry.dst, arp_entry.mac);
  391. if (ndm_family == AF_INET) {
  392. if (bpf_map_lookup_elem(exact_match_map_fd,
  393. &arp_entry.dst,
  394. &direct_entry) == 0) {
  395. if (nh->nlmsg_type == RTM_DELNEIGH) {
  396. direct_entry.arp.dst = 0;
  397. direct_entry.arp.mac = 0;
  398. } else if (nh->nlmsg_type == RTM_NEWNEIGH) {
  399. direct_entry.arp.dst = arp_entry.dst;
  400. direct_entry.arp.mac = arp_entry.mac;
  401. }
  402. assert(bpf_map_update_elem(exact_match_map_fd,
  403. &arp_entry.dst,
  404. &direct_entry, 0
  405. ) == 0);
  406. memset(&direct_entry, 0, sizeof(direct_entry));
  407. }
  408. if (nh->nlmsg_type == RTM_DELNEIGH) {
  409. assert(bpf_map_delete_elem(arp_table_map_fd,
  410. &arp_entry.dst) == 0);
  411. } else if (nh->nlmsg_type == RTM_NEWNEIGH) {
  412. assert(bpf_map_update_elem(arp_table_map_fd,
  413. &arp_entry.dst,
  414. &arp_entry.mac, 0
  415. ) == 0);
  416. }
  417. }
  418. memset(&arp_entry, 0, sizeof(arp_entry));
  419. memset(dsts, 0, sizeof(dsts));
  420. }
  421. }
  422. /* Function to read the existing arp table when the process is launched*/
  423. static int get_arp_table(int rtm_family)
  424. {
  425. struct sockaddr_nl sa;
  426. struct nlmsghdr *nh;
  427. int sock, seq = 0;
  428. struct msghdr msg;
  429. struct iovec iov;
  430. int ret = 0;
  431. int nll;
  432. struct {
  433. struct nlmsghdr nl;
  434. struct ndmsg rt;
  435. char buf[8192];
  436. } req;
  437. sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  438. if (sock < 0) {
  439. printf("open netlink socket: %s\n", strerror(errno));
  440. return -1;
  441. }
  442. memset(&sa, 0, sizeof(sa));
  443. sa.nl_family = AF_NETLINK;
  444. if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
  445. printf("bind to netlink: %s\n", strerror(errno));
  446. ret = -1;
  447. goto cleanup;
  448. }
  449. memset(&req, 0, sizeof(req));
  450. req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
  451. req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
  452. req.nl.nlmsg_type = RTM_GETNEIGH;
  453. req.rt.ndm_state = NUD_REACHABLE;
  454. req.rt.ndm_family = rtm_family;
  455. req.nl.nlmsg_pid = 0;
  456. req.nl.nlmsg_seq = ++seq;
  457. memset(&msg, 0, sizeof(msg));
  458. iov.iov_base = (void *)&req.nl;
  459. iov.iov_len = req.nl.nlmsg_len;
  460. msg.msg_iov = &iov;
  461. msg.msg_iovlen = 1;
  462. ret = sendmsg(sock, &msg, 0);
  463. if (ret < 0) {
  464. printf("send to netlink: %s\n", strerror(errno));
  465. ret = -1;
  466. goto cleanup;
  467. }
  468. memset(buf, 0, sizeof(buf));
  469. nll = recv_msg(sa, sock);
  470. if (nll < 0) {
  471. printf("recv from netlink: %s\n", strerror(nll));
  472. ret = -1;
  473. goto cleanup;
  474. }
  475. nh = (struct nlmsghdr *)buf;
  476. read_arp(nh, nll);
  477. cleanup:
  478. close(sock);
  479. return ret;
  480. }
  481. /* Function to keep track and update changes in route and arp table
  482. * Give regular statistics of packets forwarded
  483. */
  484. static int monitor_route(void)
  485. {
  486. unsigned int nr_cpus = bpf_num_possible_cpus();
  487. const unsigned int nr_keys = 256;
  488. struct pollfd fds_route, fds_arp;
  489. __u64 prev[nr_keys][nr_cpus];
  490. struct sockaddr_nl la, lr;
  491. __u64 values[nr_cpus];
  492. struct nlmsghdr *nh;
  493. int nll, ret = 0;
  494. int interval = 5;
  495. __u32 key;
  496. int i;
  497. sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  498. if (sock < 0) {
  499. printf("open netlink socket: %s\n", strerror(errno));
  500. return -1;
  501. }
  502. fcntl(sock, F_SETFL, O_NONBLOCK);
  503. memset(&lr, 0, sizeof(lr));
  504. lr.nl_family = AF_NETLINK;
  505. lr.nl_groups = RTMGRP_IPV6_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_NOTIFY;
  506. if (bind(sock, (struct sockaddr *)&lr, sizeof(lr)) < 0) {
  507. printf("bind to netlink: %s\n", strerror(errno));
  508. ret = -1;
  509. goto cleanup;
  510. }
  511. fds_route.fd = sock;
  512. fds_route.events = POLL_IN;
  513. sock_arp = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  514. if (sock_arp < 0) {
  515. printf("open netlink socket: %s\n", strerror(errno));
  516. return -1;
  517. }
  518. fcntl(sock_arp, F_SETFL, O_NONBLOCK);
  519. memset(&la, 0, sizeof(la));
  520. la.nl_family = AF_NETLINK;
  521. la.nl_groups = RTMGRP_NEIGH | RTMGRP_NOTIFY;
  522. if (bind(sock_arp, (struct sockaddr *)&la, sizeof(la)) < 0) {
  523. printf("bind to netlink: %s\n", strerror(errno));
  524. ret = -1;
  525. goto cleanup;
  526. }
  527. fds_arp.fd = sock_arp;
  528. fds_arp.events = POLL_IN;
  529. memset(prev, 0, sizeof(prev));
  530. do {
  531. signal(SIGINT, close_and_exit);
  532. signal(SIGTERM, close_and_exit);
  533. sleep(interval);
  534. for (key = 0; key < nr_keys; key++) {
  535. __u64 sum = 0;
  536. assert(bpf_map_lookup_elem(rxcnt_map_fd,
  537. &key, values) == 0);
  538. for (i = 0; i < nr_cpus; i++)
  539. sum += (values[i] - prev[key][i]);
  540. if (sum)
  541. printf("proto %u: %10llu pkt/s\n",
  542. key, sum / interval);
  543. memcpy(prev[key], values, sizeof(values));
  544. }
  545. memset(buf, 0, sizeof(buf));
  546. if (poll(&fds_route, 1, 3) == POLL_IN) {
  547. nll = recv_msg(lr, sock);
  548. if (nll < 0) {
  549. printf("recv from netlink: %s\n", strerror(nll));
  550. ret = -1;
  551. goto cleanup;
  552. }
  553. nh = (struct nlmsghdr *)buf;
  554. printf("Routing table updated.\n");
  555. read_route(nh, nll);
  556. }
  557. memset(buf, 0, sizeof(buf));
  558. if (poll(&fds_arp, 1, 3) == POLL_IN) {
  559. nll = recv_msg(la, sock_arp);
  560. if (nll < 0) {
  561. printf("recv from netlink: %s\n", strerror(nll));
  562. ret = -1;
  563. goto cleanup;
  564. }
  565. nh = (struct nlmsghdr *)buf;
  566. read_arp(nh, nll);
  567. }
  568. } while (1);
  569. cleanup:
  570. close(sock);
  571. return ret;
  572. }
  573. static void usage(const char *prog)
  574. {
  575. fprintf(stderr,
  576. "%s: %s [OPTS] interface name list\n\n"
  577. "OPTS:\n"
  578. " -S use skb-mode\n"
  579. " -F force loading prog\n",
  580. __func__, prog);
  581. }
  582. int main(int ac, char **argv)
  583. {
  584. struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
  585. struct bpf_prog_load_attr prog_load_attr = {
  586. .prog_type = BPF_PROG_TYPE_XDP,
  587. };
  588. struct bpf_prog_info info = {};
  589. __u32 info_len = sizeof(info);
  590. const char *optstr = "SF";
  591. struct bpf_object *obj;
  592. char filename[256];
  593. char **ifname_list;
  594. int prog_fd, opt;
  595. int err, i = 1;
  596. snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
  597. prog_load_attr.file = filename;
  598. total_ifindex = ac - 1;
  599. ifname_list = (argv + 1);
  600. while ((opt = getopt(ac, argv, optstr)) != -1) {
  601. switch (opt) {
  602. case 'S':
  603. flags |= XDP_FLAGS_SKB_MODE;
  604. total_ifindex--;
  605. ifname_list++;
  606. break;
  607. case 'F':
  608. flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
  609. total_ifindex--;
  610. ifname_list++;
  611. break;
  612. default:
  613. usage(basename(argv[0]));
  614. return 1;
  615. }
  616. }
  617. if (!(flags & XDP_FLAGS_SKB_MODE))
  618. flags |= XDP_FLAGS_DRV_MODE;
  619. if (optind == ac) {
  620. usage(basename(argv[0]));
  621. return 1;
  622. }
  623. if (setrlimit(RLIMIT_MEMLOCK, &r)) {
  624. perror("setrlimit(RLIMIT_MEMLOCK)");
  625. return 1;
  626. }
  627. if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
  628. return 1;
  629. printf("\n**************loading bpf file*********************\n\n\n");
  630. if (!prog_fd) {
  631. printf("bpf_prog_load_xattr: %s\n", strerror(errno));
  632. return 1;
  633. }
  634. lpm_map_fd = bpf_object__find_map_fd_by_name(obj, "lpm_map");
  635. rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt");
  636. arp_table_map_fd = bpf_object__find_map_fd_by_name(obj, "arp_table");
  637. exact_match_map_fd = bpf_object__find_map_fd_by_name(obj,
  638. "exact_match");
  639. tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_port");
  640. if (lpm_map_fd < 0 || rxcnt_map_fd < 0 || arp_table_map_fd < 0 ||
  641. exact_match_map_fd < 0 || tx_port_map_fd < 0) {
  642. printf("bpf_object__find_map_fd_by_name failed\n");
  643. return 1;
  644. }
  645. ifindex_list = (int *)calloc(total_ifindex, sizeof(int *));
  646. for (i = 0; i < total_ifindex; i++) {
  647. ifindex_list[i] = if_nametoindex(ifname_list[i]);
  648. if (!ifindex_list[i]) {
  649. printf("Couldn't translate interface name: %s",
  650. strerror(errno));
  651. return 1;
  652. }
  653. }
  654. prog_id_list = (__u32 *)calloc(total_ifindex, sizeof(__u32 *));
  655. for (i = 0; i < total_ifindex; i++) {
  656. if (bpf_set_link_xdp_fd(ifindex_list[i], prog_fd, flags) < 0) {
  657. printf("link set xdp fd failed\n");
  658. int recovery_index = i;
  659. for (i = 0; i < recovery_index; i++)
  660. bpf_set_link_xdp_fd(ifindex_list[i], -1, flags);
  661. return 1;
  662. }
  663. err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
  664. if (err) {
  665. printf("can't get prog info - %s\n", strerror(errno));
  666. return err;
  667. }
  668. prog_id_list[i] = info.id;
  669. memset(&info, 0, sizeof(info));
  670. printf("Attached to %d\n", ifindex_list[i]);
  671. }
  672. signal(SIGINT, int_exit);
  673. signal(SIGTERM, int_exit);
  674. printf("*******************ROUTE TABLE*************************\n\n\n");
  675. get_route_table(AF_INET);
  676. printf("*******************ARP TABLE***************************\n\n\n");
  677. get_arp_table(AF_INET);
  678. if (monitor_route() < 0) {
  679. printf("Error in receiving route update");
  680. return 1;
  681. }
  682. return 0;
  683. }