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