blob: 2b2150d6d6f78496a7bf7cc0026b6b9258f5d39c [file] [log] [blame]
Brenden Blanco86af8b42016-07-19 12:16:51 -07001/* Copyright (c) 2016 PLUMgrid
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License 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>
Daniel Borkmanne00c7b22016-11-26 01:28:09 +010018
Brenden Blanco86af8b42016-07-19 12:16:51 -070019#include "bpf_load.h"
Daniel Borkmanne00c7b22016-11-26 01:28:09 +010020#include "bpf_util.h"
Brenden Blanco86af8b42016-07-19 12:16:51 -070021#include "libbpf.h"
22
23static int set_link_xdp_fd(int ifindex, int fd)
24{
25 struct sockaddr_nl sa;
26 int sock, seq = 0, len, ret = -1;
27 char buf[4096];
28 struct nlattr *nla, *nla_xdp;
29 struct {
30 struct nlmsghdr nh;
31 struct ifinfomsg ifinfo;
32 char attrbuf[64];
33 } req;
34 struct nlmsghdr *nh;
35 struct nlmsgerr *err;
36
37 memset(&sa, 0, sizeof(sa));
38 sa.nl_family = AF_NETLINK;
39
40 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
41 if (sock < 0) {
42 printf("open netlink socket: %s\n", strerror(errno));
43 return -1;
44 }
45
46 if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
47 printf("bind to netlink: %s\n", strerror(errno));
48 goto cleanup;
49 }
50
51 memset(&req, 0, sizeof(req));
52 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
53 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
54 req.nh.nlmsg_type = RTM_SETLINK;
55 req.nh.nlmsg_pid = 0;
56 req.nh.nlmsg_seq = ++seq;
57 req.ifinfo.ifi_family = AF_UNSPEC;
58 req.ifinfo.ifi_index = ifindex;
59 nla = (struct nlattr *)(((char *)&req)
60 + NLMSG_ALIGN(req.nh.nlmsg_len));
61 nla->nla_type = NLA_F_NESTED | 43/*IFLA_XDP*/;
62
63 nla_xdp = (struct nlattr *)((char *)nla + NLA_HDRLEN);
64 nla_xdp->nla_type = 1/*IFLA_XDP_FD*/;
65 nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
66 memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
67 nla->nla_len = NLA_HDRLEN + nla_xdp->nla_len;
68
69 req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
70
71 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
72 printf("send to netlink: %s\n", strerror(errno));
73 goto cleanup;
74 }
75
76 len = recv(sock, buf, sizeof(buf), 0);
77 if (len < 0) {
78 printf("recv from netlink: %s\n", strerror(errno));
79 goto cleanup;
80 }
81
82 for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
83 nh = NLMSG_NEXT(nh, len)) {
84 if (nh->nlmsg_pid != getpid()) {
85 printf("Wrong pid %d, expected %d\n",
86 nh->nlmsg_pid, getpid());
87 goto cleanup;
88 }
89 if (nh->nlmsg_seq != seq) {
90 printf("Wrong seq %d, expected %d\n",
91 nh->nlmsg_seq, seq);
92 goto cleanup;
93 }
94 switch (nh->nlmsg_type) {
95 case NLMSG_ERROR:
96 err = (struct nlmsgerr *)NLMSG_DATA(nh);
97 if (!err->error)
98 continue;
99 printf("nlmsg error %s\n", strerror(-err->error));
100 goto cleanup;
101 case NLMSG_DONE:
102 break;
103 }
104 }
105
106 ret = 0;
107
108cleanup:
109 close(sock);
110 return ret;
111}
112
113static int ifindex;
114
115static void int_exit(int sig)
116{
117 set_link_xdp_fd(ifindex, -1);
118 exit(0);
119}
120
121/* simple per-protocol drop counter
122 */
123static void poll_stats(int interval)
124{
Daniel Borkmanne00c7b22016-11-26 01:28:09 +0100125 unsigned int nr_cpus = bpf_num_possible_cpus();
Brenden Blanco86af8b42016-07-19 12:16:51 -0700126 const unsigned int nr_keys = 256;
127 __u64 values[nr_cpus], prev[nr_keys][nr_cpus];
128 __u32 key;
129 int i;
130
131 memset(prev, 0, sizeof(prev));
132
133 while (1) {
134 sleep(interval);
135
136 for (key = 0; key < nr_keys; key++) {
137 __u64 sum = 0;
138
139 assert(bpf_lookup_elem(map_fd[0], &key, values) == 0);
140 for (i = 0; i < nr_cpus; i++)
141 sum += (values[i] - prev[key][i]);
142 if (sum)
143 printf("proto %u: %10llu pkt/s\n",
144 key, sum / interval);
145 memcpy(prev[key], values, sizeof(values));
146 }
147 }
148}
149
150int main(int ac, char **argv)
151{
152 char filename[256];
153
154 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
155
156 if (ac != 2) {
157 printf("usage: %s IFINDEX\n", argv[0]);
158 return 1;
159 }
160
161 ifindex = strtoul(argv[1], NULL, 0);
162
163 if (load_bpf_file(filename)) {
164 printf("%s", bpf_log_buf);
165 return 1;
166 }
167
168 if (!prog_fd[0]) {
169 printf("load_bpf_file: %s\n", strerror(errno));
170 return 1;
171 }
172
173 signal(SIGINT, int_exit);
174
175 if (set_link_xdp_fd(ifindex, prog_fd[0]) < 0) {
176 printf("link set xdp fd failed\n");
177 return 1;
178 }
179
180 poll_stats(2);
181
182 return 0;
183}