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