xref: /aosp_15_r20/external/libbpf/src/netlink.c (revision f7c14bbac8cf49633f2740db462ea43457973ec4)
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