1*f7c14bbaSAndroid Build Coastguard Worker // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2*f7c14bbaSAndroid Build Coastguard Worker /* Copyright (c) 2018 Facebook */
3*f7c14bbaSAndroid Build Coastguard Worker
4*f7c14bbaSAndroid Build Coastguard Worker #include <stdlib.h>
5*f7c14bbaSAndroid Build Coastguard Worker #include <memory.h>
6*f7c14bbaSAndroid Build Coastguard Worker #include <unistd.h>
7*f7c14bbaSAndroid Build Coastguard Worker #include <arpa/inet.h>
8*f7c14bbaSAndroid Build Coastguard Worker #include <linux/bpf.h>
9*f7c14bbaSAndroid Build Coastguard Worker #include <linux/if_ether.h>
10*f7c14bbaSAndroid Build Coastguard Worker #include <linux/pkt_cls.h>
11*f7c14bbaSAndroid Build Coastguard Worker #include <linux/rtnetlink.h>
12*f7c14bbaSAndroid Build Coastguard Worker #include <linux/netdev.h>
13*f7c14bbaSAndroid Build Coastguard Worker #include <sys/socket.h>
14*f7c14bbaSAndroid Build Coastguard Worker #include <errno.h>
15*f7c14bbaSAndroid Build Coastguard Worker #include <time.h>
16*f7c14bbaSAndroid Build Coastguard Worker
17*f7c14bbaSAndroid Build Coastguard Worker #include "bpf.h"
18*f7c14bbaSAndroid Build Coastguard Worker #include "libbpf.h"
19*f7c14bbaSAndroid Build Coastguard Worker #include "libbpf_internal.h"
20*f7c14bbaSAndroid Build Coastguard Worker #include "nlattr.h"
21*f7c14bbaSAndroid Build Coastguard Worker
22*f7c14bbaSAndroid Build Coastguard Worker #ifndef SOL_NETLINK
23*f7c14bbaSAndroid Build Coastguard Worker #define SOL_NETLINK 270
24*f7c14bbaSAndroid Build Coastguard Worker #endif
25*f7c14bbaSAndroid Build Coastguard Worker
26*f7c14bbaSAndroid Build Coastguard Worker typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
27*f7c14bbaSAndroid Build Coastguard Worker
28*f7c14bbaSAndroid Build Coastguard Worker typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, libbpf_dump_nlmsg_t,
29*f7c14bbaSAndroid Build Coastguard Worker void *cookie);
30*f7c14bbaSAndroid Build Coastguard Worker
31*f7c14bbaSAndroid Build Coastguard Worker struct xdp_link_info {
32*f7c14bbaSAndroid Build Coastguard Worker __u32 prog_id;
33*f7c14bbaSAndroid Build Coastguard Worker __u32 drv_prog_id;
34*f7c14bbaSAndroid Build Coastguard Worker __u32 hw_prog_id;
35*f7c14bbaSAndroid Build Coastguard Worker __u32 skb_prog_id;
36*f7c14bbaSAndroid Build Coastguard Worker __u8 attach_mode;
37*f7c14bbaSAndroid Build Coastguard Worker };
38*f7c14bbaSAndroid Build Coastguard Worker
39*f7c14bbaSAndroid Build Coastguard Worker struct xdp_id_md {
40*f7c14bbaSAndroid Build Coastguard Worker int ifindex;
41*f7c14bbaSAndroid Build Coastguard Worker __u32 flags;
42*f7c14bbaSAndroid Build Coastguard Worker struct xdp_link_info info;
43*f7c14bbaSAndroid Build Coastguard Worker __u64 feature_flags;
44*f7c14bbaSAndroid Build Coastguard Worker };
45*f7c14bbaSAndroid Build Coastguard Worker
46*f7c14bbaSAndroid Build Coastguard Worker struct xdp_features_md {
47*f7c14bbaSAndroid Build Coastguard Worker int ifindex;
48*f7c14bbaSAndroid Build Coastguard Worker __u32 xdp_zc_max_segs;
49*f7c14bbaSAndroid Build Coastguard Worker __u64 flags;
50*f7c14bbaSAndroid Build Coastguard Worker };
51*f7c14bbaSAndroid Build Coastguard Worker
libbpf_netlink_open(__u32 * nl_pid,int proto)52*f7c14bbaSAndroid Build Coastguard Worker static int libbpf_netlink_open(__u32 *nl_pid, int proto)
53*f7c14bbaSAndroid Build Coastguard Worker {
54*f7c14bbaSAndroid Build Coastguard Worker struct sockaddr_nl sa;
55*f7c14bbaSAndroid Build Coastguard Worker socklen_t addrlen;
56*f7c14bbaSAndroid Build Coastguard Worker int one = 1, ret;
57*f7c14bbaSAndroid Build Coastguard Worker int sock;
58*f7c14bbaSAndroid Build Coastguard Worker
59*f7c14bbaSAndroid Build Coastguard Worker memset(&sa, 0, sizeof(sa));
60*f7c14bbaSAndroid Build Coastguard Worker sa.nl_family = AF_NETLINK;
61*f7c14bbaSAndroid Build Coastguard Worker
62*f7c14bbaSAndroid Build Coastguard Worker sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, proto);
63*f7c14bbaSAndroid Build Coastguard Worker if (sock < 0)
64*f7c14bbaSAndroid Build Coastguard Worker return -errno;
65*f7c14bbaSAndroid Build Coastguard Worker
66*f7c14bbaSAndroid Build Coastguard Worker if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
67*f7c14bbaSAndroid Build Coastguard Worker &one, sizeof(one)) < 0) {
68*f7c14bbaSAndroid Build Coastguard Worker pr_warn("Netlink error reporting not supported\n");
69*f7c14bbaSAndroid Build Coastguard Worker }
70*f7c14bbaSAndroid Build Coastguard Worker
71*f7c14bbaSAndroid Build Coastguard Worker if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
72*f7c14bbaSAndroid Build Coastguard Worker ret = -errno;
73*f7c14bbaSAndroid Build Coastguard Worker goto cleanup;
74*f7c14bbaSAndroid Build Coastguard Worker }
75*f7c14bbaSAndroid Build Coastguard Worker
76*f7c14bbaSAndroid Build Coastguard Worker addrlen = sizeof(sa);
77*f7c14bbaSAndroid Build Coastguard Worker if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
78*f7c14bbaSAndroid Build Coastguard Worker ret = -errno;
79*f7c14bbaSAndroid Build Coastguard Worker goto cleanup;
80*f7c14bbaSAndroid Build Coastguard Worker }
81*f7c14bbaSAndroid Build Coastguard Worker
82*f7c14bbaSAndroid Build Coastguard Worker if (addrlen != sizeof(sa)) {
83*f7c14bbaSAndroid Build Coastguard Worker ret = -LIBBPF_ERRNO__INTERNAL;
84*f7c14bbaSAndroid Build Coastguard Worker goto cleanup;
85*f7c14bbaSAndroid Build Coastguard Worker }
86*f7c14bbaSAndroid Build Coastguard Worker
87*f7c14bbaSAndroid Build Coastguard Worker *nl_pid = sa.nl_pid;
88*f7c14bbaSAndroid Build Coastguard Worker return sock;
89*f7c14bbaSAndroid Build Coastguard Worker
90*f7c14bbaSAndroid Build Coastguard Worker cleanup:
91*f7c14bbaSAndroid Build Coastguard Worker close(sock);
92*f7c14bbaSAndroid Build Coastguard Worker return ret;
93*f7c14bbaSAndroid Build Coastguard Worker }
94*f7c14bbaSAndroid Build Coastguard Worker
libbpf_netlink_close(int sock)95*f7c14bbaSAndroid Build Coastguard Worker static void libbpf_netlink_close(int sock)
96*f7c14bbaSAndroid Build Coastguard Worker {
97*f7c14bbaSAndroid Build Coastguard Worker close(sock);
98*f7c14bbaSAndroid Build Coastguard Worker }
99*f7c14bbaSAndroid Build Coastguard Worker
100*f7c14bbaSAndroid Build Coastguard Worker enum {
101*f7c14bbaSAndroid Build Coastguard Worker NL_CONT,
102*f7c14bbaSAndroid Build Coastguard Worker NL_NEXT,
103*f7c14bbaSAndroid Build Coastguard Worker NL_DONE,
104*f7c14bbaSAndroid Build Coastguard Worker };
105*f7c14bbaSAndroid Build Coastguard Worker
netlink_recvmsg(int sock,struct msghdr * mhdr,int flags)106*f7c14bbaSAndroid Build Coastguard Worker static int netlink_recvmsg(int sock, struct msghdr *mhdr, int flags)
107*f7c14bbaSAndroid Build Coastguard Worker {
108*f7c14bbaSAndroid Build Coastguard Worker int len;
109*f7c14bbaSAndroid Build Coastguard Worker
110*f7c14bbaSAndroid Build Coastguard Worker do {
111*f7c14bbaSAndroid Build Coastguard Worker len = recvmsg(sock, mhdr, flags);
112*f7c14bbaSAndroid Build Coastguard Worker } while (len < 0 && (errno == EINTR || errno == EAGAIN));
113*f7c14bbaSAndroid Build Coastguard Worker
114*f7c14bbaSAndroid Build Coastguard Worker if (len < 0)
115*f7c14bbaSAndroid Build Coastguard Worker return -errno;
116*f7c14bbaSAndroid Build Coastguard Worker return len;
117*f7c14bbaSAndroid Build Coastguard Worker }
118*f7c14bbaSAndroid Build Coastguard Worker
alloc_iov(struct iovec * iov,int len)119*f7c14bbaSAndroid Build Coastguard Worker static int alloc_iov(struct iovec *iov, int len)
120*f7c14bbaSAndroid Build Coastguard Worker {
121*f7c14bbaSAndroid Build Coastguard Worker void *nbuf;
122*f7c14bbaSAndroid Build Coastguard Worker
123*f7c14bbaSAndroid Build Coastguard Worker nbuf = realloc(iov->iov_base, len);
124*f7c14bbaSAndroid Build Coastguard Worker if (!nbuf)
125*f7c14bbaSAndroid Build Coastguard Worker return -ENOMEM;
126*f7c14bbaSAndroid Build Coastguard Worker
127*f7c14bbaSAndroid Build Coastguard Worker iov->iov_base = nbuf;
128*f7c14bbaSAndroid Build Coastguard Worker iov->iov_len = len;
129*f7c14bbaSAndroid Build Coastguard Worker return 0;
130*f7c14bbaSAndroid Build Coastguard Worker }
131*f7c14bbaSAndroid Build Coastguard Worker
libbpf_netlink_recv(int sock,__u32 nl_pid,int seq,__dump_nlmsg_t _fn,libbpf_dump_nlmsg_t fn,void * cookie)132*f7c14bbaSAndroid Build Coastguard Worker static int libbpf_netlink_recv(int sock, __u32 nl_pid, int seq,
133*f7c14bbaSAndroid Build Coastguard Worker __dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn,
134*f7c14bbaSAndroid Build Coastguard Worker void *cookie)
135*f7c14bbaSAndroid Build Coastguard Worker {
136*f7c14bbaSAndroid Build Coastguard Worker struct iovec iov = {};
137*f7c14bbaSAndroid Build Coastguard Worker struct msghdr mhdr = {
138*f7c14bbaSAndroid Build Coastguard Worker .msg_iov = &iov,
139*f7c14bbaSAndroid Build Coastguard Worker .msg_iovlen = 1,
140*f7c14bbaSAndroid Build Coastguard Worker };
141*f7c14bbaSAndroid Build Coastguard Worker bool multipart = true;
142*f7c14bbaSAndroid Build Coastguard Worker struct nlmsgerr *err;
143*f7c14bbaSAndroid Build Coastguard Worker struct nlmsghdr *nh;
144*f7c14bbaSAndroid Build Coastguard Worker int len, ret;
145*f7c14bbaSAndroid Build Coastguard Worker
146*f7c14bbaSAndroid Build Coastguard Worker ret = alloc_iov(&iov, 4096);
147*f7c14bbaSAndroid Build Coastguard Worker if (ret)
148*f7c14bbaSAndroid Build Coastguard Worker goto done;
149*f7c14bbaSAndroid Build Coastguard Worker
150*f7c14bbaSAndroid Build Coastguard Worker while (multipart) {
151*f7c14bbaSAndroid Build Coastguard Worker start:
152*f7c14bbaSAndroid Build Coastguard Worker multipart = false;
153*f7c14bbaSAndroid Build Coastguard Worker len = netlink_recvmsg(sock, &mhdr, MSG_PEEK | MSG_TRUNC);
154*f7c14bbaSAndroid Build Coastguard Worker if (len < 0) {
155*f7c14bbaSAndroid Build Coastguard Worker ret = len;
156*f7c14bbaSAndroid Build Coastguard Worker goto done;
157*f7c14bbaSAndroid Build Coastguard Worker }
158*f7c14bbaSAndroid Build Coastguard Worker
159*f7c14bbaSAndroid Build Coastguard Worker if (len > iov.iov_len) {
160*f7c14bbaSAndroid Build Coastguard Worker ret = alloc_iov(&iov, len);
161*f7c14bbaSAndroid Build Coastguard Worker if (ret)
162*f7c14bbaSAndroid Build Coastguard Worker goto done;
163*f7c14bbaSAndroid Build Coastguard Worker }
164*f7c14bbaSAndroid Build Coastguard Worker
165*f7c14bbaSAndroid Build Coastguard Worker len = netlink_recvmsg(sock, &mhdr, 0);
166*f7c14bbaSAndroid Build Coastguard Worker if (len < 0) {
167*f7c14bbaSAndroid Build Coastguard Worker ret = len;
168*f7c14bbaSAndroid Build Coastguard Worker goto done;
169*f7c14bbaSAndroid Build Coastguard Worker }
170*f7c14bbaSAndroid Build Coastguard Worker
171*f7c14bbaSAndroid Build Coastguard Worker if (len == 0)
172*f7c14bbaSAndroid Build Coastguard Worker break;
173*f7c14bbaSAndroid Build Coastguard Worker
174*f7c14bbaSAndroid Build Coastguard Worker for (nh = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(nh, len);
175*f7c14bbaSAndroid Build Coastguard Worker nh = NLMSG_NEXT(nh, len)) {
176*f7c14bbaSAndroid Build Coastguard Worker if (nh->nlmsg_pid != nl_pid) {
177*f7c14bbaSAndroid Build Coastguard Worker ret = -LIBBPF_ERRNO__WRNGPID;
178*f7c14bbaSAndroid Build Coastguard Worker goto done;
179*f7c14bbaSAndroid Build Coastguard Worker }
180*f7c14bbaSAndroid Build Coastguard Worker if (nh->nlmsg_seq != seq) {
181*f7c14bbaSAndroid Build Coastguard Worker ret = -LIBBPF_ERRNO__INVSEQ;
182*f7c14bbaSAndroid Build Coastguard Worker goto done;
183*f7c14bbaSAndroid Build Coastguard Worker }
184*f7c14bbaSAndroid Build Coastguard Worker if (nh->nlmsg_flags & NLM_F_MULTI)
185*f7c14bbaSAndroid Build Coastguard Worker multipart = true;
186*f7c14bbaSAndroid Build Coastguard Worker switch (nh->nlmsg_type) {
187*f7c14bbaSAndroid Build Coastguard Worker case NLMSG_ERROR:
188*f7c14bbaSAndroid Build Coastguard Worker err = (struct nlmsgerr *)NLMSG_DATA(nh);
189*f7c14bbaSAndroid Build Coastguard Worker if (!err->error)
190*f7c14bbaSAndroid Build Coastguard Worker continue;
191*f7c14bbaSAndroid Build Coastguard Worker ret = err->error;
192*f7c14bbaSAndroid Build Coastguard Worker libbpf_nla_dump_errormsg(nh);
193*f7c14bbaSAndroid Build Coastguard Worker goto done;
194*f7c14bbaSAndroid Build Coastguard Worker case NLMSG_DONE:
195*f7c14bbaSAndroid Build Coastguard Worker ret = 0;
196*f7c14bbaSAndroid Build Coastguard Worker goto done;
197*f7c14bbaSAndroid Build Coastguard Worker default:
198*f7c14bbaSAndroid Build Coastguard Worker break;
199*f7c14bbaSAndroid Build Coastguard Worker }
200*f7c14bbaSAndroid Build Coastguard Worker if (_fn) {
201*f7c14bbaSAndroid Build Coastguard Worker ret = _fn(nh, fn, cookie);
202*f7c14bbaSAndroid Build Coastguard Worker switch (ret) {
203*f7c14bbaSAndroid Build Coastguard Worker case NL_CONT:
204*f7c14bbaSAndroid Build Coastguard Worker break;
205*f7c14bbaSAndroid Build Coastguard Worker case NL_NEXT:
206*f7c14bbaSAndroid Build Coastguard Worker goto start;
207*f7c14bbaSAndroid Build Coastguard Worker case NL_DONE:
208*f7c14bbaSAndroid Build Coastguard Worker ret = 0;
209*f7c14bbaSAndroid Build Coastguard Worker goto done;
210*f7c14bbaSAndroid Build Coastguard Worker default:
211*f7c14bbaSAndroid Build Coastguard Worker goto done;
212*f7c14bbaSAndroid Build Coastguard Worker }
213*f7c14bbaSAndroid Build Coastguard Worker }
214*f7c14bbaSAndroid Build Coastguard Worker }
215*f7c14bbaSAndroid Build Coastguard Worker }
216*f7c14bbaSAndroid Build Coastguard Worker ret = 0;
217*f7c14bbaSAndroid Build Coastguard Worker done:
218*f7c14bbaSAndroid Build Coastguard Worker free(iov.iov_base);
219*f7c14bbaSAndroid Build Coastguard Worker return ret;
220*f7c14bbaSAndroid Build Coastguard Worker }
221*f7c14bbaSAndroid Build Coastguard Worker
libbpf_netlink_send_recv(struct libbpf_nla_req * req,int proto,__dump_nlmsg_t parse_msg,libbpf_dump_nlmsg_t parse_attr,void * cookie)222*f7c14bbaSAndroid Build Coastguard Worker static int libbpf_netlink_send_recv(struct libbpf_nla_req *req,
223*f7c14bbaSAndroid Build Coastguard Worker int proto, __dump_nlmsg_t parse_msg,
224*f7c14bbaSAndroid Build Coastguard Worker libbpf_dump_nlmsg_t parse_attr,
225*f7c14bbaSAndroid Build Coastguard Worker void *cookie)
226*f7c14bbaSAndroid Build Coastguard Worker {
227*f7c14bbaSAndroid Build Coastguard Worker __u32 nl_pid = 0;
228*f7c14bbaSAndroid Build Coastguard Worker int sock, ret;
229*f7c14bbaSAndroid Build Coastguard Worker
230*f7c14bbaSAndroid Build Coastguard Worker sock = libbpf_netlink_open(&nl_pid, proto);
231*f7c14bbaSAndroid Build Coastguard Worker if (sock < 0)
232*f7c14bbaSAndroid Build Coastguard Worker return sock;
233*f7c14bbaSAndroid Build Coastguard Worker
234*f7c14bbaSAndroid Build Coastguard Worker req->nh.nlmsg_pid = 0;
235*f7c14bbaSAndroid Build Coastguard Worker req->nh.nlmsg_seq = time(NULL);
236*f7c14bbaSAndroid Build Coastguard Worker
237*f7c14bbaSAndroid Build Coastguard Worker if (send(sock, req, req->nh.nlmsg_len, 0) < 0) {
238*f7c14bbaSAndroid Build Coastguard Worker ret = -errno;
239*f7c14bbaSAndroid Build Coastguard Worker goto out;
240*f7c14bbaSAndroid Build Coastguard Worker }
241*f7c14bbaSAndroid Build Coastguard Worker
242*f7c14bbaSAndroid Build Coastguard Worker ret = libbpf_netlink_recv(sock, nl_pid, req->nh.nlmsg_seq,
243*f7c14bbaSAndroid Build Coastguard Worker parse_msg, parse_attr, cookie);
244*f7c14bbaSAndroid Build Coastguard Worker out:
245*f7c14bbaSAndroid Build Coastguard Worker libbpf_netlink_close(sock);
246*f7c14bbaSAndroid Build Coastguard Worker return ret;
247*f7c14bbaSAndroid Build Coastguard Worker }
248*f7c14bbaSAndroid Build Coastguard Worker
parse_genl_family_id(struct nlmsghdr * nh,libbpf_dump_nlmsg_t fn,void * cookie)249*f7c14bbaSAndroid Build Coastguard Worker static int parse_genl_family_id(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn,
250*f7c14bbaSAndroid Build Coastguard Worker void *cookie)
251*f7c14bbaSAndroid Build Coastguard Worker {
252*f7c14bbaSAndroid Build Coastguard Worker struct genlmsghdr *gnl = NLMSG_DATA(nh);
253*f7c14bbaSAndroid Build Coastguard Worker struct nlattr *na = (struct nlattr *)((void *)gnl + GENL_HDRLEN);
254*f7c14bbaSAndroid Build Coastguard Worker struct nlattr *tb[CTRL_ATTR_FAMILY_ID + 1];
255*f7c14bbaSAndroid Build Coastguard Worker __u16 *id = cookie;
256*f7c14bbaSAndroid Build Coastguard Worker
257*f7c14bbaSAndroid Build Coastguard Worker libbpf_nla_parse(tb, CTRL_ATTR_FAMILY_ID, na,
258*f7c14bbaSAndroid Build Coastguard Worker NLMSG_PAYLOAD(nh, sizeof(*gnl)), NULL);
259*f7c14bbaSAndroid Build Coastguard Worker if (!tb[CTRL_ATTR_FAMILY_ID])
260*f7c14bbaSAndroid Build Coastguard Worker return NL_CONT;
261*f7c14bbaSAndroid Build Coastguard Worker
262*f7c14bbaSAndroid Build Coastguard Worker *id = libbpf_nla_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
263*f7c14bbaSAndroid Build Coastguard Worker return NL_DONE;
264*f7c14bbaSAndroid Build Coastguard Worker }
265*f7c14bbaSAndroid Build Coastguard Worker
libbpf_netlink_resolve_genl_family_id(const char * name,__u16 len,__u16 * id)266*f7c14bbaSAndroid Build Coastguard Worker static int libbpf_netlink_resolve_genl_family_id(const char *name,
267*f7c14bbaSAndroid Build Coastguard Worker __u16 len, __u16 *id)
268*f7c14bbaSAndroid Build Coastguard Worker {
269*f7c14bbaSAndroid Build Coastguard Worker struct libbpf_nla_req req = {
270*f7c14bbaSAndroid Build Coastguard Worker .nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN),
271*f7c14bbaSAndroid Build Coastguard Worker .nh.nlmsg_type = GENL_ID_CTRL,
272*f7c14bbaSAndroid Build Coastguard Worker .nh.nlmsg_flags = NLM_F_REQUEST,
273*f7c14bbaSAndroid Build Coastguard Worker .gnl.cmd = CTRL_CMD_GETFAMILY,
274*f7c14bbaSAndroid Build Coastguard Worker .gnl.version = 2,
275*f7c14bbaSAndroid Build Coastguard Worker };
276*f7c14bbaSAndroid Build Coastguard Worker int err;
277*f7c14bbaSAndroid Build Coastguard Worker
278*f7c14bbaSAndroid Build Coastguard Worker err = nlattr_add(&req, CTRL_ATTR_FAMILY_NAME, name, len);
279*f7c14bbaSAndroid Build Coastguard Worker if (err < 0)
280*f7c14bbaSAndroid Build Coastguard Worker return err;
281*f7c14bbaSAndroid Build Coastguard Worker
282*f7c14bbaSAndroid Build Coastguard Worker return libbpf_netlink_send_recv(&req, NETLINK_GENERIC,
283*f7c14bbaSAndroid Build Coastguard Worker parse_genl_family_id, NULL, id);
284*f7c14bbaSAndroid Build Coastguard Worker }
285*f7c14bbaSAndroid Build Coastguard Worker
__bpf_set_link_xdp_fd_replace(int ifindex,int fd,int old_fd,__u32 flags)286*f7c14bbaSAndroid Build Coastguard Worker static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd,
287*f7c14bbaSAndroid Build Coastguard Worker __u32 flags)
288*f7c14bbaSAndroid Build Coastguard Worker {
289*f7c14bbaSAndroid Build Coastguard Worker struct nlattr *nla;
290*f7c14bbaSAndroid Build Coastguard Worker int ret;
291*f7c14bbaSAndroid Build Coastguard Worker struct libbpf_nla_req req;
292*f7c14bbaSAndroid Build Coastguard Worker
293*f7c14bbaSAndroid Build Coastguard Worker memset(&req, 0, sizeof(req));
294*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
295*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
296*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_type = RTM_SETLINK;
297*f7c14bbaSAndroid Build Coastguard Worker req.ifinfo.ifi_family = AF_UNSPEC;
298*f7c14bbaSAndroid Build Coastguard Worker req.ifinfo.ifi_index = ifindex;
299*f7c14bbaSAndroid Build Coastguard Worker
300*f7c14bbaSAndroid Build Coastguard Worker nla = nlattr_begin_nested(&req, IFLA_XDP);
301*f7c14bbaSAndroid Build Coastguard Worker if (!nla)
302*f7c14bbaSAndroid Build Coastguard Worker return -EMSGSIZE;
303*f7c14bbaSAndroid Build Coastguard Worker ret = nlattr_add(&req, IFLA_XDP_FD, &fd, sizeof(fd));
304*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
305*f7c14bbaSAndroid Build Coastguard Worker return ret;
306*f7c14bbaSAndroid Build Coastguard Worker if (flags) {
307*f7c14bbaSAndroid Build Coastguard Worker ret = nlattr_add(&req, IFLA_XDP_FLAGS, &flags, sizeof(flags));
308*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
309*f7c14bbaSAndroid Build Coastguard Worker return ret;
310*f7c14bbaSAndroid Build Coastguard Worker }
311*f7c14bbaSAndroid Build Coastguard Worker if (flags & XDP_FLAGS_REPLACE) {
312*f7c14bbaSAndroid Build Coastguard Worker ret = nlattr_add(&req, IFLA_XDP_EXPECTED_FD, &old_fd,
313*f7c14bbaSAndroid Build Coastguard Worker sizeof(old_fd));
314*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
315*f7c14bbaSAndroid Build Coastguard Worker return ret;
316*f7c14bbaSAndroid Build Coastguard Worker }
317*f7c14bbaSAndroid Build Coastguard Worker nlattr_end_nested(&req, nla);
318*f7c14bbaSAndroid Build Coastguard Worker
319*f7c14bbaSAndroid Build Coastguard Worker return libbpf_netlink_send_recv(&req, NETLINK_ROUTE, NULL, NULL, NULL);
320*f7c14bbaSAndroid Build Coastguard Worker }
321*f7c14bbaSAndroid Build Coastguard Worker
bpf_xdp_attach(int ifindex,int prog_fd,__u32 flags,const struct bpf_xdp_attach_opts * opts)322*f7c14bbaSAndroid Build Coastguard Worker int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags, const struct bpf_xdp_attach_opts *opts)
323*f7c14bbaSAndroid Build Coastguard Worker {
324*f7c14bbaSAndroid Build Coastguard Worker int old_prog_fd, err;
325*f7c14bbaSAndroid Build Coastguard Worker
326*f7c14bbaSAndroid Build Coastguard Worker if (!OPTS_VALID(opts, bpf_xdp_attach_opts))
327*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
328*f7c14bbaSAndroid Build Coastguard Worker
329*f7c14bbaSAndroid Build Coastguard Worker old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
330*f7c14bbaSAndroid Build Coastguard Worker if (old_prog_fd)
331*f7c14bbaSAndroid Build Coastguard Worker flags |= XDP_FLAGS_REPLACE;
332*f7c14bbaSAndroid Build Coastguard Worker else
333*f7c14bbaSAndroid Build Coastguard Worker old_prog_fd = -1;
334*f7c14bbaSAndroid Build Coastguard Worker
335*f7c14bbaSAndroid Build Coastguard Worker err = __bpf_set_link_xdp_fd_replace(ifindex, prog_fd, old_prog_fd, flags);
336*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(err);
337*f7c14bbaSAndroid Build Coastguard Worker }
338*f7c14bbaSAndroid Build Coastguard Worker
bpf_xdp_detach(int ifindex,__u32 flags,const struct bpf_xdp_attach_opts * opts)339*f7c14bbaSAndroid Build Coastguard Worker int bpf_xdp_detach(int ifindex, __u32 flags, const struct bpf_xdp_attach_opts *opts)
340*f7c14bbaSAndroid Build Coastguard Worker {
341*f7c14bbaSAndroid Build Coastguard Worker return bpf_xdp_attach(ifindex, -1, flags, opts);
342*f7c14bbaSAndroid Build Coastguard Worker }
343*f7c14bbaSAndroid Build Coastguard Worker
__dump_link_nlmsg(struct nlmsghdr * nlh,libbpf_dump_nlmsg_t dump_link_nlmsg,void * cookie)344*f7c14bbaSAndroid Build Coastguard Worker static int __dump_link_nlmsg(struct nlmsghdr *nlh,
345*f7c14bbaSAndroid Build Coastguard Worker libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie)
346*f7c14bbaSAndroid Build Coastguard Worker {
347*f7c14bbaSAndroid Build Coastguard Worker struct nlattr *tb[IFLA_MAX + 1], *attr;
348*f7c14bbaSAndroid Build Coastguard Worker struct ifinfomsg *ifi = NLMSG_DATA(nlh);
349*f7c14bbaSAndroid Build Coastguard Worker int len;
350*f7c14bbaSAndroid Build Coastguard Worker
351*f7c14bbaSAndroid Build Coastguard Worker len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
352*f7c14bbaSAndroid Build Coastguard Worker attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
353*f7c14bbaSAndroid Build Coastguard Worker
354*f7c14bbaSAndroid Build Coastguard Worker if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
355*f7c14bbaSAndroid Build Coastguard Worker return -LIBBPF_ERRNO__NLPARSE;
356*f7c14bbaSAndroid Build Coastguard Worker
357*f7c14bbaSAndroid Build Coastguard Worker return dump_link_nlmsg(cookie, ifi, tb);
358*f7c14bbaSAndroid Build Coastguard Worker }
359*f7c14bbaSAndroid Build Coastguard Worker
get_xdp_info(void * cookie,void * msg,struct nlattr ** tb)360*f7c14bbaSAndroid Build Coastguard Worker static int get_xdp_info(void *cookie, void *msg, struct nlattr **tb)
361*f7c14bbaSAndroid Build Coastguard Worker {
362*f7c14bbaSAndroid Build Coastguard Worker struct nlattr *xdp_tb[IFLA_XDP_MAX + 1];
363*f7c14bbaSAndroid Build Coastguard Worker struct xdp_id_md *xdp_id = cookie;
364*f7c14bbaSAndroid Build Coastguard Worker struct ifinfomsg *ifinfo = msg;
365*f7c14bbaSAndroid Build Coastguard Worker int ret;
366*f7c14bbaSAndroid Build Coastguard Worker
367*f7c14bbaSAndroid Build Coastguard Worker if (xdp_id->ifindex && xdp_id->ifindex != ifinfo->ifi_index)
368*f7c14bbaSAndroid Build Coastguard Worker return 0;
369*f7c14bbaSAndroid Build Coastguard Worker
370*f7c14bbaSAndroid Build Coastguard Worker if (!tb[IFLA_XDP])
371*f7c14bbaSAndroid Build Coastguard Worker return 0;
372*f7c14bbaSAndroid Build Coastguard Worker
373*f7c14bbaSAndroid Build Coastguard Worker ret = libbpf_nla_parse_nested(xdp_tb, IFLA_XDP_MAX, tb[IFLA_XDP], NULL);
374*f7c14bbaSAndroid Build Coastguard Worker if (ret)
375*f7c14bbaSAndroid Build Coastguard Worker return ret;
376*f7c14bbaSAndroid Build Coastguard Worker
377*f7c14bbaSAndroid Build Coastguard Worker if (!xdp_tb[IFLA_XDP_ATTACHED])
378*f7c14bbaSAndroid Build Coastguard Worker return 0;
379*f7c14bbaSAndroid Build Coastguard Worker
380*f7c14bbaSAndroid Build Coastguard Worker xdp_id->info.attach_mode = libbpf_nla_getattr_u8(
381*f7c14bbaSAndroid Build Coastguard Worker xdp_tb[IFLA_XDP_ATTACHED]);
382*f7c14bbaSAndroid Build Coastguard Worker
383*f7c14bbaSAndroid Build Coastguard Worker if (xdp_id->info.attach_mode == XDP_ATTACHED_NONE)
384*f7c14bbaSAndroid Build Coastguard Worker return 0;
385*f7c14bbaSAndroid Build Coastguard Worker
386*f7c14bbaSAndroid Build Coastguard Worker if (xdp_tb[IFLA_XDP_PROG_ID])
387*f7c14bbaSAndroid Build Coastguard Worker xdp_id->info.prog_id = libbpf_nla_getattr_u32(
388*f7c14bbaSAndroid Build Coastguard Worker xdp_tb[IFLA_XDP_PROG_ID]);
389*f7c14bbaSAndroid Build Coastguard Worker
390*f7c14bbaSAndroid Build Coastguard Worker if (xdp_tb[IFLA_XDP_SKB_PROG_ID])
391*f7c14bbaSAndroid Build Coastguard Worker xdp_id->info.skb_prog_id = libbpf_nla_getattr_u32(
392*f7c14bbaSAndroid Build Coastguard Worker xdp_tb[IFLA_XDP_SKB_PROG_ID]);
393*f7c14bbaSAndroid Build Coastguard Worker
394*f7c14bbaSAndroid Build Coastguard Worker if (xdp_tb[IFLA_XDP_DRV_PROG_ID])
395*f7c14bbaSAndroid Build Coastguard Worker xdp_id->info.drv_prog_id = libbpf_nla_getattr_u32(
396*f7c14bbaSAndroid Build Coastguard Worker xdp_tb[IFLA_XDP_DRV_PROG_ID]);
397*f7c14bbaSAndroid Build Coastguard Worker
398*f7c14bbaSAndroid Build Coastguard Worker if (xdp_tb[IFLA_XDP_HW_PROG_ID])
399*f7c14bbaSAndroid Build Coastguard Worker xdp_id->info.hw_prog_id = libbpf_nla_getattr_u32(
400*f7c14bbaSAndroid Build Coastguard Worker xdp_tb[IFLA_XDP_HW_PROG_ID]);
401*f7c14bbaSAndroid Build Coastguard Worker
402*f7c14bbaSAndroid Build Coastguard Worker return 0;
403*f7c14bbaSAndroid Build Coastguard Worker }
404*f7c14bbaSAndroid Build Coastguard Worker
parse_xdp_features(struct nlmsghdr * nh,libbpf_dump_nlmsg_t fn,void * cookie)405*f7c14bbaSAndroid Build Coastguard Worker static int parse_xdp_features(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn,
406*f7c14bbaSAndroid Build Coastguard Worker void *cookie)
407*f7c14bbaSAndroid Build Coastguard Worker {
408*f7c14bbaSAndroid Build Coastguard Worker struct genlmsghdr *gnl = NLMSG_DATA(nh);
409*f7c14bbaSAndroid Build Coastguard Worker struct nlattr *na = (struct nlattr *)((void *)gnl + GENL_HDRLEN);
410*f7c14bbaSAndroid Build Coastguard Worker struct nlattr *tb[NETDEV_CMD_MAX + 1];
411*f7c14bbaSAndroid Build Coastguard Worker struct xdp_features_md *md = cookie;
412*f7c14bbaSAndroid Build Coastguard Worker __u32 ifindex;
413*f7c14bbaSAndroid Build Coastguard Worker
414*f7c14bbaSAndroid Build Coastguard Worker libbpf_nla_parse(tb, NETDEV_CMD_MAX, na,
415*f7c14bbaSAndroid Build Coastguard Worker NLMSG_PAYLOAD(nh, sizeof(*gnl)), NULL);
416*f7c14bbaSAndroid Build Coastguard Worker
417*f7c14bbaSAndroid Build Coastguard Worker if (!tb[NETDEV_A_DEV_IFINDEX] || !tb[NETDEV_A_DEV_XDP_FEATURES])
418*f7c14bbaSAndroid Build Coastguard Worker return NL_CONT;
419*f7c14bbaSAndroid Build Coastguard Worker
420*f7c14bbaSAndroid Build Coastguard Worker ifindex = libbpf_nla_getattr_u32(tb[NETDEV_A_DEV_IFINDEX]);
421*f7c14bbaSAndroid Build Coastguard Worker if (ifindex != md->ifindex)
422*f7c14bbaSAndroid Build Coastguard Worker return NL_CONT;
423*f7c14bbaSAndroid Build Coastguard Worker
424*f7c14bbaSAndroid Build Coastguard Worker md->flags = libbpf_nla_getattr_u64(tb[NETDEV_A_DEV_XDP_FEATURES]);
425*f7c14bbaSAndroid Build Coastguard Worker if (tb[NETDEV_A_DEV_XDP_ZC_MAX_SEGS])
426*f7c14bbaSAndroid Build Coastguard Worker md->xdp_zc_max_segs =
427*f7c14bbaSAndroid Build Coastguard Worker libbpf_nla_getattr_u32(tb[NETDEV_A_DEV_XDP_ZC_MAX_SEGS]);
428*f7c14bbaSAndroid Build Coastguard Worker return NL_DONE;
429*f7c14bbaSAndroid Build Coastguard Worker }
430*f7c14bbaSAndroid Build Coastguard Worker
bpf_xdp_query(int ifindex,int xdp_flags,struct bpf_xdp_query_opts * opts)431*f7c14bbaSAndroid Build Coastguard Worker int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
432*f7c14bbaSAndroid Build Coastguard Worker {
433*f7c14bbaSAndroid Build Coastguard Worker struct libbpf_nla_req req = {
434*f7c14bbaSAndroid Build Coastguard Worker .nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
435*f7c14bbaSAndroid Build Coastguard Worker .nh.nlmsg_type = RTM_GETLINK,
436*f7c14bbaSAndroid Build Coastguard Worker .nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
437*f7c14bbaSAndroid Build Coastguard Worker .ifinfo.ifi_family = AF_PACKET,
438*f7c14bbaSAndroid Build Coastguard Worker };
439*f7c14bbaSAndroid Build Coastguard Worker struct xdp_id_md xdp_id = {};
440*f7c14bbaSAndroid Build Coastguard Worker struct xdp_features_md md = {
441*f7c14bbaSAndroid Build Coastguard Worker .ifindex = ifindex,
442*f7c14bbaSAndroid Build Coastguard Worker };
443*f7c14bbaSAndroid Build Coastguard Worker __u16 id;
444*f7c14bbaSAndroid Build Coastguard Worker int err;
445*f7c14bbaSAndroid Build Coastguard Worker
446*f7c14bbaSAndroid Build Coastguard Worker if (!OPTS_VALID(opts, bpf_xdp_query_opts))
447*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
448*f7c14bbaSAndroid Build Coastguard Worker
449*f7c14bbaSAndroid Build Coastguard Worker if (xdp_flags & ~XDP_FLAGS_MASK)
450*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
451*f7c14bbaSAndroid Build Coastguard Worker
452*f7c14bbaSAndroid Build Coastguard Worker /* Check whether the single {HW,DRV,SKB} mode is set */
453*f7c14bbaSAndroid Build Coastguard Worker xdp_flags &= XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE;
454*f7c14bbaSAndroid Build Coastguard Worker if (xdp_flags & (xdp_flags - 1))
455*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
456*f7c14bbaSAndroid Build Coastguard Worker
457*f7c14bbaSAndroid Build Coastguard Worker xdp_id.ifindex = ifindex;
458*f7c14bbaSAndroid Build Coastguard Worker xdp_id.flags = xdp_flags;
459*f7c14bbaSAndroid Build Coastguard Worker
460*f7c14bbaSAndroid Build Coastguard Worker err = libbpf_netlink_send_recv(&req, NETLINK_ROUTE, __dump_link_nlmsg,
461*f7c14bbaSAndroid Build Coastguard Worker get_xdp_info, &xdp_id);
462*f7c14bbaSAndroid Build Coastguard Worker if (err)
463*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(err);
464*f7c14bbaSAndroid Build Coastguard Worker
465*f7c14bbaSAndroid Build Coastguard Worker OPTS_SET(opts, prog_id, xdp_id.info.prog_id);
466*f7c14bbaSAndroid Build Coastguard Worker OPTS_SET(opts, drv_prog_id, xdp_id.info.drv_prog_id);
467*f7c14bbaSAndroid Build Coastguard Worker OPTS_SET(opts, hw_prog_id, xdp_id.info.hw_prog_id);
468*f7c14bbaSAndroid Build Coastguard Worker OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id);
469*f7c14bbaSAndroid Build Coastguard Worker OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode);
470*f7c14bbaSAndroid Build Coastguard Worker
471*f7c14bbaSAndroid Build Coastguard Worker if (!OPTS_HAS(opts, feature_flags))
472*f7c14bbaSAndroid Build Coastguard Worker return 0;
473*f7c14bbaSAndroid Build Coastguard Worker
474*f7c14bbaSAndroid Build Coastguard Worker err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id);
475*f7c14bbaSAndroid Build Coastguard Worker if (err < 0) {
476*f7c14bbaSAndroid Build Coastguard Worker if (err == -ENOENT) {
477*f7c14bbaSAndroid Build Coastguard Worker opts->feature_flags = 0;
478*f7c14bbaSAndroid Build Coastguard Worker goto skip_feature_flags;
479*f7c14bbaSAndroid Build Coastguard Worker }
480*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(err);
481*f7c14bbaSAndroid Build Coastguard Worker }
482*f7c14bbaSAndroid Build Coastguard Worker
483*f7c14bbaSAndroid Build Coastguard Worker memset(&req, 0, sizeof(req));
484*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
485*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_flags = NLM_F_REQUEST;
486*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_type = id;
487*f7c14bbaSAndroid Build Coastguard Worker req.gnl.cmd = NETDEV_CMD_DEV_GET;
488*f7c14bbaSAndroid Build Coastguard Worker req.gnl.version = 2;
489*f7c14bbaSAndroid Build Coastguard Worker
490*f7c14bbaSAndroid Build Coastguard Worker err = nlattr_add(&req, NETDEV_A_DEV_IFINDEX, &ifindex, sizeof(ifindex));
491*f7c14bbaSAndroid Build Coastguard Worker if (err < 0)
492*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(err);
493*f7c14bbaSAndroid Build Coastguard Worker
494*f7c14bbaSAndroid Build Coastguard Worker err = libbpf_netlink_send_recv(&req, NETLINK_GENERIC,
495*f7c14bbaSAndroid Build Coastguard Worker parse_xdp_features, NULL, &md);
496*f7c14bbaSAndroid Build Coastguard Worker if (err)
497*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(err);
498*f7c14bbaSAndroid Build Coastguard Worker
499*f7c14bbaSAndroid Build Coastguard Worker OPTS_SET(opts, feature_flags, md.flags);
500*f7c14bbaSAndroid Build Coastguard Worker OPTS_SET(opts, xdp_zc_max_segs, md.xdp_zc_max_segs);
501*f7c14bbaSAndroid Build Coastguard Worker
502*f7c14bbaSAndroid Build Coastguard Worker skip_feature_flags:
503*f7c14bbaSAndroid Build Coastguard Worker return 0;
504*f7c14bbaSAndroid Build Coastguard Worker }
505*f7c14bbaSAndroid Build Coastguard Worker
bpf_xdp_query_id(int ifindex,int flags,__u32 * prog_id)506*f7c14bbaSAndroid Build Coastguard Worker int bpf_xdp_query_id(int ifindex, int flags, __u32 *prog_id)
507*f7c14bbaSAndroid Build Coastguard Worker {
508*f7c14bbaSAndroid Build Coastguard Worker LIBBPF_OPTS(bpf_xdp_query_opts, opts);
509*f7c14bbaSAndroid Build Coastguard Worker int ret;
510*f7c14bbaSAndroid Build Coastguard Worker
511*f7c14bbaSAndroid Build Coastguard Worker ret = bpf_xdp_query(ifindex, flags, &opts);
512*f7c14bbaSAndroid Build Coastguard Worker if (ret)
513*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(ret);
514*f7c14bbaSAndroid Build Coastguard Worker
515*f7c14bbaSAndroid Build Coastguard Worker flags &= XDP_FLAGS_MODES;
516*f7c14bbaSAndroid Build Coastguard Worker
517*f7c14bbaSAndroid Build Coastguard Worker if (opts.attach_mode != XDP_ATTACHED_MULTI && !flags)
518*f7c14bbaSAndroid Build Coastguard Worker *prog_id = opts.prog_id;
519*f7c14bbaSAndroid Build Coastguard Worker else if (flags & XDP_FLAGS_DRV_MODE)
520*f7c14bbaSAndroid Build Coastguard Worker *prog_id = opts.drv_prog_id;
521*f7c14bbaSAndroid Build Coastguard Worker else if (flags & XDP_FLAGS_HW_MODE)
522*f7c14bbaSAndroid Build Coastguard Worker *prog_id = opts.hw_prog_id;
523*f7c14bbaSAndroid Build Coastguard Worker else if (flags & XDP_FLAGS_SKB_MODE)
524*f7c14bbaSAndroid Build Coastguard Worker *prog_id = opts.skb_prog_id;
525*f7c14bbaSAndroid Build Coastguard Worker else
526*f7c14bbaSAndroid Build Coastguard Worker *prog_id = 0;
527*f7c14bbaSAndroid Build Coastguard Worker
528*f7c14bbaSAndroid Build Coastguard Worker return 0;
529*f7c14bbaSAndroid Build Coastguard Worker }
530*f7c14bbaSAndroid Build Coastguard Worker
531*f7c14bbaSAndroid Build Coastguard Worker
532*f7c14bbaSAndroid Build Coastguard Worker typedef int (*qdisc_config_t)(struct libbpf_nla_req *req);
533*f7c14bbaSAndroid Build Coastguard Worker
clsact_config(struct libbpf_nla_req * req)534*f7c14bbaSAndroid Build Coastguard Worker static int clsact_config(struct libbpf_nla_req *req)
535*f7c14bbaSAndroid Build Coastguard Worker {
536*f7c14bbaSAndroid Build Coastguard Worker req->tc.tcm_parent = TC_H_CLSACT;
537*f7c14bbaSAndroid Build Coastguard Worker req->tc.tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0);
538*f7c14bbaSAndroid Build Coastguard Worker
539*f7c14bbaSAndroid Build Coastguard Worker return nlattr_add(req, TCA_KIND, "clsact", sizeof("clsact"));
540*f7c14bbaSAndroid Build Coastguard Worker }
541*f7c14bbaSAndroid Build Coastguard Worker
attach_point_to_config(struct bpf_tc_hook * hook,qdisc_config_t * config)542*f7c14bbaSAndroid Build Coastguard Worker static int attach_point_to_config(struct bpf_tc_hook *hook,
543*f7c14bbaSAndroid Build Coastguard Worker qdisc_config_t *config)
544*f7c14bbaSAndroid Build Coastguard Worker {
545*f7c14bbaSAndroid Build Coastguard Worker switch (OPTS_GET(hook, attach_point, 0)) {
546*f7c14bbaSAndroid Build Coastguard Worker case BPF_TC_INGRESS:
547*f7c14bbaSAndroid Build Coastguard Worker case BPF_TC_EGRESS:
548*f7c14bbaSAndroid Build Coastguard Worker case BPF_TC_INGRESS | BPF_TC_EGRESS:
549*f7c14bbaSAndroid Build Coastguard Worker if (OPTS_GET(hook, parent, 0))
550*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
551*f7c14bbaSAndroid Build Coastguard Worker *config = &clsact_config;
552*f7c14bbaSAndroid Build Coastguard Worker return 0;
553*f7c14bbaSAndroid Build Coastguard Worker case BPF_TC_CUSTOM:
554*f7c14bbaSAndroid Build Coastguard Worker return -EOPNOTSUPP;
555*f7c14bbaSAndroid Build Coastguard Worker default:
556*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
557*f7c14bbaSAndroid Build Coastguard Worker }
558*f7c14bbaSAndroid Build Coastguard Worker }
559*f7c14bbaSAndroid Build Coastguard Worker
tc_get_tcm_parent(enum bpf_tc_attach_point attach_point,__u32 * parent)560*f7c14bbaSAndroid Build Coastguard Worker static int tc_get_tcm_parent(enum bpf_tc_attach_point attach_point,
561*f7c14bbaSAndroid Build Coastguard Worker __u32 *parent)
562*f7c14bbaSAndroid Build Coastguard Worker {
563*f7c14bbaSAndroid Build Coastguard Worker switch (attach_point) {
564*f7c14bbaSAndroid Build Coastguard Worker case BPF_TC_INGRESS:
565*f7c14bbaSAndroid Build Coastguard Worker case BPF_TC_EGRESS:
566*f7c14bbaSAndroid Build Coastguard Worker if (*parent)
567*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
568*f7c14bbaSAndroid Build Coastguard Worker *parent = TC_H_MAKE(TC_H_CLSACT,
569*f7c14bbaSAndroid Build Coastguard Worker attach_point == BPF_TC_INGRESS ?
570*f7c14bbaSAndroid Build Coastguard Worker TC_H_MIN_INGRESS : TC_H_MIN_EGRESS);
571*f7c14bbaSAndroid Build Coastguard Worker break;
572*f7c14bbaSAndroid Build Coastguard Worker case BPF_TC_CUSTOM:
573*f7c14bbaSAndroid Build Coastguard Worker if (!*parent)
574*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
575*f7c14bbaSAndroid Build Coastguard Worker break;
576*f7c14bbaSAndroid Build Coastguard Worker default:
577*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
578*f7c14bbaSAndroid Build Coastguard Worker }
579*f7c14bbaSAndroid Build Coastguard Worker return 0;
580*f7c14bbaSAndroid Build Coastguard Worker }
581*f7c14bbaSAndroid Build Coastguard Worker
tc_qdisc_modify(struct bpf_tc_hook * hook,int cmd,int flags)582*f7c14bbaSAndroid Build Coastguard Worker static int tc_qdisc_modify(struct bpf_tc_hook *hook, int cmd, int flags)
583*f7c14bbaSAndroid Build Coastguard Worker {
584*f7c14bbaSAndroid Build Coastguard Worker qdisc_config_t config;
585*f7c14bbaSAndroid Build Coastguard Worker int ret;
586*f7c14bbaSAndroid Build Coastguard Worker struct libbpf_nla_req req;
587*f7c14bbaSAndroid Build Coastguard Worker
588*f7c14bbaSAndroid Build Coastguard Worker ret = attach_point_to_config(hook, &config);
589*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
590*f7c14bbaSAndroid Build Coastguard Worker return ret;
591*f7c14bbaSAndroid Build Coastguard Worker
592*f7c14bbaSAndroid Build Coastguard Worker memset(&req, 0, sizeof(req));
593*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
594*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
595*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_type = cmd;
596*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_family = AF_UNSPEC;
597*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_ifindex = OPTS_GET(hook, ifindex, 0);
598*f7c14bbaSAndroid Build Coastguard Worker
599*f7c14bbaSAndroid Build Coastguard Worker ret = config(&req);
600*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
601*f7c14bbaSAndroid Build Coastguard Worker return ret;
602*f7c14bbaSAndroid Build Coastguard Worker
603*f7c14bbaSAndroid Build Coastguard Worker return libbpf_netlink_send_recv(&req, NETLINK_ROUTE, NULL, NULL, NULL);
604*f7c14bbaSAndroid Build Coastguard Worker }
605*f7c14bbaSAndroid Build Coastguard Worker
tc_qdisc_create_excl(struct bpf_tc_hook * hook)606*f7c14bbaSAndroid Build Coastguard Worker static int tc_qdisc_create_excl(struct bpf_tc_hook *hook)
607*f7c14bbaSAndroid Build Coastguard Worker {
608*f7c14bbaSAndroid Build Coastguard Worker return tc_qdisc_modify(hook, RTM_NEWQDISC, NLM_F_CREATE | NLM_F_EXCL);
609*f7c14bbaSAndroid Build Coastguard Worker }
610*f7c14bbaSAndroid Build Coastguard Worker
tc_qdisc_delete(struct bpf_tc_hook * hook)611*f7c14bbaSAndroid Build Coastguard Worker static int tc_qdisc_delete(struct bpf_tc_hook *hook)
612*f7c14bbaSAndroid Build Coastguard Worker {
613*f7c14bbaSAndroid Build Coastguard Worker return tc_qdisc_modify(hook, RTM_DELQDISC, 0);
614*f7c14bbaSAndroid Build Coastguard Worker }
615*f7c14bbaSAndroid Build Coastguard Worker
bpf_tc_hook_create(struct bpf_tc_hook * hook)616*f7c14bbaSAndroid Build Coastguard Worker int bpf_tc_hook_create(struct bpf_tc_hook *hook)
617*f7c14bbaSAndroid Build Coastguard Worker {
618*f7c14bbaSAndroid Build Coastguard Worker int ret;
619*f7c14bbaSAndroid Build Coastguard Worker
620*f7c14bbaSAndroid Build Coastguard Worker if (!hook || !OPTS_VALID(hook, bpf_tc_hook) ||
621*f7c14bbaSAndroid Build Coastguard Worker OPTS_GET(hook, ifindex, 0) <= 0)
622*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
623*f7c14bbaSAndroid Build Coastguard Worker
624*f7c14bbaSAndroid Build Coastguard Worker ret = tc_qdisc_create_excl(hook);
625*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(ret);
626*f7c14bbaSAndroid Build Coastguard Worker }
627*f7c14bbaSAndroid Build Coastguard Worker
628*f7c14bbaSAndroid Build Coastguard Worker static int __bpf_tc_detach(const struct bpf_tc_hook *hook,
629*f7c14bbaSAndroid Build Coastguard Worker const struct bpf_tc_opts *opts,
630*f7c14bbaSAndroid Build Coastguard Worker const bool flush);
631*f7c14bbaSAndroid Build Coastguard Worker
bpf_tc_hook_destroy(struct bpf_tc_hook * hook)632*f7c14bbaSAndroid Build Coastguard Worker int bpf_tc_hook_destroy(struct bpf_tc_hook *hook)
633*f7c14bbaSAndroid Build Coastguard Worker {
634*f7c14bbaSAndroid Build Coastguard Worker if (!hook || !OPTS_VALID(hook, bpf_tc_hook) ||
635*f7c14bbaSAndroid Build Coastguard Worker OPTS_GET(hook, ifindex, 0) <= 0)
636*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
637*f7c14bbaSAndroid Build Coastguard Worker
638*f7c14bbaSAndroid Build Coastguard Worker switch (OPTS_GET(hook, attach_point, 0)) {
639*f7c14bbaSAndroid Build Coastguard Worker case BPF_TC_INGRESS:
640*f7c14bbaSAndroid Build Coastguard Worker case BPF_TC_EGRESS:
641*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(__bpf_tc_detach(hook, NULL, true));
642*f7c14bbaSAndroid Build Coastguard Worker case BPF_TC_INGRESS | BPF_TC_EGRESS:
643*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(tc_qdisc_delete(hook));
644*f7c14bbaSAndroid Build Coastguard Worker case BPF_TC_CUSTOM:
645*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EOPNOTSUPP);
646*f7c14bbaSAndroid Build Coastguard Worker default:
647*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
648*f7c14bbaSAndroid Build Coastguard Worker }
649*f7c14bbaSAndroid Build Coastguard Worker }
650*f7c14bbaSAndroid Build Coastguard Worker
651*f7c14bbaSAndroid Build Coastguard Worker struct bpf_cb_ctx {
652*f7c14bbaSAndroid Build Coastguard Worker struct bpf_tc_opts *opts;
653*f7c14bbaSAndroid Build Coastguard Worker bool processed;
654*f7c14bbaSAndroid Build Coastguard Worker };
655*f7c14bbaSAndroid Build Coastguard Worker
__get_tc_info(void * cookie,struct tcmsg * tc,struct nlattr ** tb,bool unicast)656*f7c14bbaSAndroid Build Coastguard Worker static int __get_tc_info(void *cookie, struct tcmsg *tc, struct nlattr **tb,
657*f7c14bbaSAndroid Build Coastguard Worker bool unicast)
658*f7c14bbaSAndroid Build Coastguard Worker {
659*f7c14bbaSAndroid Build Coastguard Worker struct nlattr *tbb[TCA_BPF_MAX + 1];
660*f7c14bbaSAndroid Build Coastguard Worker struct bpf_cb_ctx *info = cookie;
661*f7c14bbaSAndroid Build Coastguard Worker
662*f7c14bbaSAndroid Build Coastguard Worker if (!info || !info->opts)
663*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
664*f7c14bbaSAndroid Build Coastguard Worker if (unicast && info->processed)
665*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
666*f7c14bbaSAndroid Build Coastguard Worker if (!tb[TCA_OPTIONS])
667*f7c14bbaSAndroid Build Coastguard Worker return NL_CONT;
668*f7c14bbaSAndroid Build Coastguard Worker
669*f7c14bbaSAndroid Build Coastguard Worker libbpf_nla_parse_nested(tbb, TCA_BPF_MAX, tb[TCA_OPTIONS], NULL);
670*f7c14bbaSAndroid Build Coastguard Worker if (!tbb[TCA_BPF_ID])
671*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
672*f7c14bbaSAndroid Build Coastguard Worker
673*f7c14bbaSAndroid Build Coastguard Worker OPTS_SET(info->opts, prog_id, libbpf_nla_getattr_u32(tbb[TCA_BPF_ID]));
674*f7c14bbaSAndroid Build Coastguard Worker OPTS_SET(info->opts, handle, tc->tcm_handle);
675*f7c14bbaSAndroid Build Coastguard Worker OPTS_SET(info->opts, priority, TC_H_MAJ(tc->tcm_info) >> 16);
676*f7c14bbaSAndroid Build Coastguard Worker
677*f7c14bbaSAndroid Build Coastguard Worker info->processed = true;
678*f7c14bbaSAndroid Build Coastguard Worker return unicast ? NL_NEXT : NL_DONE;
679*f7c14bbaSAndroid Build Coastguard Worker }
680*f7c14bbaSAndroid Build Coastguard Worker
get_tc_info(struct nlmsghdr * nh,libbpf_dump_nlmsg_t fn,void * cookie)681*f7c14bbaSAndroid Build Coastguard Worker static int get_tc_info(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn,
682*f7c14bbaSAndroid Build Coastguard Worker void *cookie)
683*f7c14bbaSAndroid Build Coastguard Worker {
684*f7c14bbaSAndroid Build Coastguard Worker struct tcmsg *tc = NLMSG_DATA(nh);
685*f7c14bbaSAndroid Build Coastguard Worker struct nlattr *tb[TCA_MAX + 1];
686*f7c14bbaSAndroid Build Coastguard Worker
687*f7c14bbaSAndroid Build Coastguard Worker libbpf_nla_parse(tb, TCA_MAX,
688*f7c14bbaSAndroid Build Coastguard Worker (struct nlattr *)((void *)tc + NLMSG_ALIGN(sizeof(*tc))),
689*f7c14bbaSAndroid Build Coastguard Worker NLMSG_PAYLOAD(nh, sizeof(*tc)), NULL);
690*f7c14bbaSAndroid Build Coastguard Worker if (!tb[TCA_KIND])
691*f7c14bbaSAndroid Build Coastguard Worker return NL_CONT;
692*f7c14bbaSAndroid Build Coastguard Worker return __get_tc_info(cookie, tc, tb, nh->nlmsg_flags & NLM_F_ECHO);
693*f7c14bbaSAndroid Build Coastguard Worker }
694*f7c14bbaSAndroid Build Coastguard Worker
tc_add_fd_and_name(struct libbpf_nla_req * req,int fd)695*f7c14bbaSAndroid Build Coastguard Worker static int tc_add_fd_and_name(struct libbpf_nla_req *req, int fd)
696*f7c14bbaSAndroid Build Coastguard Worker {
697*f7c14bbaSAndroid Build Coastguard Worker struct bpf_prog_info info;
698*f7c14bbaSAndroid Build Coastguard Worker __u32 info_len = sizeof(info);
699*f7c14bbaSAndroid Build Coastguard Worker char name[256];
700*f7c14bbaSAndroid Build Coastguard Worker int len, ret;
701*f7c14bbaSAndroid Build Coastguard Worker
702*f7c14bbaSAndroid Build Coastguard Worker memset(&info, 0, info_len);
703*f7c14bbaSAndroid Build Coastguard Worker ret = bpf_prog_get_info_by_fd(fd, &info, &info_len);
704*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
705*f7c14bbaSAndroid Build Coastguard Worker return ret;
706*f7c14bbaSAndroid Build Coastguard Worker
707*f7c14bbaSAndroid Build Coastguard Worker ret = nlattr_add(req, TCA_BPF_FD, &fd, sizeof(fd));
708*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
709*f7c14bbaSAndroid Build Coastguard Worker return ret;
710*f7c14bbaSAndroid Build Coastguard Worker len = snprintf(name, sizeof(name), "%s:[%u]", info.name, info.id);
711*f7c14bbaSAndroid Build Coastguard Worker if (len < 0)
712*f7c14bbaSAndroid Build Coastguard Worker return -errno;
713*f7c14bbaSAndroid Build Coastguard Worker if (len >= sizeof(name))
714*f7c14bbaSAndroid Build Coastguard Worker return -ENAMETOOLONG;
715*f7c14bbaSAndroid Build Coastguard Worker return nlattr_add(req, TCA_BPF_NAME, name, len + 1);
716*f7c14bbaSAndroid Build Coastguard Worker }
717*f7c14bbaSAndroid Build Coastguard Worker
bpf_tc_attach(const struct bpf_tc_hook * hook,struct bpf_tc_opts * opts)718*f7c14bbaSAndroid Build Coastguard Worker int bpf_tc_attach(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
719*f7c14bbaSAndroid Build Coastguard Worker {
720*f7c14bbaSAndroid Build Coastguard Worker __u32 protocol, bpf_flags, handle, priority, parent, prog_id, flags;
721*f7c14bbaSAndroid Build Coastguard Worker int ret, ifindex, attach_point, prog_fd;
722*f7c14bbaSAndroid Build Coastguard Worker struct bpf_cb_ctx info = {};
723*f7c14bbaSAndroid Build Coastguard Worker struct libbpf_nla_req req;
724*f7c14bbaSAndroid Build Coastguard Worker struct nlattr *nla;
725*f7c14bbaSAndroid Build Coastguard Worker
726*f7c14bbaSAndroid Build Coastguard Worker if (!hook || !opts ||
727*f7c14bbaSAndroid Build Coastguard Worker !OPTS_VALID(hook, bpf_tc_hook) ||
728*f7c14bbaSAndroid Build Coastguard Worker !OPTS_VALID(opts, bpf_tc_opts))
729*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
730*f7c14bbaSAndroid Build Coastguard Worker
731*f7c14bbaSAndroid Build Coastguard Worker ifindex = OPTS_GET(hook, ifindex, 0);
732*f7c14bbaSAndroid Build Coastguard Worker parent = OPTS_GET(hook, parent, 0);
733*f7c14bbaSAndroid Build Coastguard Worker attach_point = OPTS_GET(hook, attach_point, 0);
734*f7c14bbaSAndroid Build Coastguard Worker
735*f7c14bbaSAndroid Build Coastguard Worker handle = OPTS_GET(opts, handle, 0);
736*f7c14bbaSAndroid Build Coastguard Worker priority = OPTS_GET(opts, priority, 0);
737*f7c14bbaSAndroid Build Coastguard Worker prog_fd = OPTS_GET(opts, prog_fd, 0);
738*f7c14bbaSAndroid Build Coastguard Worker prog_id = OPTS_GET(opts, prog_id, 0);
739*f7c14bbaSAndroid Build Coastguard Worker flags = OPTS_GET(opts, flags, 0);
740*f7c14bbaSAndroid Build Coastguard Worker
741*f7c14bbaSAndroid Build Coastguard Worker if (ifindex <= 0 || !prog_fd || prog_id)
742*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
743*f7c14bbaSAndroid Build Coastguard Worker if (priority > UINT16_MAX)
744*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
745*f7c14bbaSAndroid Build Coastguard Worker if (flags & ~BPF_TC_F_REPLACE)
746*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
747*f7c14bbaSAndroid Build Coastguard Worker
748*f7c14bbaSAndroid Build Coastguard Worker flags = (flags & BPF_TC_F_REPLACE) ? NLM_F_REPLACE : NLM_F_EXCL;
749*f7c14bbaSAndroid Build Coastguard Worker protocol = ETH_P_ALL;
750*f7c14bbaSAndroid Build Coastguard Worker
751*f7c14bbaSAndroid Build Coastguard Worker memset(&req, 0, sizeof(req));
752*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
753*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE |
754*f7c14bbaSAndroid Build Coastguard Worker NLM_F_ECHO | flags;
755*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_type = RTM_NEWTFILTER;
756*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_family = AF_UNSPEC;
757*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_ifindex = ifindex;
758*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_handle = handle;
759*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_info = TC_H_MAKE(priority << 16, htons(protocol));
760*f7c14bbaSAndroid Build Coastguard Worker
761*f7c14bbaSAndroid Build Coastguard Worker ret = tc_get_tcm_parent(attach_point, &parent);
762*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
763*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(ret);
764*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_parent = parent;
765*f7c14bbaSAndroid Build Coastguard Worker
766*f7c14bbaSAndroid Build Coastguard Worker ret = nlattr_add(&req, TCA_KIND, "bpf", sizeof("bpf"));
767*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
768*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(ret);
769*f7c14bbaSAndroid Build Coastguard Worker nla = nlattr_begin_nested(&req, TCA_OPTIONS);
770*f7c14bbaSAndroid Build Coastguard Worker if (!nla)
771*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EMSGSIZE);
772*f7c14bbaSAndroid Build Coastguard Worker ret = tc_add_fd_and_name(&req, prog_fd);
773*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
774*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(ret);
775*f7c14bbaSAndroid Build Coastguard Worker bpf_flags = TCA_BPF_FLAG_ACT_DIRECT;
776*f7c14bbaSAndroid Build Coastguard Worker ret = nlattr_add(&req, TCA_BPF_FLAGS, &bpf_flags, sizeof(bpf_flags));
777*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
778*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(ret);
779*f7c14bbaSAndroid Build Coastguard Worker nlattr_end_nested(&req, nla);
780*f7c14bbaSAndroid Build Coastguard Worker
781*f7c14bbaSAndroid Build Coastguard Worker info.opts = opts;
782*f7c14bbaSAndroid Build Coastguard Worker
783*f7c14bbaSAndroid Build Coastguard Worker ret = libbpf_netlink_send_recv(&req, NETLINK_ROUTE, get_tc_info, NULL,
784*f7c14bbaSAndroid Build Coastguard Worker &info);
785*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
786*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(ret);
787*f7c14bbaSAndroid Build Coastguard Worker if (!info.processed)
788*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-ENOENT);
789*f7c14bbaSAndroid Build Coastguard Worker return ret;
790*f7c14bbaSAndroid Build Coastguard Worker }
791*f7c14bbaSAndroid Build Coastguard Worker
__bpf_tc_detach(const struct bpf_tc_hook * hook,const struct bpf_tc_opts * opts,const bool flush)792*f7c14bbaSAndroid Build Coastguard Worker static int __bpf_tc_detach(const struct bpf_tc_hook *hook,
793*f7c14bbaSAndroid Build Coastguard Worker const struct bpf_tc_opts *opts,
794*f7c14bbaSAndroid Build Coastguard Worker const bool flush)
795*f7c14bbaSAndroid Build Coastguard Worker {
796*f7c14bbaSAndroid Build Coastguard Worker __u32 protocol = 0, handle, priority, parent, prog_id, flags;
797*f7c14bbaSAndroid Build Coastguard Worker int ret, ifindex, attach_point, prog_fd;
798*f7c14bbaSAndroid Build Coastguard Worker struct libbpf_nla_req req;
799*f7c14bbaSAndroid Build Coastguard Worker
800*f7c14bbaSAndroid Build Coastguard Worker if (!hook ||
801*f7c14bbaSAndroid Build Coastguard Worker !OPTS_VALID(hook, bpf_tc_hook) ||
802*f7c14bbaSAndroid Build Coastguard Worker !OPTS_VALID(opts, bpf_tc_opts))
803*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
804*f7c14bbaSAndroid Build Coastguard Worker
805*f7c14bbaSAndroid Build Coastguard Worker ifindex = OPTS_GET(hook, ifindex, 0);
806*f7c14bbaSAndroid Build Coastguard Worker parent = OPTS_GET(hook, parent, 0);
807*f7c14bbaSAndroid Build Coastguard Worker attach_point = OPTS_GET(hook, attach_point, 0);
808*f7c14bbaSAndroid Build Coastguard Worker
809*f7c14bbaSAndroid Build Coastguard Worker handle = OPTS_GET(opts, handle, 0);
810*f7c14bbaSAndroid Build Coastguard Worker priority = OPTS_GET(opts, priority, 0);
811*f7c14bbaSAndroid Build Coastguard Worker prog_fd = OPTS_GET(opts, prog_fd, 0);
812*f7c14bbaSAndroid Build Coastguard Worker prog_id = OPTS_GET(opts, prog_id, 0);
813*f7c14bbaSAndroid Build Coastguard Worker flags = OPTS_GET(opts, flags, 0);
814*f7c14bbaSAndroid Build Coastguard Worker
815*f7c14bbaSAndroid Build Coastguard Worker if (ifindex <= 0 || flags || prog_fd || prog_id)
816*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
817*f7c14bbaSAndroid Build Coastguard Worker if (priority > UINT16_MAX)
818*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
819*f7c14bbaSAndroid Build Coastguard Worker if (!flush) {
820*f7c14bbaSAndroid Build Coastguard Worker if (!handle || !priority)
821*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
822*f7c14bbaSAndroid Build Coastguard Worker protocol = ETH_P_ALL;
823*f7c14bbaSAndroid Build Coastguard Worker } else {
824*f7c14bbaSAndroid Build Coastguard Worker if (handle || priority)
825*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
826*f7c14bbaSAndroid Build Coastguard Worker }
827*f7c14bbaSAndroid Build Coastguard Worker
828*f7c14bbaSAndroid Build Coastguard Worker memset(&req, 0, sizeof(req));
829*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
830*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
831*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_type = RTM_DELTFILTER;
832*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_family = AF_UNSPEC;
833*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_ifindex = ifindex;
834*f7c14bbaSAndroid Build Coastguard Worker if (!flush) {
835*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_handle = handle;
836*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_info = TC_H_MAKE(priority << 16, htons(protocol));
837*f7c14bbaSAndroid Build Coastguard Worker }
838*f7c14bbaSAndroid Build Coastguard Worker
839*f7c14bbaSAndroid Build Coastguard Worker ret = tc_get_tcm_parent(attach_point, &parent);
840*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
841*f7c14bbaSAndroid Build Coastguard Worker return ret;
842*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_parent = parent;
843*f7c14bbaSAndroid Build Coastguard Worker
844*f7c14bbaSAndroid Build Coastguard Worker if (!flush) {
845*f7c14bbaSAndroid Build Coastguard Worker ret = nlattr_add(&req, TCA_KIND, "bpf", sizeof("bpf"));
846*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
847*f7c14bbaSAndroid Build Coastguard Worker return ret;
848*f7c14bbaSAndroid Build Coastguard Worker }
849*f7c14bbaSAndroid Build Coastguard Worker
850*f7c14bbaSAndroid Build Coastguard Worker return libbpf_netlink_send_recv(&req, NETLINK_ROUTE, NULL, NULL, NULL);
851*f7c14bbaSAndroid Build Coastguard Worker }
852*f7c14bbaSAndroid Build Coastguard Worker
bpf_tc_detach(const struct bpf_tc_hook * hook,const struct bpf_tc_opts * opts)853*f7c14bbaSAndroid Build Coastguard Worker int bpf_tc_detach(const struct bpf_tc_hook *hook,
854*f7c14bbaSAndroid Build Coastguard Worker const struct bpf_tc_opts *opts)
855*f7c14bbaSAndroid Build Coastguard Worker {
856*f7c14bbaSAndroid Build Coastguard Worker int ret;
857*f7c14bbaSAndroid Build Coastguard Worker
858*f7c14bbaSAndroid Build Coastguard Worker if (!opts)
859*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
860*f7c14bbaSAndroid Build Coastguard Worker
861*f7c14bbaSAndroid Build Coastguard Worker ret = __bpf_tc_detach(hook, opts, false);
862*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(ret);
863*f7c14bbaSAndroid Build Coastguard Worker }
864*f7c14bbaSAndroid Build Coastguard Worker
bpf_tc_query(const struct bpf_tc_hook * hook,struct bpf_tc_opts * opts)865*f7c14bbaSAndroid Build Coastguard Worker int bpf_tc_query(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
866*f7c14bbaSAndroid Build Coastguard Worker {
867*f7c14bbaSAndroid Build Coastguard Worker __u32 protocol, handle, priority, parent, prog_id, flags;
868*f7c14bbaSAndroid Build Coastguard Worker int ret, ifindex, attach_point, prog_fd;
869*f7c14bbaSAndroid Build Coastguard Worker struct bpf_cb_ctx info = {};
870*f7c14bbaSAndroid Build Coastguard Worker struct libbpf_nla_req req;
871*f7c14bbaSAndroid Build Coastguard Worker
872*f7c14bbaSAndroid Build Coastguard Worker if (!hook || !opts ||
873*f7c14bbaSAndroid Build Coastguard Worker !OPTS_VALID(hook, bpf_tc_hook) ||
874*f7c14bbaSAndroid Build Coastguard Worker !OPTS_VALID(opts, bpf_tc_opts))
875*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
876*f7c14bbaSAndroid Build Coastguard Worker
877*f7c14bbaSAndroid Build Coastguard Worker ifindex = OPTS_GET(hook, ifindex, 0);
878*f7c14bbaSAndroid Build Coastguard Worker parent = OPTS_GET(hook, parent, 0);
879*f7c14bbaSAndroid Build Coastguard Worker attach_point = OPTS_GET(hook, attach_point, 0);
880*f7c14bbaSAndroid Build Coastguard Worker
881*f7c14bbaSAndroid Build Coastguard Worker handle = OPTS_GET(opts, handle, 0);
882*f7c14bbaSAndroid Build Coastguard Worker priority = OPTS_GET(opts, priority, 0);
883*f7c14bbaSAndroid Build Coastguard Worker prog_fd = OPTS_GET(opts, prog_fd, 0);
884*f7c14bbaSAndroid Build Coastguard Worker prog_id = OPTS_GET(opts, prog_id, 0);
885*f7c14bbaSAndroid Build Coastguard Worker flags = OPTS_GET(opts, flags, 0);
886*f7c14bbaSAndroid Build Coastguard Worker
887*f7c14bbaSAndroid Build Coastguard Worker if (ifindex <= 0 || flags || prog_fd || prog_id ||
888*f7c14bbaSAndroid Build Coastguard Worker !handle || !priority)
889*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
890*f7c14bbaSAndroid Build Coastguard Worker if (priority > UINT16_MAX)
891*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-EINVAL);
892*f7c14bbaSAndroid Build Coastguard Worker
893*f7c14bbaSAndroid Build Coastguard Worker protocol = ETH_P_ALL;
894*f7c14bbaSAndroid Build Coastguard Worker
895*f7c14bbaSAndroid Build Coastguard Worker memset(&req, 0, sizeof(req));
896*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
897*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_flags = NLM_F_REQUEST;
898*f7c14bbaSAndroid Build Coastguard Worker req.nh.nlmsg_type = RTM_GETTFILTER;
899*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_family = AF_UNSPEC;
900*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_ifindex = ifindex;
901*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_handle = handle;
902*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_info = TC_H_MAKE(priority << 16, htons(protocol));
903*f7c14bbaSAndroid Build Coastguard Worker
904*f7c14bbaSAndroid Build Coastguard Worker ret = tc_get_tcm_parent(attach_point, &parent);
905*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
906*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(ret);
907*f7c14bbaSAndroid Build Coastguard Worker req.tc.tcm_parent = parent;
908*f7c14bbaSAndroid Build Coastguard Worker
909*f7c14bbaSAndroid Build Coastguard Worker ret = nlattr_add(&req, TCA_KIND, "bpf", sizeof("bpf"));
910*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
911*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(ret);
912*f7c14bbaSAndroid Build Coastguard Worker
913*f7c14bbaSAndroid Build Coastguard Worker info.opts = opts;
914*f7c14bbaSAndroid Build Coastguard Worker
915*f7c14bbaSAndroid Build Coastguard Worker ret = libbpf_netlink_send_recv(&req, NETLINK_ROUTE, get_tc_info, NULL,
916*f7c14bbaSAndroid Build Coastguard Worker &info);
917*f7c14bbaSAndroid Build Coastguard Worker if (ret < 0)
918*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(ret);
919*f7c14bbaSAndroid Build Coastguard Worker if (!info.processed)
920*f7c14bbaSAndroid Build Coastguard Worker return libbpf_err(-ENOENT);
921*f7c14bbaSAndroid Build Coastguard Worker return ret;
922*f7c14bbaSAndroid Build Coastguard Worker }
923