aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf/netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lib/bpf/netlink.c')
-rw-r--r--tools/lib/bpf/netlink.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c
new file mode 100644
index 000000000000..ccaa991fe9d8
--- /dev/null
+++ b/tools/lib/bpf/netlink.c
@@ -0,0 +1,165 @@
1// SPDX-License-Identifier: LGPL-2.1
2/* Copyright (c) 2018 Facebook */
3
4#include <stdlib.h>
5#include <memory.h>
6#include <unistd.h>
7#include <linux/bpf.h>
8#include <linux/rtnetlink.h>
9#include <sys/socket.h>
10#include <errno.h>
11#include <time.h>
12
13#include "bpf.h"
14#include "libbpf.h"
15#include "nlattr.h"
16
17#ifndef SOL_NETLINK
18#define SOL_NETLINK 270
19#endif
20
21static int bpf_netlink_open(__u32 *nl_pid)
22{
23 struct sockaddr_nl sa;
24 socklen_t addrlen;
25 int one = 1, ret;
26 int sock;
27
28 memset(&sa, 0, sizeof(sa));
29 sa.nl_family = AF_NETLINK;
30
31 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
32 if (sock < 0)
33 return -errno;
34
35 if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
36 &one, sizeof(one)) < 0) {
37 fprintf(stderr, "Netlink error reporting not supported\n");
38 }
39
40 if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
41 ret = -errno;
42 goto cleanup;
43 }
44
45 addrlen = sizeof(sa);
46 if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
47 ret = -errno;
48 goto cleanup;
49 }
50
51 if (addrlen != sizeof(sa)) {
52 ret = -LIBBPF_ERRNO__INTERNAL;
53 goto cleanup;
54 }
55
56 *nl_pid = sa.nl_pid;
57 return sock;
58
59cleanup:
60 close(sock);
61 return ret;
62}
63
64static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq)
65{
66 struct nlmsgerr *err;
67 struct nlmsghdr *nh;
68 char buf[4096];
69 int len, ret;
70
71 while (1) {
72 len = recv(sock, buf, sizeof(buf), 0);
73 if (len < 0) {
74 ret = -errno;
75 goto done;
76 }
77
78 for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
79 nh = NLMSG_NEXT(nh, len)) {
80 if (nh->nlmsg_pid != nl_pid) {
81 ret = -LIBBPF_ERRNO__WRNGPID;
82 goto done;
83 }
84 if (nh->nlmsg_seq != seq) {
85 ret = -LIBBPF_ERRNO__INVSEQ;
86 goto done;
87 }
88 switch (nh->nlmsg_type) {
89 case NLMSG_ERROR:
90 err = (struct nlmsgerr *)NLMSG_DATA(nh);
91 if (!err->error)
92 continue;
93 ret = err->error;
94 nla_dump_errormsg(nh);
95 goto done;
96 case NLMSG_DONE:
97 return 0;
98 default:
99 break;
100 }
101 }
102 }
103 ret = 0;
104done:
105 return ret;
106}
107
108int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
109{
110 int sock, seq = 0, ret;
111 struct nlattr *nla, *nla_xdp;
112 struct {
113 struct nlmsghdr nh;
114 struct ifinfomsg ifinfo;
115 char attrbuf[64];
116 } req;
117 __u32 nl_pid;
118
119 sock = bpf_netlink_open(&nl_pid);
120 if (sock < 0)
121 return sock;
122
123 memset(&req, 0, sizeof(req));
124 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
125 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
126 req.nh.nlmsg_type = RTM_SETLINK;
127 req.nh.nlmsg_pid = 0;
128 req.nh.nlmsg_seq = ++seq;
129 req.ifinfo.ifi_family = AF_UNSPEC;
130 req.ifinfo.ifi_index = ifindex;
131
132 /* started nested attribute for XDP */
133 nla = (struct nlattr *)(((char *)&req)
134 + NLMSG_ALIGN(req.nh.nlmsg_len));
135 nla->nla_type = NLA_F_NESTED | IFLA_XDP;
136 nla->nla_len = NLA_HDRLEN;
137
138 /* add XDP fd */
139 nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
140 nla_xdp->nla_type = IFLA_XDP_FD;
141 nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
142 memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
143 nla->nla_len += nla_xdp->nla_len;
144
145 /* if user passed in any flags, add those too */
146 if (flags) {
147 nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
148 nla_xdp->nla_type = IFLA_XDP_FLAGS;
149 nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
150 memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
151 nla->nla_len += nla_xdp->nla_len;
152 }
153
154 req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
155
156 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
157 ret = -errno;
158 goto cleanup;
159 }
160 ret = bpf_netlink_recv(sock, nl_pid, seq);
161
162cleanup:
163 close(sock);
164 return ret;
165}