blob: c63c6beec7d624baf78cdc75485d2ac9fc553b0c [file] [log] [blame]
Christina Jacob3e29cd02017-11-05 08:52:30 +05301/* Copyright (C) 2017 Cavium, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of version 2 of the GNU General Public License
5 * as published by the Free Software Foundation.
6 */
7#include <linux/bpf.h>
8#include <linux/netlink.h>
9#include <linux/rtnetlink.h>
10#include <assert.h>
11#include <errno.h>
12#include <signal.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/socket.h>
17#include <unistd.h>
Jakub Kicinski2bf3e2e2018-05-14 22:35:02 -070018#include <bpf/bpf.h>
Christina Jacob3e29cd02017-11-05 08:52:30 +053019#include <arpa/inet.h>
20#include <fcntl.h>
21#include <poll.h>
22#include <net/if.h>
23#include <netdb.h>
24#include <sys/ioctl.h>
25#include <sys/syscall.h>
26#include "bpf_util.h"
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +010027#include "bpf/libbpf.h"
Maciej Fijalkowski6a545762019-02-01 22:42:26 +010028#include <sys/resource.h>
Christina Jacob3e29cd02017-11-05 08:52:30 +053029
30int sock, sock_arp, flags = 0;
31static int total_ifindex;
32int *ifindex_list;
33char buf[8192];
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +010034static int lpm_map_fd;
35static int rxcnt_map_fd;
36static int arp_table_map_fd;
37static int exact_match_map_fd;
38static int tx_port_map_fd;
Christina Jacob3e29cd02017-11-05 08:52:30 +053039
40static int get_route_table(int rtm_family);
41static void int_exit(int sig)
42{
43 int i = 0;
44
45 for (i = 0; i < total_ifindex; i++)
Eric Leblondb259c2f2018-01-30 21:55:04 +010046 bpf_set_link_xdp_fd(ifindex_list[i], -1, flags);
Christina Jacob3e29cd02017-11-05 08:52:30 +053047 exit(0);
48}
49
50static void close_and_exit(int sig)
51{
52 int i = 0;
53
54 close(sock);
55 close(sock_arp);
56
57 for (i = 0; i < total_ifindex; i++)
Eric Leblondb259c2f2018-01-30 21:55:04 +010058 bpf_set_link_xdp_fd(ifindex_list[i], -1, flags);
Christina Jacob3e29cd02017-11-05 08:52:30 +053059 exit(0);
60}
61
62/* Get the mac address of the interface given interface name */
63static __be64 getmac(char *iface)
64{
65 struct ifreq ifr;
66 __be64 mac = 0;
67 int fd, i;
68
69 fd = socket(AF_INET, SOCK_DGRAM, 0);
70 ifr.ifr_addr.sa_family = AF_INET;
71 strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1);
72 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
73 printf("ioctl failed leaving....\n");
74 return -1;
75 }
76 for (i = 0; i < 6 ; i++)
77 *((__u8 *)&mac + i) = (__u8)ifr.ifr_hwaddr.sa_data[i];
78 close(fd);
79 return mac;
80}
81
82static int recv_msg(struct sockaddr_nl sock_addr, int sock)
83{
84 struct nlmsghdr *nh;
85 int len, nll = 0;
86 char *buf_ptr;
87
88 buf_ptr = buf;
89 while (1) {
90 len = recv(sock, buf_ptr, sizeof(buf) - nll, 0);
91 if (len < 0)
92 return len;
93
94 nh = (struct nlmsghdr *)buf_ptr;
95
96 if (nh->nlmsg_type == NLMSG_DONE)
97 break;
98 buf_ptr += len;
99 nll += len;
100 if ((sock_addr.nl_groups & RTMGRP_NEIGH) == RTMGRP_NEIGH)
101 break;
102
103 if ((sock_addr.nl_groups & RTMGRP_IPV4_ROUTE) == RTMGRP_IPV4_ROUTE)
104 break;
105 }
106 return nll;
107}
108
109/* Function to parse the route entry returned by netlink
110 * Updates the route entry related map entries
111 */
112static void read_route(struct nlmsghdr *nh, int nll)
113{
114 char dsts[24], gws[24], ifs[16], dsts_len[24], metrics[24];
115 struct bpf_lpm_trie_key *prefix_key;
116 struct rtattr *rt_attr;
117 struct rtmsg *rt_msg;
118 int rtm_family;
119 int rtl;
120 int i;
121 struct route_table {
122 int dst_len, iface, metric;
123 char *iface_name;
124 __be32 dst, gw;
125 __be64 mac;
126 } route;
127 struct arp_table {
128 __be64 mac;
129 __be32 dst;
130 };
131
132 struct direct_map {
133 struct arp_table arp;
134 int ifindex;
135 __be64 mac;
136 } direct_entry;
137
138 if (nh->nlmsg_type == RTM_DELROUTE)
139 printf("DELETING Route entry\n");
140 else if (nh->nlmsg_type == RTM_GETROUTE)
141 printf("READING Route entry\n");
142 else if (nh->nlmsg_type == RTM_NEWROUTE)
143 printf("NEW Route entry\n");
144 else
145 printf("%d\n", nh->nlmsg_type);
146
147 memset(&route, 0, sizeof(route));
148 printf("Destination\t\tGateway\t\tGenmask\t\tMetric\t\tIface\n");
149 for (; NLMSG_OK(nh, nll); nh = NLMSG_NEXT(nh, nll)) {
150 rt_msg = (struct rtmsg *)NLMSG_DATA(nh);
151 rtm_family = rt_msg->rtm_family;
152 if (rtm_family == AF_INET)
153 if (rt_msg->rtm_table != RT_TABLE_MAIN)
154 continue;
155 rt_attr = (struct rtattr *)RTM_RTA(rt_msg);
156 rtl = RTM_PAYLOAD(nh);
157
158 for (; RTA_OK(rt_attr, rtl); rt_attr = RTA_NEXT(rt_attr, rtl)) {
159 switch (rt_attr->rta_type) {
160 case NDA_DST:
161 sprintf(dsts, "%u",
162 (*((__be32 *)RTA_DATA(rt_attr))));
163 break;
164 case RTA_GATEWAY:
165 sprintf(gws, "%u",
166 *((__be32 *)RTA_DATA(rt_attr)));
167 break;
168 case RTA_OIF:
169 sprintf(ifs, "%u",
170 *((int *)RTA_DATA(rt_attr)));
171 break;
172 case RTA_METRICS:
173 sprintf(metrics, "%u",
174 *((int *)RTA_DATA(rt_attr)));
175 default:
176 break;
177 }
178 }
179 sprintf(dsts_len, "%d", rt_msg->rtm_dst_len);
180 route.dst = atoi(dsts);
181 route.dst_len = atoi(dsts_len);
182 route.gw = atoi(gws);
183 route.iface = atoi(ifs);
184 route.metric = atoi(metrics);
185 route.iface_name = alloca(sizeof(char *) * IFNAMSIZ);
186 route.iface_name = if_indextoname(route.iface, route.iface_name);
187 route.mac = getmac(route.iface_name);
188 if (route.mac == -1) {
189 int i = 0;
190
191 for (i = 0; i < total_ifindex; i++)
Eric Leblondb259c2f2018-01-30 21:55:04 +0100192 bpf_set_link_xdp_fd(ifindex_list[i], -1, flags);
Christina Jacob3e29cd02017-11-05 08:52:30 +0530193 exit(0);
194 }
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100195 assert(bpf_map_update_elem(tx_port_map_fd,
196 &route.iface, &route.iface, 0) == 0);
Christina Jacob3e29cd02017-11-05 08:52:30 +0530197 if (rtm_family == AF_INET) {
198 struct trie_value {
199 __u8 prefix[4];
200 __be64 value;
201 int ifindex;
202 int metric;
203 __be32 gw;
204 } *prefix_value;
205
206 prefix_key = alloca(sizeof(*prefix_key) + 3);
207 prefix_value = alloca(sizeof(*prefix_value));
208
209 prefix_key->prefixlen = 32;
210 prefix_key->prefixlen = route.dst_len;
211 direct_entry.mac = route.mac & 0xffffffffffff;
212 direct_entry.ifindex = route.iface;
213 direct_entry.arp.mac = 0;
214 direct_entry.arp.dst = 0;
215 if (route.dst_len == 32) {
Dan Carpenterfae45362017-11-14 09:12:03 +0300216 if (nh->nlmsg_type == RTM_DELROUTE) {
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100217 assert(bpf_map_delete_elem(exact_match_map_fd,
218 &route.dst) == 0);
Dan Carpenterfae45362017-11-14 09:12:03 +0300219 } else {
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100220 if (bpf_map_lookup_elem(arp_table_map_fd,
221 &route.dst,
222 &direct_entry.arp.mac) == 0)
Christina Jacob3e29cd02017-11-05 08:52:30 +0530223 direct_entry.arp.dst = route.dst;
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100224 assert(bpf_map_update_elem(exact_match_map_fd,
225 &route.dst,
226 &direct_entry, 0) == 0);
Dan Carpenterfae45362017-11-14 09:12:03 +0300227 }
Christina Jacob3e29cd02017-11-05 08:52:30 +0530228 }
229 for (i = 0; i < 4; i++)
230 prefix_key->data[i] = (route.dst >> i * 8) & 0xff;
231
232 printf("%3d.%d.%d.%d\t\t%3x\t\t%d\t\t%d\t\t%s\n",
233 (int)prefix_key->data[0],
234 (int)prefix_key->data[1],
235 (int)prefix_key->data[2],
236 (int)prefix_key->data[3],
237 route.gw, route.dst_len,
238 route.metric,
239 route.iface_name);
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100240 if (bpf_map_lookup_elem(lpm_map_fd, prefix_key,
Christina Jacob3e29cd02017-11-05 08:52:30 +0530241 prefix_value) < 0) {
242 for (i = 0; i < 4; i++)
243 prefix_value->prefix[i] = prefix_key->data[i];
244 prefix_value->value = route.mac & 0xffffffffffff;
245 prefix_value->ifindex = route.iface;
246 prefix_value->gw = route.gw;
247 prefix_value->metric = route.metric;
248
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100249 assert(bpf_map_update_elem(lpm_map_fd,
Christina Jacob3e29cd02017-11-05 08:52:30 +0530250 prefix_key,
251 prefix_value, 0
252 ) == 0);
253 } else {
254 if (nh->nlmsg_type == RTM_DELROUTE) {
255 printf("deleting entry\n");
256 printf("prefix key=%d.%d.%d.%d/%d",
257 prefix_key->data[0],
258 prefix_key->data[1],
259 prefix_key->data[2],
260 prefix_key->data[3],
261 prefix_key->prefixlen);
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100262 assert(bpf_map_delete_elem(lpm_map_fd,
Christina Jacob3e29cd02017-11-05 08:52:30 +0530263 prefix_key
264 ) == 0);
265 /* Rereading the route table to check if
266 * there is an entry with the same
267 * prefix but a different metric as the
268 * deleted enty.
269 */
270 get_route_table(AF_INET);
271 } else if (prefix_key->data[0] ==
272 prefix_value->prefix[0] &&
273 prefix_key->data[1] ==
274 prefix_value->prefix[1] &&
275 prefix_key->data[2] ==
276 prefix_value->prefix[2] &&
277 prefix_key->data[3] ==
278 prefix_value->prefix[3] &&
279 route.metric >= prefix_value->metric) {
280 continue;
281 } else {
282 for (i = 0; i < 4; i++)
283 prefix_value->prefix[i] =
284 prefix_key->data[i];
285 prefix_value->value =
286 route.mac & 0xffffffffffff;
287 prefix_value->ifindex = route.iface;
288 prefix_value->gw = route.gw;
289 prefix_value->metric = route.metric;
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100290 assert(bpf_map_update_elem(lpm_map_fd,
Christina Jacob3e29cd02017-11-05 08:52:30 +0530291 prefix_key,
292 prefix_value,
293 0) == 0);
294 }
295 }
296 }
297 memset(&route, 0, sizeof(route));
298 memset(dsts, 0, sizeof(dsts));
299 memset(dsts_len, 0, sizeof(dsts_len));
300 memset(gws, 0, sizeof(gws));
301 memset(ifs, 0, sizeof(ifs));
302 memset(&route, 0, sizeof(route));
303 }
304}
305
306/* Function to read the existing route table when the process is launched*/
307static int get_route_table(int rtm_family)
308{
309 struct sockaddr_nl sa;
310 struct nlmsghdr *nh;
311 int sock, seq = 0;
312 struct msghdr msg;
313 struct iovec iov;
314 int ret = 0;
315 int nll;
316
317 struct {
318 struct nlmsghdr nl;
319 struct rtmsg rt;
320 char buf[8192];
321 } req;
322
323 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
324 if (sock < 0) {
325 printf("open netlink socket: %s\n", strerror(errno));
326 return -1;
327 }
328 memset(&sa, 0, sizeof(sa));
329 sa.nl_family = AF_NETLINK;
330 if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
331 printf("bind to netlink: %s\n", strerror(errno));
332 ret = -1;
333 goto cleanup;
334 }
335 memset(&req, 0, sizeof(req));
336 req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
337 req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
338 req.nl.nlmsg_type = RTM_GETROUTE;
339
340 req.rt.rtm_family = rtm_family;
341 req.rt.rtm_table = RT_TABLE_MAIN;
342 req.nl.nlmsg_pid = 0;
343 req.nl.nlmsg_seq = ++seq;
344 memset(&msg, 0, sizeof(msg));
345 iov.iov_base = (void *)&req.nl;
346 iov.iov_len = req.nl.nlmsg_len;
347 msg.msg_iov = &iov;
348 msg.msg_iovlen = 1;
349 ret = sendmsg(sock, &msg, 0);
350 if (ret < 0) {
351 printf("send to netlink: %s\n", strerror(errno));
352 ret = -1;
353 goto cleanup;
354 }
355 memset(buf, 0, sizeof(buf));
356 nll = recv_msg(sa, sock);
357 if (nll < 0) {
358 printf("recv from netlink: %s\n", strerror(nll));
359 ret = -1;
360 goto cleanup;
361 }
362 nh = (struct nlmsghdr *)buf;
363 read_route(nh, nll);
364cleanup:
365 close(sock);
366 return ret;
367}
368
369/* Function to parse the arp entry returned by netlink
370 * Updates the arp entry related map entries
371 */
372static void read_arp(struct nlmsghdr *nh, int nll)
373{
374 struct rtattr *rt_attr;
375 char dsts[24], mac[24];
376 struct ndmsg *rt_msg;
377 int rtl, ndm_family;
378
379 struct arp_table {
380 __be64 mac;
381 __be32 dst;
382 } arp_entry;
383 struct direct_map {
384 struct arp_table arp;
385 int ifindex;
386 __be64 mac;
387 } direct_entry;
388
389 if (nh->nlmsg_type == RTM_GETNEIGH)
390 printf("READING arp entry\n");
391 printf("Address\tHwAddress\n");
392 for (; NLMSG_OK(nh, nll); nh = NLMSG_NEXT(nh, nll)) {
393 rt_msg = (struct ndmsg *)NLMSG_DATA(nh);
394 rt_attr = (struct rtattr *)RTM_RTA(rt_msg);
395 ndm_family = rt_msg->ndm_family;
396 rtl = RTM_PAYLOAD(nh);
397 for (; RTA_OK(rt_attr, rtl); rt_attr = RTA_NEXT(rt_attr, rtl)) {
398 switch (rt_attr->rta_type) {
399 case NDA_DST:
400 sprintf(dsts, "%u",
401 *((__be32 *)RTA_DATA(rt_attr)));
402 break;
403 case NDA_LLADDR:
404 sprintf(mac, "%lld",
405 *((__be64 *)RTA_DATA(rt_attr)));
406 break;
407 default:
408 break;
409 }
410 }
411 arp_entry.dst = atoi(dsts);
412 arp_entry.mac = atol(mac);
413 printf("%x\t\t%llx\n", arp_entry.dst, arp_entry.mac);
414 if (ndm_family == AF_INET) {
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100415 if (bpf_map_lookup_elem(exact_match_map_fd,
416 &arp_entry.dst,
Christina Jacob3e29cd02017-11-05 08:52:30 +0530417 &direct_entry) == 0) {
418 if (nh->nlmsg_type == RTM_DELNEIGH) {
419 direct_entry.arp.dst = 0;
420 direct_entry.arp.mac = 0;
421 } else if (nh->nlmsg_type == RTM_NEWNEIGH) {
422 direct_entry.arp.dst = arp_entry.dst;
423 direct_entry.arp.mac = arp_entry.mac;
424 }
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100425 assert(bpf_map_update_elem(exact_match_map_fd,
Christina Jacob3e29cd02017-11-05 08:52:30 +0530426 &arp_entry.dst,
427 &direct_entry, 0
428 ) == 0);
429 memset(&direct_entry, 0, sizeof(direct_entry));
430 }
431 if (nh->nlmsg_type == RTM_DELNEIGH) {
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100432 assert(bpf_map_delete_elem(arp_table_map_fd,
433 &arp_entry.dst) == 0);
Christina Jacob3e29cd02017-11-05 08:52:30 +0530434 } else if (nh->nlmsg_type == RTM_NEWNEIGH) {
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100435 assert(bpf_map_update_elem(arp_table_map_fd,
Christina Jacob3e29cd02017-11-05 08:52:30 +0530436 &arp_entry.dst,
437 &arp_entry.mac, 0
438 ) == 0);
439 }
440 }
441 memset(&arp_entry, 0, sizeof(arp_entry));
442 memset(dsts, 0, sizeof(dsts));
443 }
444}
445
446/* Function to read the existing arp table when the process is launched*/
447static int get_arp_table(int rtm_family)
448{
449 struct sockaddr_nl sa;
450 struct nlmsghdr *nh;
451 int sock, seq = 0;
452 struct msghdr msg;
453 struct iovec iov;
454 int ret = 0;
455 int nll;
456 struct {
457 struct nlmsghdr nl;
458 struct ndmsg rt;
459 char buf[8192];
460 } req;
461
462 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
463 if (sock < 0) {
464 printf("open netlink socket: %s\n", strerror(errno));
465 return -1;
466 }
467 memset(&sa, 0, sizeof(sa));
468 sa.nl_family = AF_NETLINK;
469 if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
470 printf("bind to netlink: %s\n", strerror(errno));
471 ret = -1;
472 goto cleanup;
473 }
474 memset(&req, 0, sizeof(req));
475 req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
476 req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
477 req.nl.nlmsg_type = RTM_GETNEIGH;
478 req.rt.ndm_state = NUD_REACHABLE;
479 req.rt.ndm_family = rtm_family;
480 req.nl.nlmsg_pid = 0;
481 req.nl.nlmsg_seq = ++seq;
482 memset(&msg, 0, sizeof(msg));
483 iov.iov_base = (void *)&req.nl;
484 iov.iov_len = req.nl.nlmsg_len;
485 msg.msg_iov = &iov;
486 msg.msg_iovlen = 1;
487 ret = sendmsg(sock, &msg, 0);
488 if (ret < 0) {
489 printf("send to netlink: %s\n", strerror(errno));
490 ret = -1;
491 goto cleanup;
492 }
493 memset(buf, 0, sizeof(buf));
494 nll = recv_msg(sa, sock);
495 if (nll < 0) {
496 printf("recv from netlink: %s\n", strerror(nll));
497 ret = -1;
498 goto cleanup;
499 }
500 nh = (struct nlmsghdr *)buf;
501 read_arp(nh, nll);
502cleanup:
503 close(sock);
504 return ret;
505}
506
507/* Function to keep track and update changes in route and arp table
508 * Give regular statistics of packets forwarded
509 */
510static int monitor_route(void)
511{
512 unsigned int nr_cpus = bpf_num_possible_cpus();
513 const unsigned int nr_keys = 256;
514 struct pollfd fds_route, fds_arp;
515 __u64 prev[nr_keys][nr_cpus];
516 struct sockaddr_nl la, lr;
517 __u64 values[nr_cpus];
518 struct nlmsghdr *nh;
519 int nll, ret = 0;
520 int interval = 5;
521 __u32 key;
522 int i;
523
524 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
525 if (sock < 0) {
526 printf("open netlink socket: %s\n", strerror(errno));
527 return -1;
528 }
529
530 fcntl(sock, F_SETFL, O_NONBLOCK);
531 memset(&lr, 0, sizeof(lr));
532 lr.nl_family = AF_NETLINK;
533 lr.nl_groups = RTMGRP_IPV6_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_NOTIFY;
534 if (bind(sock, (struct sockaddr *)&lr, sizeof(lr)) < 0) {
535 printf("bind to netlink: %s\n", strerror(errno));
536 ret = -1;
537 goto cleanup;
538 }
539 fds_route.fd = sock;
540 fds_route.events = POLL_IN;
541
542 sock_arp = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
543 if (sock_arp < 0) {
544 printf("open netlink socket: %s\n", strerror(errno));
545 return -1;
546 }
547
548 fcntl(sock_arp, F_SETFL, O_NONBLOCK);
549 memset(&la, 0, sizeof(la));
550 la.nl_family = AF_NETLINK;
551 la.nl_groups = RTMGRP_NEIGH | RTMGRP_NOTIFY;
552 if (bind(sock_arp, (struct sockaddr *)&la, sizeof(la)) < 0) {
553 printf("bind to netlink: %s\n", strerror(errno));
554 ret = -1;
555 goto cleanup;
556 }
557 fds_arp.fd = sock_arp;
558 fds_arp.events = POLL_IN;
559
560 memset(prev, 0, sizeof(prev));
561 do {
562 signal(SIGINT, close_and_exit);
563 signal(SIGTERM, close_and_exit);
564
565 sleep(interval);
566 for (key = 0; key < nr_keys; key++) {
567 __u64 sum = 0;
568
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100569 assert(bpf_map_lookup_elem(rxcnt_map_fd,
570 &key, values) == 0);
Christina Jacob3e29cd02017-11-05 08:52:30 +0530571 for (i = 0; i < nr_cpus; i++)
572 sum += (values[i] - prev[key][i]);
573 if (sum)
574 printf("proto %u: %10llu pkt/s\n",
575 key, sum / interval);
576 memcpy(prev[key], values, sizeof(values));
577 }
578
579 memset(buf, 0, sizeof(buf));
580 if (poll(&fds_route, 1, 3) == POLL_IN) {
581 nll = recv_msg(lr, sock);
582 if (nll < 0) {
583 printf("recv from netlink: %s\n", strerror(nll));
584 ret = -1;
585 goto cleanup;
586 }
587
588 nh = (struct nlmsghdr *)buf;
589 printf("Routing table updated.\n");
590 read_route(nh, nll);
591 }
592 memset(buf, 0, sizeof(buf));
593 if (poll(&fds_arp, 1, 3) == POLL_IN) {
594 nll = recv_msg(la, sock_arp);
595 if (nll < 0) {
596 printf("recv from netlink: %s\n", strerror(nll));
597 ret = -1;
598 goto cleanup;
599 }
600
601 nh = (struct nlmsghdr *)buf;
602 read_arp(nh, nll);
603 }
604
605 } while (1);
606cleanup:
607 close(sock);
608 return ret;
609}
610
611int main(int ac, char **argv)
612{
Maciej Fijalkowski6a545762019-02-01 22:42:26 +0100613 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100614 struct bpf_prog_load_attr prog_load_attr = {
615 .prog_type = BPF_PROG_TYPE_XDP,
616 };
617 struct bpf_object *obj;
Christina Jacob3e29cd02017-11-05 08:52:30 +0530618 char filename[256];
619 char **ifname_list;
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100620 int prog_fd;
Christina Jacob3e29cd02017-11-05 08:52:30 +0530621 int i = 1;
622
623 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100624 prog_load_attr.file = filename;
625
Christina Jacob3e29cd02017-11-05 08:52:30 +0530626 if (ac < 2) {
627 printf("usage: %s [-S] Interface name list\n", argv[0]);
628 return 1;
629 }
630 if (!strcmp(argv[1], "-S")) {
631 flags = XDP_FLAGS_SKB_MODE;
632 total_ifindex = ac - 2;
633 ifname_list = (argv + 2);
634 } else {
635 flags = 0;
636 total_ifindex = ac - 1;
637 ifname_list = (argv + 1);
638 }
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100639
Maciej Fijalkowski6a545762019-02-01 22:42:26 +0100640 if (setrlimit(RLIMIT_MEMLOCK, &r)) {
641 perror("setrlimit(RLIMIT_MEMLOCK)");
642 return 1;
643 }
644
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100645 if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
Christina Jacob3e29cd02017-11-05 08:52:30 +0530646 return 1;
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100647
Christina Jacob3e29cd02017-11-05 08:52:30 +0530648 printf("\n**************loading bpf file*********************\n\n\n");
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100649 if (!prog_fd) {
650 printf("bpf_prog_load_xattr: %s\n", strerror(errno));
Christina Jacob3e29cd02017-11-05 08:52:30 +0530651 return 1;
652 }
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100653
654 lpm_map_fd = bpf_object__find_map_fd_by_name(obj, "lpm_map");
655 rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt");
656 arp_table_map_fd = bpf_object__find_map_fd_by_name(obj, "arp_table");
657 exact_match_map_fd = bpf_object__find_map_fd_by_name(obj,
658 "exact_match");
659 tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_port");
660 if (lpm_map_fd < 0 || rxcnt_map_fd < 0 || arp_table_map_fd < 0 ||
661 exact_match_map_fd < 0 || tx_port_map_fd < 0) {
662 printf("bpf_object__find_map_fd_by_name failed\n");
663 return 1;
664 }
665
Christina Jacob3e29cd02017-11-05 08:52:30 +0530666 ifindex_list = (int *)malloc(total_ifindex * sizeof(int *));
667 for (i = 0; i < total_ifindex; i++) {
668 ifindex_list[i] = if_nametoindex(ifname_list[i]);
669 if (!ifindex_list[i]) {
670 printf("Couldn't translate interface name: %s",
671 strerror(errno));
672 return 1;
673 }
674 }
675 for (i = 0; i < total_ifindex; i++) {
Maciej Fijalkowskibbaf6022019-02-01 22:42:25 +0100676 if (bpf_set_link_xdp_fd(ifindex_list[i], prog_fd, flags) < 0) {
Christina Jacob3e29cd02017-11-05 08:52:30 +0530677 printf("link set xdp fd failed\n");
678 int recovery_index = i;
679
680 for (i = 0; i < recovery_index; i++)
Eric Leblondb259c2f2018-01-30 21:55:04 +0100681 bpf_set_link_xdp_fd(ifindex_list[i], -1, flags);
Christina Jacob3e29cd02017-11-05 08:52:30 +0530682
683 return 1;
684 }
685 printf("Attached to %d\n", ifindex_list[i]);
686 }
687 signal(SIGINT, int_exit);
688 signal(SIGTERM, int_exit);
689
690 printf("*******************ROUTE TABLE*************************\n\n\n");
691 get_route_table(AF_INET);
692 printf("*******************ARP TABLE***************************\n\n\n");
693 get_arp_table(AF_INET);
694 if (monitor_route() < 0) {
695 printf("Error in receiving route update");
696 return 1;
697 }
698
699 return 0;
700}