xref: /aosp_15_r20/external/bpftool/src/net.c (revision 858ea5e570667251cdc31d3fe7b846b591105938)
1*858ea5e5SAndroid Build Coastguard Worker // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2*858ea5e5SAndroid Build Coastguard Worker // Copyright (C) 2018 Facebook
3*858ea5e5SAndroid Build Coastguard Worker 
4*858ea5e5SAndroid Build Coastguard Worker #ifndef _GNU_SOURCE
5*858ea5e5SAndroid Build Coastguard Worker #define _GNU_SOURCE
6*858ea5e5SAndroid Build Coastguard Worker #endif
7*858ea5e5SAndroid Build Coastguard Worker #include <errno.h>
8*858ea5e5SAndroid Build Coastguard Worker #include <fcntl.h>
9*858ea5e5SAndroid Build Coastguard Worker #include <stdlib.h>
10*858ea5e5SAndroid Build Coastguard Worker #include <string.h>
11*858ea5e5SAndroid Build Coastguard Worker #include <time.h>
12*858ea5e5SAndroid Build Coastguard Worker #include <unistd.h>
13*858ea5e5SAndroid Build Coastguard Worker #include <bpf/bpf.h>
14*858ea5e5SAndroid Build Coastguard Worker #include <bpf/libbpf.h>
15*858ea5e5SAndroid Build Coastguard Worker #include <net/if.h>
16*858ea5e5SAndroid Build Coastguard Worker #include <linux/rtnetlink.h>
17*858ea5e5SAndroid Build Coastguard Worker #include <linux/socket.h>
18*858ea5e5SAndroid Build Coastguard Worker #include <linux/tc_act/tc_bpf.h>
19*858ea5e5SAndroid Build Coastguard Worker #include <sys/socket.h>
20*858ea5e5SAndroid Build Coastguard Worker #include <sys/stat.h>
21*858ea5e5SAndroid Build Coastguard Worker #include <sys/types.h>
22*858ea5e5SAndroid Build Coastguard Worker 
23*858ea5e5SAndroid Build Coastguard Worker #include "bpf/nlattr.h"
24*858ea5e5SAndroid Build Coastguard Worker #include "main.h"
25*858ea5e5SAndroid Build Coastguard Worker #include "netlink_dumper.h"
26*858ea5e5SAndroid Build Coastguard Worker 
27*858ea5e5SAndroid Build Coastguard Worker #ifndef SOL_NETLINK
28*858ea5e5SAndroid Build Coastguard Worker #define SOL_NETLINK 270
29*858ea5e5SAndroid Build Coastguard Worker #endif
30*858ea5e5SAndroid Build Coastguard Worker 
31*858ea5e5SAndroid Build Coastguard Worker struct ip_devname_ifindex {
32*858ea5e5SAndroid Build Coastguard Worker 	char	devname[64];
33*858ea5e5SAndroid Build Coastguard Worker 	int	ifindex;
34*858ea5e5SAndroid Build Coastguard Worker };
35*858ea5e5SAndroid Build Coastguard Worker 
36*858ea5e5SAndroid Build Coastguard Worker struct bpf_netdev_t {
37*858ea5e5SAndroid Build Coastguard Worker 	struct ip_devname_ifindex *devices;
38*858ea5e5SAndroid Build Coastguard Worker 	int	used_len;
39*858ea5e5SAndroid Build Coastguard Worker 	int	array_len;
40*858ea5e5SAndroid Build Coastguard Worker 	int	filter_idx;
41*858ea5e5SAndroid Build Coastguard Worker };
42*858ea5e5SAndroid Build Coastguard Worker 
43*858ea5e5SAndroid Build Coastguard Worker struct tc_kind_handle {
44*858ea5e5SAndroid Build Coastguard Worker 	char	kind[64];
45*858ea5e5SAndroid Build Coastguard Worker 	int	handle;
46*858ea5e5SAndroid Build Coastguard Worker };
47*858ea5e5SAndroid Build Coastguard Worker 
48*858ea5e5SAndroid Build Coastguard Worker struct bpf_tcinfo_t {
49*858ea5e5SAndroid Build Coastguard Worker 	struct tc_kind_handle	*handle_array;
50*858ea5e5SAndroid Build Coastguard Worker 	int			used_len;
51*858ea5e5SAndroid Build Coastguard Worker 	int			array_len;
52*858ea5e5SAndroid Build Coastguard Worker 	bool			is_qdisc;
53*858ea5e5SAndroid Build Coastguard Worker };
54*858ea5e5SAndroid Build Coastguard Worker 
55*858ea5e5SAndroid Build Coastguard Worker struct bpf_filter_t {
56*858ea5e5SAndroid Build Coastguard Worker 	const char	*kind;
57*858ea5e5SAndroid Build Coastguard Worker 	const char	*devname;
58*858ea5e5SAndroid Build Coastguard Worker 	int		ifindex;
59*858ea5e5SAndroid Build Coastguard Worker };
60*858ea5e5SAndroid Build Coastguard Worker 
61*858ea5e5SAndroid Build Coastguard Worker struct bpf_attach_info {
62*858ea5e5SAndroid Build Coastguard Worker 	__u32 flow_dissector_id;
63*858ea5e5SAndroid Build Coastguard Worker };
64*858ea5e5SAndroid Build Coastguard Worker 
65*858ea5e5SAndroid Build Coastguard Worker enum net_attach_type {
66*858ea5e5SAndroid Build Coastguard Worker 	NET_ATTACH_TYPE_XDP,
67*858ea5e5SAndroid Build Coastguard Worker 	NET_ATTACH_TYPE_XDP_GENERIC,
68*858ea5e5SAndroid Build Coastguard Worker 	NET_ATTACH_TYPE_XDP_DRIVER,
69*858ea5e5SAndroid Build Coastguard Worker 	NET_ATTACH_TYPE_XDP_OFFLOAD,
70*858ea5e5SAndroid Build Coastguard Worker };
71*858ea5e5SAndroid Build Coastguard Worker 
72*858ea5e5SAndroid Build Coastguard Worker static const char * const attach_type_strings[] = {
73*858ea5e5SAndroid Build Coastguard Worker 	[NET_ATTACH_TYPE_XDP]		= "xdp",
74*858ea5e5SAndroid Build Coastguard Worker 	[NET_ATTACH_TYPE_XDP_GENERIC]	= "xdpgeneric",
75*858ea5e5SAndroid Build Coastguard Worker 	[NET_ATTACH_TYPE_XDP_DRIVER]	= "xdpdrv",
76*858ea5e5SAndroid Build Coastguard Worker 	[NET_ATTACH_TYPE_XDP_OFFLOAD]	= "xdpoffload",
77*858ea5e5SAndroid Build Coastguard Worker };
78*858ea5e5SAndroid Build Coastguard Worker 
79*858ea5e5SAndroid Build Coastguard Worker static const char * const attach_loc_strings[] = {
80*858ea5e5SAndroid Build Coastguard Worker 	[BPF_TCX_INGRESS]		= "tcx/ingress",
81*858ea5e5SAndroid Build Coastguard Worker 	[BPF_TCX_EGRESS]		= "tcx/egress",
82*858ea5e5SAndroid Build Coastguard Worker 	[BPF_NETKIT_PRIMARY]		= "netkit/primary",
83*858ea5e5SAndroid Build Coastguard Worker 	[BPF_NETKIT_PEER]		= "netkit/peer",
84*858ea5e5SAndroid Build Coastguard Worker };
85*858ea5e5SAndroid Build Coastguard Worker 
86*858ea5e5SAndroid Build Coastguard Worker const size_t net_attach_type_size = ARRAY_SIZE(attach_type_strings);
87*858ea5e5SAndroid Build Coastguard Worker 
parse_attach_type(const char * str)88*858ea5e5SAndroid Build Coastguard Worker static enum net_attach_type parse_attach_type(const char *str)
89*858ea5e5SAndroid Build Coastguard Worker {
90*858ea5e5SAndroid Build Coastguard Worker 	enum net_attach_type type;
91*858ea5e5SAndroid Build Coastguard Worker 
92*858ea5e5SAndroid Build Coastguard Worker 	for (type = 0; type < net_attach_type_size; type++) {
93*858ea5e5SAndroid Build Coastguard Worker 		if (attach_type_strings[type] &&
94*858ea5e5SAndroid Build Coastguard Worker 		    is_prefix(str, attach_type_strings[type]))
95*858ea5e5SAndroid Build Coastguard Worker 			return type;
96*858ea5e5SAndroid Build Coastguard Worker 	}
97*858ea5e5SAndroid Build Coastguard Worker 
98*858ea5e5SAndroid Build Coastguard Worker 	return net_attach_type_size;
99*858ea5e5SAndroid Build Coastguard Worker }
100*858ea5e5SAndroid Build Coastguard Worker 
101*858ea5e5SAndroid Build Coastguard Worker typedef int (*dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
102*858ea5e5SAndroid Build Coastguard Worker 
103*858ea5e5SAndroid Build Coastguard Worker typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, dump_nlmsg_t, void *cookie);
104*858ea5e5SAndroid Build Coastguard Worker 
netlink_open(__u32 * nl_pid)105*858ea5e5SAndroid Build Coastguard Worker static int netlink_open(__u32 *nl_pid)
106*858ea5e5SAndroid Build Coastguard Worker {
107*858ea5e5SAndroid Build Coastguard Worker 	struct sockaddr_nl sa;
108*858ea5e5SAndroid Build Coastguard Worker 	socklen_t addrlen;
109*858ea5e5SAndroid Build Coastguard Worker 	int one = 1, ret;
110*858ea5e5SAndroid Build Coastguard Worker 	int sock;
111*858ea5e5SAndroid Build Coastguard Worker 
112*858ea5e5SAndroid Build Coastguard Worker 	memset(&sa, 0, sizeof(sa));
113*858ea5e5SAndroid Build Coastguard Worker 	sa.nl_family = AF_NETLINK;
114*858ea5e5SAndroid Build Coastguard Worker 
115*858ea5e5SAndroid Build Coastguard Worker 	sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
116*858ea5e5SAndroid Build Coastguard Worker 	if (sock < 0)
117*858ea5e5SAndroid Build Coastguard Worker 		return -errno;
118*858ea5e5SAndroid Build Coastguard Worker 
119*858ea5e5SAndroid Build Coastguard Worker 	if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
120*858ea5e5SAndroid Build Coastguard Worker 		       &one, sizeof(one)) < 0) {
121*858ea5e5SAndroid Build Coastguard Worker 		p_err("Netlink error reporting not supported");
122*858ea5e5SAndroid Build Coastguard Worker 	}
123*858ea5e5SAndroid Build Coastguard Worker 
124*858ea5e5SAndroid Build Coastguard Worker 	if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
125*858ea5e5SAndroid Build Coastguard Worker 		ret = -errno;
126*858ea5e5SAndroid Build Coastguard Worker 		goto cleanup;
127*858ea5e5SAndroid Build Coastguard Worker 	}
128*858ea5e5SAndroid Build Coastguard Worker 
129*858ea5e5SAndroid Build Coastguard Worker 	addrlen = sizeof(sa);
130*858ea5e5SAndroid Build Coastguard Worker 	if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
131*858ea5e5SAndroid Build Coastguard Worker 		ret = -errno;
132*858ea5e5SAndroid Build Coastguard Worker 		goto cleanup;
133*858ea5e5SAndroid Build Coastguard Worker 	}
134*858ea5e5SAndroid Build Coastguard Worker 
135*858ea5e5SAndroid Build Coastguard Worker 	if (addrlen != sizeof(sa)) {
136*858ea5e5SAndroid Build Coastguard Worker 		ret = -LIBBPF_ERRNO__INTERNAL;
137*858ea5e5SAndroid Build Coastguard Worker 		goto cleanup;
138*858ea5e5SAndroid Build Coastguard Worker 	}
139*858ea5e5SAndroid Build Coastguard Worker 
140*858ea5e5SAndroid Build Coastguard Worker 	*nl_pid = sa.nl_pid;
141*858ea5e5SAndroid Build Coastguard Worker 	return sock;
142*858ea5e5SAndroid Build Coastguard Worker 
143*858ea5e5SAndroid Build Coastguard Worker cleanup:
144*858ea5e5SAndroid Build Coastguard Worker 	close(sock);
145*858ea5e5SAndroid Build Coastguard Worker 	return ret;
146*858ea5e5SAndroid Build Coastguard Worker }
147*858ea5e5SAndroid Build Coastguard Worker 
netlink_recv(int sock,__u32 nl_pid,__u32 seq,__dump_nlmsg_t _fn,dump_nlmsg_t fn,void * cookie)148*858ea5e5SAndroid Build Coastguard Worker static int netlink_recv(int sock, __u32 nl_pid, __u32 seq,
149*858ea5e5SAndroid Build Coastguard Worker 			    __dump_nlmsg_t _fn, dump_nlmsg_t fn,
150*858ea5e5SAndroid Build Coastguard Worker 			    void *cookie)
151*858ea5e5SAndroid Build Coastguard Worker {
152*858ea5e5SAndroid Build Coastguard Worker 	bool multipart = true;
153*858ea5e5SAndroid Build Coastguard Worker 	struct nlmsgerr *err;
154*858ea5e5SAndroid Build Coastguard Worker 	struct nlmsghdr *nh;
155*858ea5e5SAndroid Build Coastguard Worker 	char buf[4096];
156*858ea5e5SAndroid Build Coastguard Worker 	int len, ret;
157*858ea5e5SAndroid Build Coastguard Worker 
158*858ea5e5SAndroid Build Coastguard Worker 	while (multipart) {
159*858ea5e5SAndroid Build Coastguard Worker 		multipart = false;
160*858ea5e5SAndroid Build Coastguard Worker 		len = recv(sock, buf, sizeof(buf), 0);
161*858ea5e5SAndroid Build Coastguard Worker 		if (len < 0) {
162*858ea5e5SAndroid Build Coastguard Worker 			ret = -errno;
163*858ea5e5SAndroid Build Coastguard Worker 			goto done;
164*858ea5e5SAndroid Build Coastguard Worker 		}
165*858ea5e5SAndroid Build Coastguard Worker 
166*858ea5e5SAndroid Build Coastguard Worker 		if (len == 0)
167*858ea5e5SAndroid Build Coastguard Worker 			break;
168*858ea5e5SAndroid Build Coastguard Worker 
169*858ea5e5SAndroid Build Coastguard Worker 		for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, (unsigned int)len);
170*858ea5e5SAndroid Build Coastguard Worker 		     nh = NLMSG_NEXT(nh, len)) {
171*858ea5e5SAndroid Build Coastguard Worker 			if (nh->nlmsg_pid != nl_pid) {
172*858ea5e5SAndroid Build Coastguard Worker 				ret = -LIBBPF_ERRNO__WRNGPID;
173*858ea5e5SAndroid Build Coastguard Worker 				goto done;
174*858ea5e5SAndroid Build Coastguard Worker 			}
175*858ea5e5SAndroid Build Coastguard Worker 			if (nh->nlmsg_seq != seq) {
176*858ea5e5SAndroid Build Coastguard Worker 				ret = -LIBBPF_ERRNO__INVSEQ;
177*858ea5e5SAndroid Build Coastguard Worker 				goto done;
178*858ea5e5SAndroid Build Coastguard Worker 			}
179*858ea5e5SAndroid Build Coastguard Worker 			if (nh->nlmsg_flags & NLM_F_MULTI)
180*858ea5e5SAndroid Build Coastguard Worker 				multipart = true;
181*858ea5e5SAndroid Build Coastguard Worker 			switch (nh->nlmsg_type) {
182*858ea5e5SAndroid Build Coastguard Worker 			case NLMSG_ERROR:
183*858ea5e5SAndroid Build Coastguard Worker 				err = (struct nlmsgerr *)NLMSG_DATA(nh);
184*858ea5e5SAndroid Build Coastguard Worker 				if (!err->error)
185*858ea5e5SAndroid Build Coastguard Worker 					continue;
186*858ea5e5SAndroid Build Coastguard Worker 				ret = err->error;
187*858ea5e5SAndroid Build Coastguard Worker 				libbpf_nla_dump_errormsg(nh);
188*858ea5e5SAndroid Build Coastguard Worker 				goto done;
189*858ea5e5SAndroid Build Coastguard Worker 			case NLMSG_DONE:
190*858ea5e5SAndroid Build Coastguard Worker 				return 0;
191*858ea5e5SAndroid Build Coastguard Worker 			default:
192*858ea5e5SAndroid Build Coastguard Worker 				break;
193*858ea5e5SAndroid Build Coastguard Worker 			}
194*858ea5e5SAndroid Build Coastguard Worker 			if (_fn) {
195*858ea5e5SAndroid Build Coastguard Worker 				ret = _fn(nh, fn, cookie);
196*858ea5e5SAndroid Build Coastguard Worker 				if (ret)
197*858ea5e5SAndroid Build Coastguard Worker 					return ret;
198*858ea5e5SAndroid Build Coastguard Worker 			}
199*858ea5e5SAndroid Build Coastguard Worker 		}
200*858ea5e5SAndroid Build Coastguard Worker 	}
201*858ea5e5SAndroid Build Coastguard Worker 	ret = 0;
202*858ea5e5SAndroid Build Coastguard Worker done:
203*858ea5e5SAndroid Build Coastguard Worker 	return ret;
204*858ea5e5SAndroid Build Coastguard Worker }
205*858ea5e5SAndroid Build Coastguard Worker 
__dump_class_nlmsg(struct nlmsghdr * nlh,dump_nlmsg_t dump_class_nlmsg,void * cookie)206*858ea5e5SAndroid Build Coastguard Worker static int __dump_class_nlmsg(struct nlmsghdr *nlh,
207*858ea5e5SAndroid Build Coastguard Worker 			      dump_nlmsg_t dump_class_nlmsg,
208*858ea5e5SAndroid Build Coastguard Worker 			      void *cookie)
209*858ea5e5SAndroid Build Coastguard Worker {
210*858ea5e5SAndroid Build Coastguard Worker 	struct nlattr *tb[TCA_MAX + 1], *attr;
211*858ea5e5SAndroid Build Coastguard Worker 	struct tcmsg *t = NLMSG_DATA(nlh);
212*858ea5e5SAndroid Build Coastguard Worker 	int len;
213*858ea5e5SAndroid Build Coastguard Worker 
214*858ea5e5SAndroid Build Coastguard Worker 	len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
215*858ea5e5SAndroid Build Coastguard Worker 	attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
216*858ea5e5SAndroid Build Coastguard Worker 	if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
217*858ea5e5SAndroid Build Coastguard Worker 		return -LIBBPF_ERRNO__NLPARSE;
218*858ea5e5SAndroid Build Coastguard Worker 
219*858ea5e5SAndroid Build Coastguard Worker 	return dump_class_nlmsg(cookie, t, tb);
220*858ea5e5SAndroid Build Coastguard Worker }
221*858ea5e5SAndroid Build Coastguard Worker 
netlink_get_class(int sock,unsigned int nl_pid,int ifindex,dump_nlmsg_t dump_class_nlmsg,void * cookie)222*858ea5e5SAndroid Build Coastguard Worker static int netlink_get_class(int sock, unsigned int nl_pid, int ifindex,
223*858ea5e5SAndroid Build Coastguard Worker 			     dump_nlmsg_t dump_class_nlmsg, void *cookie)
224*858ea5e5SAndroid Build Coastguard Worker {
225*858ea5e5SAndroid Build Coastguard Worker 	struct {
226*858ea5e5SAndroid Build Coastguard Worker 		struct nlmsghdr nlh;
227*858ea5e5SAndroid Build Coastguard Worker 		struct tcmsg t;
228*858ea5e5SAndroid Build Coastguard Worker 	} req = {
229*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
230*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_type = RTM_GETTCLASS,
231*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
232*858ea5e5SAndroid Build Coastguard Worker 		.t.tcm_family = AF_UNSPEC,
233*858ea5e5SAndroid Build Coastguard Worker 		.t.tcm_ifindex = ifindex,
234*858ea5e5SAndroid Build Coastguard Worker 	};
235*858ea5e5SAndroid Build Coastguard Worker 	int seq = time(NULL);
236*858ea5e5SAndroid Build Coastguard Worker 
237*858ea5e5SAndroid Build Coastguard Worker 	req.nlh.nlmsg_seq = seq;
238*858ea5e5SAndroid Build Coastguard Worker 	if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
239*858ea5e5SAndroid Build Coastguard Worker 		return -errno;
240*858ea5e5SAndroid Build Coastguard Worker 
241*858ea5e5SAndroid Build Coastguard Worker 	return netlink_recv(sock, nl_pid, seq, __dump_class_nlmsg,
242*858ea5e5SAndroid Build Coastguard Worker 			    dump_class_nlmsg, cookie);
243*858ea5e5SAndroid Build Coastguard Worker }
244*858ea5e5SAndroid Build Coastguard Worker 
__dump_qdisc_nlmsg(struct nlmsghdr * nlh,dump_nlmsg_t dump_qdisc_nlmsg,void * cookie)245*858ea5e5SAndroid Build Coastguard Worker static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh,
246*858ea5e5SAndroid Build Coastguard Worker 			      dump_nlmsg_t dump_qdisc_nlmsg,
247*858ea5e5SAndroid Build Coastguard Worker 			      void *cookie)
248*858ea5e5SAndroid Build Coastguard Worker {
249*858ea5e5SAndroid Build Coastguard Worker 	struct nlattr *tb[TCA_MAX + 1], *attr;
250*858ea5e5SAndroid Build Coastguard Worker 	struct tcmsg *t = NLMSG_DATA(nlh);
251*858ea5e5SAndroid Build Coastguard Worker 	int len;
252*858ea5e5SAndroid Build Coastguard Worker 
253*858ea5e5SAndroid Build Coastguard Worker 	len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
254*858ea5e5SAndroid Build Coastguard Worker 	attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
255*858ea5e5SAndroid Build Coastguard Worker 	if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
256*858ea5e5SAndroid Build Coastguard Worker 		return -LIBBPF_ERRNO__NLPARSE;
257*858ea5e5SAndroid Build Coastguard Worker 
258*858ea5e5SAndroid Build Coastguard Worker 	return dump_qdisc_nlmsg(cookie, t, tb);
259*858ea5e5SAndroid Build Coastguard Worker }
260*858ea5e5SAndroid Build Coastguard Worker 
netlink_get_qdisc(int sock,unsigned int nl_pid,int ifindex,dump_nlmsg_t dump_qdisc_nlmsg,void * cookie)261*858ea5e5SAndroid Build Coastguard Worker static int netlink_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
262*858ea5e5SAndroid Build Coastguard Worker 			     dump_nlmsg_t dump_qdisc_nlmsg, void *cookie)
263*858ea5e5SAndroid Build Coastguard Worker {
264*858ea5e5SAndroid Build Coastguard Worker 	struct {
265*858ea5e5SAndroid Build Coastguard Worker 		struct nlmsghdr nlh;
266*858ea5e5SAndroid Build Coastguard Worker 		struct tcmsg t;
267*858ea5e5SAndroid Build Coastguard Worker 	} req = {
268*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
269*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_type = RTM_GETQDISC,
270*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
271*858ea5e5SAndroid Build Coastguard Worker 		.t.tcm_family = AF_UNSPEC,
272*858ea5e5SAndroid Build Coastguard Worker 		.t.tcm_ifindex = ifindex,
273*858ea5e5SAndroid Build Coastguard Worker 	};
274*858ea5e5SAndroid Build Coastguard Worker 	int seq = time(NULL);
275*858ea5e5SAndroid Build Coastguard Worker 
276*858ea5e5SAndroid Build Coastguard Worker 	req.nlh.nlmsg_seq = seq;
277*858ea5e5SAndroid Build Coastguard Worker 	if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
278*858ea5e5SAndroid Build Coastguard Worker 		return -errno;
279*858ea5e5SAndroid Build Coastguard Worker 
280*858ea5e5SAndroid Build Coastguard Worker 	return netlink_recv(sock, nl_pid, seq, __dump_qdisc_nlmsg,
281*858ea5e5SAndroid Build Coastguard Worker 			    dump_qdisc_nlmsg, cookie);
282*858ea5e5SAndroid Build Coastguard Worker }
283*858ea5e5SAndroid Build Coastguard Worker 
__dump_filter_nlmsg(struct nlmsghdr * nlh,dump_nlmsg_t dump_filter_nlmsg,void * cookie)284*858ea5e5SAndroid Build Coastguard Worker static int __dump_filter_nlmsg(struct nlmsghdr *nlh,
285*858ea5e5SAndroid Build Coastguard Worker 			       dump_nlmsg_t dump_filter_nlmsg,
286*858ea5e5SAndroid Build Coastguard Worker 			       void *cookie)
287*858ea5e5SAndroid Build Coastguard Worker {
288*858ea5e5SAndroid Build Coastguard Worker 	struct nlattr *tb[TCA_MAX + 1], *attr;
289*858ea5e5SAndroid Build Coastguard Worker 	struct tcmsg *t = NLMSG_DATA(nlh);
290*858ea5e5SAndroid Build Coastguard Worker 	int len;
291*858ea5e5SAndroid Build Coastguard Worker 
292*858ea5e5SAndroid Build Coastguard Worker 	len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
293*858ea5e5SAndroid Build Coastguard Worker 	attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
294*858ea5e5SAndroid Build Coastguard Worker 	if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
295*858ea5e5SAndroid Build Coastguard Worker 		return -LIBBPF_ERRNO__NLPARSE;
296*858ea5e5SAndroid Build Coastguard Worker 
297*858ea5e5SAndroid Build Coastguard Worker 	return dump_filter_nlmsg(cookie, t, tb);
298*858ea5e5SAndroid Build Coastguard Worker }
299*858ea5e5SAndroid Build Coastguard Worker 
netlink_get_filter(int sock,unsigned int nl_pid,int ifindex,int handle,dump_nlmsg_t dump_filter_nlmsg,void * cookie)300*858ea5e5SAndroid Build Coastguard Worker static int netlink_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
301*858ea5e5SAndroid Build Coastguard Worker 			      dump_nlmsg_t dump_filter_nlmsg, void *cookie)
302*858ea5e5SAndroid Build Coastguard Worker {
303*858ea5e5SAndroid Build Coastguard Worker 	struct {
304*858ea5e5SAndroid Build Coastguard Worker 		struct nlmsghdr nlh;
305*858ea5e5SAndroid Build Coastguard Worker 		struct tcmsg t;
306*858ea5e5SAndroid Build Coastguard Worker 	} req = {
307*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
308*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_type = RTM_GETTFILTER,
309*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
310*858ea5e5SAndroid Build Coastguard Worker 		.t.tcm_family = AF_UNSPEC,
311*858ea5e5SAndroid Build Coastguard Worker 		.t.tcm_ifindex = ifindex,
312*858ea5e5SAndroid Build Coastguard Worker 		.t.tcm_parent = handle,
313*858ea5e5SAndroid Build Coastguard Worker 	};
314*858ea5e5SAndroid Build Coastguard Worker 	int seq = time(NULL);
315*858ea5e5SAndroid Build Coastguard Worker 
316*858ea5e5SAndroid Build Coastguard Worker 	req.nlh.nlmsg_seq = seq;
317*858ea5e5SAndroid Build Coastguard Worker 	if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
318*858ea5e5SAndroid Build Coastguard Worker 		return -errno;
319*858ea5e5SAndroid Build Coastguard Worker 
320*858ea5e5SAndroid Build Coastguard Worker 	return netlink_recv(sock, nl_pid, seq, __dump_filter_nlmsg,
321*858ea5e5SAndroid Build Coastguard Worker 			    dump_filter_nlmsg, cookie);
322*858ea5e5SAndroid Build Coastguard Worker }
323*858ea5e5SAndroid Build Coastguard Worker 
__dump_link_nlmsg(struct nlmsghdr * nlh,dump_nlmsg_t dump_link_nlmsg,void * cookie)324*858ea5e5SAndroid Build Coastguard Worker static int __dump_link_nlmsg(struct nlmsghdr *nlh,
325*858ea5e5SAndroid Build Coastguard Worker 			     dump_nlmsg_t dump_link_nlmsg, void *cookie)
326*858ea5e5SAndroid Build Coastguard Worker {
327*858ea5e5SAndroid Build Coastguard Worker 	struct nlattr *tb[IFLA_MAX + 1], *attr;
328*858ea5e5SAndroid Build Coastguard Worker 	struct ifinfomsg *ifi = NLMSG_DATA(nlh);
329*858ea5e5SAndroid Build Coastguard Worker 	int len;
330*858ea5e5SAndroid Build Coastguard Worker 
331*858ea5e5SAndroid Build Coastguard Worker 	len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
332*858ea5e5SAndroid Build Coastguard Worker 	attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
333*858ea5e5SAndroid Build Coastguard Worker 	if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
334*858ea5e5SAndroid Build Coastguard Worker 		return -LIBBPF_ERRNO__NLPARSE;
335*858ea5e5SAndroid Build Coastguard Worker 
336*858ea5e5SAndroid Build Coastguard Worker 	return dump_link_nlmsg(cookie, ifi, tb);
337*858ea5e5SAndroid Build Coastguard Worker }
338*858ea5e5SAndroid Build Coastguard Worker 
netlink_get_link(int sock,unsigned int nl_pid,dump_nlmsg_t dump_link_nlmsg,void * cookie)339*858ea5e5SAndroid Build Coastguard Worker static int netlink_get_link(int sock, unsigned int nl_pid,
340*858ea5e5SAndroid Build Coastguard Worker 			    dump_nlmsg_t dump_link_nlmsg, void *cookie)
341*858ea5e5SAndroid Build Coastguard Worker {
342*858ea5e5SAndroid Build Coastguard Worker 	struct {
343*858ea5e5SAndroid Build Coastguard Worker 		struct nlmsghdr nlh;
344*858ea5e5SAndroid Build Coastguard Worker 		struct ifinfomsg ifm;
345*858ea5e5SAndroid Build Coastguard Worker 	} req = {
346*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
347*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_type = RTM_GETLINK,
348*858ea5e5SAndroid Build Coastguard Worker 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
349*858ea5e5SAndroid Build Coastguard Worker 		.ifm.ifi_family = AF_PACKET,
350*858ea5e5SAndroid Build Coastguard Worker 	};
351*858ea5e5SAndroid Build Coastguard Worker 	int seq = time(NULL);
352*858ea5e5SAndroid Build Coastguard Worker 
353*858ea5e5SAndroid Build Coastguard Worker 	req.nlh.nlmsg_seq = seq;
354*858ea5e5SAndroid Build Coastguard Worker 	if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
355*858ea5e5SAndroid Build Coastguard Worker 		return -errno;
356*858ea5e5SAndroid Build Coastguard Worker 
357*858ea5e5SAndroid Build Coastguard Worker 	return netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg,
358*858ea5e5SAndroid Build Coastguard Worker 			    dump_link_nlmsg, cookie);
359*858ea5e5SAndroid Build Coastguard Worker }
360*858ea5e5SAndroid Build Coastguard Worker 
dump_link_nlmsg(void * cookie,void * msg,struct nlattr ** tb)361*858ea5e5SAndroid Build Coastguard Worker static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
362*858ea5e5SAndroid Build Coastguard Worker {
363*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_netdev_t *netinfo = cookie;
364*858ea5e5SAndroid Build Coastguard Worker 	struct ifinfomsg *ifinfo = msg;
365*858ea5e5SAndroid Build Coastguard Worker 
366*858ea5e5SAndroid Build Coastguard Worker 	if (netinfo->filter_idx > 0 && netinfo->filter_idx != ifinfo->ifi_index)
367*858ea5e5SAndroid Build Coastguard Worker 		return 0;
368*858ea5e5SAndroid Build Coastguard Worker 
369*858ea5e5SAndroid Build Coastguard Worker 	if (netinfo->used_len == netinfo->array_len) {
370*858ea5e5SAndroid Build Coastguard Worker 		netinfo->devices = realloc(netinfo->devices,
371*858ea5e5SAndroid Build Coastguard Worker 			(netinfo->array_len + 16) *
372*858ea5e5SAndroid Build Coastguard Worker 			sizeof(struct ip_devname_ifindex));
373*858ea5e5SAndroid Build Coastguard Worker 		if (!netinfo->devices)
374*858ea5e5SAndroid Build Coastguard Worker 			return -ENOMEM;
375*858ea5e5SAndroid Build Coastguard Worker 
376*858ea5e5SAndroid Build Coastguard Worker 		netinfo->array_len += 16;
377*858ea5e5SAndroid Build Coastguard Worker 	}
378*858ea5e5SAndroid Build Coastguard Worker 	netinfo->devices[netinfo->used_len].ifindex = ifinfo->ifi_index;
379*858ea5e5SAndroid Build Coastguard Worker 	snprintf(netinfo->devices[netinfo->used_len].devname,
380*858ea5e5SAndroid Build Coastguard Worker 		 sizeof(netinfo->devices[netinfo->used_len].devname),
381*858ea5e5SAndroid Build Coastguard Worker 		 "%s",
382*858ea5e5SAndroid Build Coastguard Worker 		 tb[IFLA_IFNAME]
383*858ea5e5SAndroid Build Coastguard Worker 			 ? libbpf_nla_getattr_str(tb[IFLA_IFNAME])
384*858ea5e5SAndroid Build Coastguard Worker 			 : "");
385*858ea5e5SAndroid Build Coastguard Worker 	netinfo->used_len++;
386*858ea5e5SAndroid Build Coastguard Worker 
387*858ea5e5SAndroid Build Coastguard Worker 	return do_xdp_dump(ifinfo, tb);
388*858ea5e5SAndroid Build Coastguard Worker }
389*858ea5e5SAndroid Build Coastguard Worker 
dump_class_qdisc_nlmsg(void * cookie,void * msg,struct nlattr ** tb)390*858ea5e5SAndroid Build Coastguard Worker static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb)
391*858ea5e5SAndroid Build Coastguard Worker {
392*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_tcinfo_t *tcinfo = cookie;
393*858ea5e5SAndroid Build Coastguard Worker 	struct tcmsg *info = msg;
394*858ea5e5SAndroid Build Coastguard Worker 
395*858ea5e5SAndroid Build Coastguard Worker 	if (tcinfo->is_qdisc) {
396*858ea5e5SAndroid Build Coastguard Worker 		/* skip clsact qdisc */
397*858ea5e5SAndroid Build Coastguard Worker 		if (tb[TCA_KIND] &&
398*858ea5e5SAndroid Build Coastguard Worker 		    strcmp(libbpf_nla_data(tb[TCA_KIND]), "clsact") == 0)
399*858ea5e5SAndroid Build Coastguard Worker 			return 0;
400*858ea5e5SAndroid Build Coastguard Worker 		if (info->tcm_handle == 0)
401*858ea5e5SAndroid Build Coastguard Worker 			return 0;
402*858ea5e5SAndroid Build Coastguard Worker 	}
403*858ea5e5SAndroid Build Coastguard Worker 
404*858ea5e5SAndroid Build Coastguard Worker 	if (tcinfo->used_len == tcinfo->array_len) {
405*858ea5e5SAndroid Build Coastguard Worker 		tcinfo->handle_array = realloc(tcinfo->handle_array,
406*858ea5e5SAndroid Build Coastguard Worker 			(tcinfo->array_len + 16) * sizeof(struct tc_kind_handle));
407*858ea5e5SAndroid Build Coastguard Worker 		if (!tcinfo->handle_array)
408*858ea5e5SAndroid Build Coastguard Worker 			return -ENOMEM;
409*858ea5e5SAndroid Build Coastguard Worker 
410*858ea5e5SAndroid Build Coastguard Worker 		tcinfo->array_len += 16;
411*858ea5e5SAndroid Build Coastguard Worker 	}
412*858ea5e5SAndroid Build Coastguard Worker 	tcinfo->handle_array[tcinfo->used_len].handle = info->tcm_handle;
413*858ea5e5SAndroid Build Coastguard Worker 	snprintf(tcinfo->handle_array[tcinfo->used_len].kind,
414*858ea5e5SAndroid Build Coastguard Worker 		 sizeof(tcinfo->handle_array[tcinfo->used_len].kind),
415*858ea5e5SAndroid Build Coastguard Worker 		 "%s",
416*858ea5e5SAndroid Build Coastguard Worker 		 tb[TCA_KIND]
417*858ea5e5SAndroid Build Coastguard Worker 			 ? libbpf_nla_getattr_str(tb[TCA_KIND])
418*858ea5e5SAndroid Build Coastguard Worker 			 : "unknown");
419*858ea5e5SAndroid Build Coastguard Worker 	tcinfo->used_len++;
420*858ea5e5SAndroid Build Coastguard Worker 
421*858ea5e5SAndroid Build Coastguard Worker 	return 0;
422*858ea5e5SAndroid Build Coastguard Worker }
423*858ea5e5SAndroid Build Coastguard Worker 
dump_filter_nlmsg(void * cookie,void * msg,struct nlattr ** tb)424*858ea5e5SAndroid Build Coastguard Worker static int dump_filter_nlmsg(void *cookie, void *msg, struct nlattr **tb)
425*858ea5e5SAndroid Build Coastguard Worker {
426*858ea5e5SAndroid Build Coastguard Worker 	const struct bpf_filter_t *filter_info = cookie;
427*858ea5e5SAndroid Build Coastguard Worker 
428*858ea5e5SAndroid Build Coastguard Worker 	return do_filter_dump((struct tcmsg *)msg, tb, filter_info->kind,
429*858ea5e5SAndroid Build Coastguard Worker 			      filter_info->devname, filter_info->ifindex);
430*858ea5e5SAndroid Build Coastguard Worker }
431*858ea5e5SAndroid Build Coastguard Worker 
__show_dev_tc_bpf_name(__u32 id,char * name,size_t len)432*858ea5e5SAndroid Build Coastguard Worker static int __show_dev_tc_bpf_name(__u32 id, char *name, size_t len)
433*858ea5e5SAndroid Build Coastguard Worker {
434*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_prog_info info = {};
435*858ea5e5SAndroid Build Coastguard Worker 	__u32 ilen = sizeof(info);
436*858ea5e5SAndroid Build Coastguard Worker 	int fd, ret;
437*858ea5e5SAndroid Build Coastguard Worker 
438*858ea5e5SAndroid Build Coastguard Worker 	fd = bpf_prog_get_fd_by_id(id);
439*858ea5e5SAndroid Build Coastguard Worker 	if (fd < 0)
440*858ea5e5SAndroid Build Coastguard Worker 		return fd;
441*858ea5e5SAndroid Build Coastguard Worker 	ret = bpf_obj_get_info_by_fd(fd, &info, &ilen);
442*858ea5e5SAndroid Build Coastguard Worker 	if (ret < 0)
443*858ea5e5SAndroid Build Coastguard Worker 		goto out;
444*858ea5e5SAndroid Build Coastguard Worker 	ret = -ENOENT;
445*858ea5e5SAndroid Build Coastguard Worker 	if (info.name[0]) {
446*858ea5e5SAndroid Build Coastguard Worker 		get_prog_full_name(&info, fd, name, len);
447*858ea5e5SAndroid Build Coastguard Worker 		ret = 0;
448*858ea5e5SAndroid Build Coastguard Worker 	}
449*858ea5e5SAndroid Build Coastguard Worker out:
450*858ea5e5SAndroid Build Coastguard Worker 	close(fd);
451*858ea5e5SAndroid Build Coastguard Worker 	return ret;
452*858ea5e5SAndroid Build Coastguard Worker }
453*858ea5e5SAndroid Build Coastguard Worker 
__show_dev_tc_bpf(const struct ip_devname_ifindex * dev,const enum bpf_attach_type loc)454*858ea5e5SAndroid Build Coastguard Worker static void __show_dev_tc_bpf(const struct ip_devname_ifindex *dev,
455*858ea5e5SAndroid Build Coastguard Worker 			      const enum bpf_attach_type loc)
456*858ea5e5SAndroid Build Coastguard Worker {
457*858ea5e5SAndroid Build Coastguard Worker 	__u32 prog_flags[64] = {}, link_flags[64] = {}, i, j;
458*858ea5e5SAndroid Build Coastguard Worker 	__u32 prog_ids[64] = {}, link_ids[64] = {};
459*858ea5e5SAndroid Build Coastguard Worker 	LIBBPF_OPTS(bpf_prog_query_opts, optq);
460*858ea5e5SAndroid Build Coastguard Worker 	char prog_name[MAX_PROG_FULL_NAME];
461*858ea5e5SAndroid Build Coastguard Worker 	int ret;
462*858ea5e5SAndroid Build Coastguard Worker 
463*858ea5e5SAndroid Build Coastguard Worker 	optq.prog_ids = prog_ids;
464*858ea5e5SAndroid Build Coastguard Worker 	optq.prog_attach_flags = prog_flags;
465*858ea5e5SAndroid Build Coastguard Worker 	optq.link_ids = link_ids;
466*858ea5e5SAndroid Build Coastguard Worker 	optq.link_attach_flags = link_flags;
467*858ea5e5SAndroid Build Coastguard Worker 	optq.count = ARRAY_SIZE(prog_ids);
468*858ea5e5SAndroid Build Coastguard Worker 
469*858ea5e5SAndroid Build Coastguard Worker 	ret = bpf_prog_query_opts(dev->ifindex, loc, &optq);
470*858ea5e5SAndroid Build Coastguard Worker 	if (ret)
471*858ea5e5SAndroid Build Coastguard Worker 		return;
472*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < optq.count; i++) {
473*858ea5e5SAndroid Build Coastguard Worker 		NET_START_OBJECT;
474*858ea5e5SAndroid Build Coastguard Worker 		NET_DUMP_STR("devname", "%s", dev->devname);
475*858ea5e5SAndroid Build Coastguard Worker 		NET_DUMP_UINT("ifindex", "(%u)", dev->ifindex);
476*858ea5e5SAndroid Build Coastguard Worker 		NET_DUMP_STR("kind", " %s", attach_loc_strings[loc]);
477*858ea5e5SAndroid Build Coastguard Worker 		ret = __show_dev_tc_bpf_name(prog_ids[i], prog_name,
478*858ea5e5SAndroid Build Coastguard Worker 					     sizeof(prog_name));
479*858ea5e5SAndroid Build Coastguard Worker 		if (!ret)
480*858ea5e5SAndroid Build Coastguard Worker 			NET_DUMP_STR("name", " %s", prog_name);
481*858ea5e5SAndroid Build Coastguard Worker 		NET_DUMP_UINT("prog_id", " prog_id %u ", prog_ids[i]);
482*858ea5e5SAndroid Build Coastguard Worker 		if (prog_flags[i] || json_output) {
483*858ea5e5SAndroid Build Coastguard Worker 			NET_START_ARRAY("prog_flags", "%s ");
484*858ea5e5SAndroid Build Coastguard Worker 			for (j = 0; prog_flags[i] && j < 32; j++) {
485*858ea5e5SAndroid Build Coastguard Worker 				if (!(prog_flags[i] & (1 << j)))
486*858ea5e5SAndroid Build Coastguard Worker 					continue;
487*858ea5e5SAndroid Build Coastguard Worker 				NET_DUMP_UINT_ONLY(1 << j);
488*858ea5e5SAndroid Build Coastguard Worker 			}
489*858ea5e5SAndroid Build Coastguard Worker 			NET_END_ARRAY("");
490*858ea5e5SAndroid Build Coastguard Worker 		}
491*858ea5e5SAndroid Build Coastguard Worker 		if (link_ids[i] || json_output) {
492*858ea5e5SAndroid Build Coastguard Worker 			NET_DUMP_UINT("link_id", "link_id %u ", link_ids[i]);
493*858ea5e5SAndroid Build Coastguard Worker 			if (link_flags[i] || json_output) {
494*858ea5e5SAndroid Build Coastguard Worker 				NET_START_ARRAY("link_flags", "%s ");
495*858ea5e5SAndroid Build Coastguard Worker 				for (j = 0; link_flags[i] && j < 32; j++) {
496*858ea5e5SAndroid Build Coastguard Worker 					if (!(link_flags[i] & (1 << j)))
497*858ea5e5SAndroid Build Coastguard Worker 						continue;
498*858ea5e5SAndroid Build Coastguard Worker 					NET_DUMP_UINT_ONLY(1 << j);
499*858ea5e5SAndroid Build Coastguard Worker 				}
500*858ea5e5SAndroid Build Coastguard Worker 				NET_END_ARRAY("");
501*858ea5e5SAndroid Build Coastguard Worker 			}
502*858ea5e5SAndroid Build Coastguard Worker 		}
503*858ea5e5SAndroid Build Coastguard Worker 		NET_END_OBJECT_FINAL;
504*858ea5e5SAndroid Build Coastguard Worker 	}
505*858ea5e5SAndroid Build Coastguard Worker }
506*858ea5e5SAndroid Build Coastguard Worker 
show_dev_tc_bpf(struct ip_devname_ifindex * dev)507*858ea5e5SAndroid Build Coastguard Worker static void show_dev_tc_bpf(struct ip_devname_ifindex *dev)
508*858ea5e5SAndroid Build Coastguard Worker {
509*858ea5e5SAndroid Build Coastguard Worker 	__show_dev_tc_bpf(dev, BPF_TCX_INGRESS);
510*858ea5e5SAndroid Build Coastguard Worker 	__show_dev_tc_bpf(dev, BPF_TCX_EGRESS);
511*858ea5e5SAndroid Build Coastguard Worker 
512*858ea5e5SAndroid Build Coastguard Worker 	__show_dev_tc_bpf(dev, BPF_NETKIT_PRIMARY);
513*858ea5e5SAndroid Build Coastguard Worker 	__show_dev_tc_bpf(dev, BPF_NETKIT_PEER);
514*858ea5e5SAndroid Build Coastguard Worker }
515*858ea5e5SAndroid Build Coastguard Worker 
show_dev_tc_bpf_classic(int sock,unsigned int nl_pid,struct ip_devname_ifindex * dev)516*858ea5e5SAndroid Build Coastguard Worker static int show_dev_tc_bpf_classic(int sock, unsigned int nl_pid,
517*858ea5e5SAndroid Build Coastguard Worker 				   struct ip_devname_ifindex *dev)
518*858ea5e5SAndroid Build Coastguard Worker {
519*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_filter_t filter_info;
520*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_tcinfo_t tcinfo;
521*858ea5e5SAndroid Build Coastguard Worker 	int i, handle, ret = 0;
522*858ea5e5SAndroid Build Coastguard Worker 
523*858ea5e5SAndroid Build Coastguard Worker 	tcinfo.handle_array = NULL;
524*858ea5e5SAndroid Build Coastguard Worker 	tcinfo.used_len = 0;
525*858ea5e5SAndroid Build Coastguard Worker 	tcinfo.array_len = 0;
526*858ea5e5SAndroid Build Coastguard Worker 
527*858ea5e5SAndroid Build Coastguard Worker 	tcinfo.is_qdisc = false;
528*858ea5e5SAndroid Build Coastguard Worker 	ret = netlink_get_class(sock, nl_pid, dev->ifindex,
529*858ea5e5SAndroid Build Coastguard Worker 				dump_class_qdisc_nlmsg, &tcinfo);
530*858ea5e5SAndroid Build Coastguard Worker 	if (ret)
531*858ea5e5SAndroid Build Coastguard Worker 		goto out;
532*858ea5e5SAndroid Build Coastguard Worker 
533*858ea5e5SAndroid Build Coastguard Worker 	tcinfo.is_qdisc = true;
534*858ea5e5SAndroid Build Coastguard Worker 	ret = netlink_get_qdisc(sock, nl_pid, dev->ifindex,
535*858ea5e5SAndroid Build Coastguard Worker 				dump_class_qdisc_nlmsg, &tcinfo);
536*858ea5e5SAndroid Build Coastguard Worker 	if (ret)
537*858ea5e5SAndroid Build Coastguard Worker 		goto out;
538*858ea5e5SAndroid Build Coastguard Worker 
539*858ea5e5SAndroid Build Coastguard Worker 	filter_info.devname = dev->devname;
540*858ea5e5SAndroid Build Coastguard Worker 	filter_info.ifindex = dev->ifindex;
541*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < tcinfo.used_len; i++) {
542*858ea5e5SAndroid Build Coastguard Worker 		filter_info.kind = tcinfo.handle_array[i].kind;
543*858ea5e5SAndroid Build Coastguard Worker 		ret = netlink_get_filter(sock, nl_pid, dev->ifindex,
544*858ea5e5SAndroid Build Coastguard Worker 					 tcinfo.handle_array[i].handle,
545*858ea5e5SAndroid Build Coastguard Worker 					 dump_filter_nlmsg, &filter_info);
546*858ea5e5SAndroid Build Coastguard Worker 		if (ret)
547*858ea5e5SAndroid Build Coastguard Worker 			goto out;
548*858ea5e5SAndroid Build Coastguard Worker 	}
549*858ea5e5SAndroid Build Coastguard Worker 
550*858ea5e5SAndroid Build Coastguard Worker 	/* root, ingress and egress handle */
551*858ea5e5SAndroid Build Coastguard Worker 	handle = TC_H_ROOT;
552*858ea5e5SAndroid Build Coastguard Worker 	filter_info.kind = "root";
553*858ea5e5SAndroid Build Coastguard Worker 	ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
554*858ea5e5SAndroid Build Coastguard Worker 				 dump_filter_nlmsg, &filter_info);
555*858ea5e5SAndroid Build Coastguard Worker 	if (ret)
556*858ea5e5SAndroid Build Coastguard Worker 		goto out;
557*858ea5e5SAndroid Build Coastguard Worker 
558*858ea5e5SAndroid Build Coastguard Worker 	handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS);
559*858ea5e5SAndroid Build Coastguard Worker 	filter_info.kind = "clsact/ingress";
560*858ea5e5SAndroid Build Coastguard Worker 	ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
561*858ea5e5SAndroid Build Coastguard Worker 				 dump_filter_nlmsg, &filter_info);
562*858ea5e5SAndroid Build Coastguard Worker 	if (ret)
563*858ea5e5SAndroid Build Coastguard Worker 		goto out;
564*858ea5e5SAndroid Build Coastguard Worker 
565*858ea5e5SAndroid Build Coastguard Worker 	handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS);
566*858ea5e5SAndroid Build Coastguard Worker 	filter_info.kind = "clsact/egress";
567*858ea5e5SAndroid Build Coastguard Worker 	ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
568*858ea5e5SAndroid Build Coastguard Worker 				 dump_filter_nlmsg, &filter_info);
569*858ea5e5SAndroid Build Coastguard Worker 	if (ret)
570*858ea5e5SAndroid Build Coastguard Worker 		goto out;
571*858ea5e5SAndroid Build Coastguard Worker 
572*858ea5e5SAndroid Build Coastguard Worker out:
573*858ea5e5SAndroid Build Coastguard Worker 	free(tcinfo.handle_array);
574*858ea5e5SAndroid Build Coastguard Worker 	return 0;
575*858ea5e5SAndroid Build Coastguard Worker }
576*858ea5e5SAndroid Build Coastguard Worker 
query_flow_dissector(struct bpf_attach_info * attach_info)577*858ea5e5SAndroid Build Coastguard Worker static int query_flow_dissector(struct bpf_attach_info *attach_info)
578*858ea5e5SAndroid Build Coastguard Worker {
579*858ea5e5SAndroid Build Coastguard Worker 	__u32 attach_flags;
580*858ea5e5SAndroid Build Coastguard Worker 	__u32 prog_ids[1];
581*858ea5e5SAndroid Build Coastguard Worker 	__u32 prog_cnt;
582*858ea5e5SAndroid Build Coastguard Worker 	int err;
583*858ea5e5SAndroid Build Coastguard Worker 	int fd;
584*858ea5e5SAndroid Build Coastguard Worker 
585*858ea5e5SAndroid Build Coastguard Worker 	fd = open("/proc/self/ns/net", O_RDONLY);
586*858ea5e5SAndroid Build Coastguard Worker 	if (fd < 0) {
587*858ea5e5SAndroid Build Coastguard Worker 		p_err("can't open /proc/self/ns/net: %s",
588*858ea5e5SAndroid Build Coastguard Worker 		      strerror(errno));
589*858ea5e5SAndroid Build Coastguard Worker 		return -1;
590*858ea5e5SAndroid Build Coastguard Worker 	}
591*858ea5e5SAndroid Build Coastguard Worker 	prog_cnt = ARRAY_SIZE(prog_ids);
592*858ea5e5SAndroid Build Coastguard Worker 	err = bpf_prog_query(fd, BPF_FLOW_DISSECTOR, 0,
593*858ea5e5SAndroid Build Coastguard Worker 			     &attach_flags, prog_ids, &prog_cnt);
594*858ea5e5SAndroid Build Coastguard Worker 	close(fd);
595*858ea5e5SAndroid Build Coastguard Worker 	if (err) {
596*858ea5e5SAndroid Build Coastguard Worker 		if (errno == EINVAL) {
597*858ea5e5SAndroid Build Coastguard Worker 			/* Older kernel's don't support querying
598*858ea5e5SAndroid Build Coastguard Worker 			 * flow dissector programs.
599*858ea5e5SAndroid Build Coastguard Worker 			 */
600*858ea5e5SAndroid Build Coastguard Worker 			errno = 0;
601*858ea5e5SAndroid Build Coastguard Worker 			return 0;
602*858ea5e5SAndroid Build Coastguard Worker 		}
603*858ea5e5SAndroid Build Coastguard Worker 		p_err("can't query prog: %s", strerror(errno));
604*858ea5e5SAndroid Build Coastguard Worker 		return -1;
605*858ea5e5SAndroid Build Coastguard Worker 	}
606*858ea5e5SAndroid Build Coastguard Worker 
607*858ea5e5SAndroid Build Coastguard Worker 	if (prog_cnt == 1)
608*858ea5e5SAndroid Build Coastguard Worker 		attach_info->flow_dissector_id = prog_ids[0];
609*858ea5e5SAndroid Build Coastguard Worker 
610*858ea5e5SAndroid Build Coastguard Worker 	return 0;
611*858ea5e5SAndroid Build Coastguard Worker }
612*858ea5e5SAndroid Build Coastguard Worker 
net_parse_dev(int * argc,char *** argv)613*858ea5e5SAndroid Build Coastguard Worker static int net_parse_dev(int *argc, char ***argv)
614*858ea5e5SAndroid Build Coastguard Worker {
615*858ea5e5SAndroid Build Coastguard Worker 	int ifindex;
616*858ea5e5SAndroid Build Coastguard Worker 
617*858ea5e5SAndroid Build Coastguard Worker 	if (is_prefix(**argv, "dev")) {
618*858ea5e5SAndroid Build Coastguard Worker 		NEXT_ARGP();
619*858ea5e5SAndroid Build Coastguard Worker 
620*858ea5e5SAndroid Build Coastguard Worker 		ifindex = if_nametoindex(**argv);
621*858ea5e5SAndroid Build Coastguard Worker 		if (!ifindex)
622*858ea5e5SAndroid Build Coastguard Worker 			p_err("invalid devname %s", **argv);
623*858ea5e5SAndroid Build Coastguard Worker 
624*858ea5e5SAndroid Build Coastguard Worker 		NEXT_ARGP();
625*858ea5e5SAndroid Build Coastguard Worker 	} else {
626*858ea5e5SAndroid Build Coastguard Worker 		p_err("expected 'dev', got: '%s'?", **argv);
627*858ea5e5SAndroid Build Coastguard Worker 		return -1;
628*858ea5e5SAndroid Build Coastguard Worker 	}
629*858ea5e5SAndroid Build Coastguard Worker 
630*858ea5e5SAndroid Build Coastguard Worker 	return ifindex;
631*858ea5e5SAndroid Build Coastguard Worker }
632*858ea5e5SAndroid Build Coastguard Worker 
do_attach_detach_xdp(int progfd,enum net_attach_type attach_type,int ifindex,bool overwrite)633*858ea5e5SAndroid Build Coastguard Worker static int do_attach_detach_xdp(int progfd, enum net_attach_type attach_type,
634*858ea5e5SAndroid Build Coastguard Worker 				int ifindex, bool overwrite)
635*858ea5e5SAndroid Build Coastguard Worker {
636*858ea5e5SAndroid Build Coastguard Worker 	__u32 flags = 0;
637*858ea5e5SAndroid Build Coastguard Worker 
638*858ea5e5SAndroid Build Coastguard Worker 	if (!overwrite)
639*858ea5e5SAndroid Build Coastguard Worker 		flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
640*858ea5e5SAndroid Build Coastguard Worker 	if (attach_type == NET_ATTACH_TYPE_XDP_GENERIC)
641*858ea5e5SAndroid Build Coastguard Worker 		flags |= XDP_FLAGS_SKB_MODE;
642*858ea5e5SAndroid Build Coastguard Worker 	if (attach_type == NET_ATTACH_TYPE_XDP_DRIVER)
643*858ea5e5SAndroid Build Coastguard Worker 		flags |= XDP_FLAGS_DRV_MODE;
644*858ea5e5SAndroid Build Coastguard Worker 	if (attach_type == NET_ATTACH_TYPE_XDP_OFFLOAD)
645*858ea5e5SAndroid Build Coastguard Worker 		flags |= XDP_FLAGS_HW_MODE;
646*858ea5e5SAndroid Build Coastguard Worker 
647*858ea5e5SAndroid Build Coastguard Worker 	return bpf_xdp_attach(ifindex, progfd, flags, NULL);
648*858ea5e5SAndroid Build Coastguard Worker }
649*858ea5e5SAndroid Build Coastguard Worker 
do_attach(int argc,char ** argv)650*858ea5e5SAndroid Build Coastguard Worker static int do_attach(int argc, char **argv)
651*858ea5e5SAndroid Build Coastguard Worker {
652*858ea5e5SAndroid Build Coastguard Worker 	enum net_attach_type attach_type;
653*858ea5e5SAndroid Build Coastguard Worker 	int progfd, ifindex, err = 0;
654*858ea5e5SAndroid Build Coastguard Worker 	bool overwrite = false;
655*858ea5e5SAndroid Build Coastguard Worker 
656*858ea5e5SAndroid Build Coastguard Worker 	/* parse attach args */
657*858ea5e5SAndroid Build Coastguard Worker 	if (!REQ_ARGS(5))
658*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
659*858ea5e5SAndroid Build Coastguard Worker 
660*858ea5e5SAndroid Build Coastguard Worker 	attach_type = parse_attach_type(*argv);
661*858ea5e5SAndroid Build Coastguard Worker 	if (attach_type == net_attach_type_size) {
662*858ea5e5SAndroid Build Coastguard Worker 		p_err("invalid net attach/detach type: %s", *argv);
663*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
664*858ea5e5SAndroid Build Coastguard Worker 	}
665*858ea5e5SAndroid Build Coastguard Worker 	NEXT_ARG();
666*858ea5e5SAndroid Build Coastguard Worker 
667*858ea5e5SAndroid Build Coastguard Worker 	progfd = prog_parse_fd(&argc, &argv);
668*858ea5e5SAndroid Build Coastguard Worker 	if (progfd < 0)
669*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
670*858ea5e5SAndroid Build Coastguard Worker 
671*858ea5e5SAndroid Build Coastguard Worker 	ifindex = net_parse_dev(&argc, &argv);
672*858ea5e5SAndroid Build Coastguard Worker 	if (ifindex < 1) {
673*858ea5e5SAndroid Build Coastguard Worker 		err = -EINVAL;
674*858ea5e5SAndroid Build Coastguard Worker 		goto cleanup;
675*858ea5e5SAndroid Build Coastguard Worker 	}
676*858ea5e5SAndroid Build Coastguard Worker 
677*858ea5e5SAndroid Build Coastguard Worker 	if (argc) {
678*858ea5e5SAndroid Build Coastguard Worker 		if (is_prefix(*argv, "overwrite")) {
679*858ea5e5SAndroid Build Coastguard Worker 			overwrite = true;
680*858ea5e5SAndroid Build Coastguard Worker 		} else {
681*858ea5e5SAndroid Build Coastguard Worker 			p_err("expected 'overwrite', got: '%s'?", *argv);
682*858ea5e5SAndroid Build Coastguard Worker 			err = -EINVAL;
683*858ea5e5SAndroid Build Coastguard Worker 			goto cleanup;
684*858ea5e5SAndroid Build Coastguard Worker 		}
685*858ea5e5SAndroid Build Coastguard Worker 	}
686*858ea5e5SAndroid Build Coastguard Worker 
687*858ea5e5SAndroid Build Coastguard Worker 	/* attach xdp prog */
688*858ea5e5SAndroid Build Coastguard Worker 	if (is_prefix("xdp", attach_type_strings[attach_type]))
689*858ea5e5SAndroid Build Coastguard Worker 		err = do_attach_detach_xdp(progfd, attach_type, ifindex,
690*858ea5e5SAndroid Build Coastguard Worker 					   overwrite);
691*858ea5e5SAndroid Build Coastguard Worker 	if (err) {
692*858ea5e5SAndroid Build Coastguard Worker 		p_err("interface %s attach failed: %s",
693*858ea5e5SAndroid Build Coastguard Worker 		      attach_type_strings[attach_type], strerror(-err));
694*858ea5e5SAndroid Build Coastguard Worker 		goto cleanup;
695*858ea5e5SAndroid Build Coastguard Worker 	}
696*858ea5e5SAndroid Build Coastguard Worker 
697*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
698*858ea5e5SAndroid Build Coastguard Worker 		jsonw_null(json_wtr);
699*858ea5e5SAndroid Build Coastguard Worker cleanup:
700*858ea5e5SAndroid Build Coastguard Worker 	close(progfd);
701*858ea5e5SAndroid Build Coastguard Worker 	return err;
702*858ea5e5SAndroid Build Coastguard Worker }
703*858ea5e5SAndroid Build Coastguard Worker 
do_detach(int argc,char ** argv)704*858ea5e5SAndroid Build Coastguard Worker static int do_detach(int argc, char **argv)
705*858ea5e5SAndroid Build Coastguard Worker {
706*858ea5e5SAndroid Build Coastguard Worker 	enum net_attach_type attach_type;
707*858ea5e5SAndroid Build Coastguard Worker 	int progfd, ifindex, err = 0;
708*858ea5e5SAndroid Build Coastguard Worker 
709*858ea5e5SAndroid Build Coastguard Worker 	/* parse detach args */
710*858ea5e5SAndroid Build Coastguard Worker 	if (!REQ_ARGS(3))
711*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
712*858ea5e5SAndroid Build Coastguard Worker 
713*858ea5e5SAndroid Build Coastguard Worker 	attach_type = parse_attach_type(*argv);
714*858ea5e5SAndroid Build Coastguard Worker 	if (attach_type == net_attach_type_size) {
715*858ea5e5SAndroid Build Coastguard Worker 		p_err("invalid net attach/detach type: %s", *argv);
716*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
717*858ea5e5SAndroid Build Coastguard Worker 	}
718*858ea5e5SAndroid Build Coastguard Worker 	NEXT_ARG();
719*858ea5e5SAndroid Build Coastguard Worker 
720*858ea5e5SAndroid Build Coastguard Worker 	ifindex = net_parse_dev(&argc, &argv);
721*858ea5e5SAndroid Build Coastguard Worker 	if (ifindex < 1)
722*858ea5e5SAndroid Build Coastguard Worker 		return -EINVAL;
723*858ea5e5SAndroid Build Coastguard Worker 
724*858ea5e5SAndroid Build Coastguard Worker 	/* detach xdp prog */
725*858ea5e5SAndroid Build Coastguard Worker 	progfd = -1;
726*858ea5e5SAndroid Build Coastguard Worker 	if (is_prefix("xdp", attach_type_strings[attach_type]))
727*858ea5e5SAndroid Build Coastguard Worker 		err = do_attach_detach_xdp(progfd, attach_type, ifindex, NULL);
728*858ea5e5SAndroid Build Coastguard Worker 
729*858ea5e5SAndroid Build Coastguard Worker 	if (err < 0) {
730*858ea5e5SAndroid Build Coastguard Worker 		p_err("interface %s detach failed: %s",
731*858ea5e5SAndroid Build Coastguard Worker 		      attach_type_strings[attach_type], strerror(-err));
732*858ea5e5SAndroid Build Coastguard Worker 		return err;
733*858ea5e5SAndroid Build Coastguard Worker 	}
734*858ea5e5SAndroid Build Coastguard Worker 
735*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
736*858ea5e5SAndroid Build Coastguard Worker 		jsonw_null(json_wtr);
737*858ea5e5SAndroid Build Coastguard Worker 
738*858ea5e5SAndroid Build Coastguard Worker 	return 0;
739*858ea5e5SAndroid Build Coastguard Worker }
740*858ea5e5SAndroid Build Coastguard Worker 
netfilter_link_compar(const void * a,const void * b)741*858ea5e5SAndroid Build Coastguard Worker static int netfilter_link_compar(const void *a, const void *b)
742*858ea5e5SAndroid Build Coastguard Worker {
743*858ea5e5SAndroid Build Coastguard Worker 	const struct bpf_link_info *nfa = a;
744*858ea5e5SAndroid Build Coastguard Worker 	const struct bpf_link_info *nfb = b;
745*858ea5e5SAndroid Build Coastguard Worker 	int delta;
746*858ea5e5SAndroid Build Coastguard Worker 
747*858ea5e5SAndroid Build Coastguard Worker 	delta = nfa->netfilter.pf - nfb->netfilter.pf;
748*858ea5e5SAndroid Build Coastguard Worker 	if (delta)
749*858ea5e5SAndroid Build Coastguard Worker 		return delta;
750*858ea5e5SAndroid Build Coastguard Worker 
751*858ea5e5SAndroid Build Coastguard Worker 	delta = nfa->netfilter.hooknum - nfb->netfilter.hooknum;
752*858ea5e5SAndroid Build Coastguard Worker 	if (delta)
753*858ea5e5SAndroid Build Coastguard Worker 		return delta;
754*858ea5e5SAndroid Build Coastguard Worker 
755*858ea5e5SAndroid Build Coastguard Worker 	if (nfa->netfilter.priority < nfb->netfilter.priority)
756*858ea5e5SAndroid Build Coastguard Worker 		return -1;
757*858ea5e5SAndroid Build Coastguard Worker 	if (nfa->netfilter.priority > nfb->netfilter.priority)
758*858ea5e5SAndroid Build Coastguard Worker 		return 1;
759*858ea5e5SAndroid Build Coastguard Worker 
760*858ea5e5SAndroid Build Coastguard Worker 	return nfa->netfilter.flags - nfb->netfilter.flags;
761*858ea5e5SAndroid Build Coastguard Worker }
762*858ea5e5SAndroid Build Coastguard Worker 
show_link_netfilter(void)763*858ea5e5SAndroid Build Coastguard Worker static void show_link_netfilter(void)
764*858ea5e5SAndroid Build Coastguard Worker {
765*858ea5e5SAndroid Build Coastguard Worker 	unsigned int nf_link_len = 0, nf_link_count = 0;
766*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_link_info *nf_link_info = NULL;
767*858ea5e5SAndroid Build Coastguard Worker 	__u32 id = 0;
768*858ea5e5SAndroid Build Coastguard Worker 
769*858ea5e5SAndroid Build Coastguard Worker 	while (true) {
770*858ea5e5SAndroid Build Coastguard Worker 		struct bpf_link_info info;
771*858ea5e5SAndroid Build Coastguard Worker 		int fd, err;
772*858ea5e5SAndroid Build Coastguard Worker 		__u32 len;
773*858ea5e5SAndroid Build Coastguard Worker 
774*858ea5e5SAndroid Build Coastguard Worker 		err = bpf_link_get_next_id(id, &id);
775*858ea5e5SAndroid Build Coastguard Worker 		if (err) {
776*858ea5e5SAndroid Build Coastguard Worker 			if (errno == ENOENT)
777*858ea5e5SAndroid Build Coastguard Worker 				break;
778*858ea5e5SAndroid Build Coastguard Worker 			p_err("can't get next link: %s (id %d)", strerror(errno), id);
779*858ea5e5SAndroid Build Coastguard Worker 			break;
780*858ea5e5SAndroid Build Coastguard Worker 		}
781*858ea5e5SAndroid Build Coastguard Worker 
782*858ea5e5SAndroid Build Coastguard Worker 		fd = bpf_link_get_fd_by_id(id);
783*858ea5e5SAndroid Build Coastguard Worker 		if (fd < 0) {
784*858ea5e5SAndroid Build Coastguard Worker 			p_err("can't get link by id (%u): %s", id, strerror(errno));
785*858ea5e5SAndroid Build Coastguard Worker 			continue;
786*858ea5e5SAndroid Build Coastguard Worker 		}
787*858ea5e5SAndroid Build Coastguard Worker 
788*858ea5e5SAndroid Build Coastguard Worker 		memset(&info, 0, sizeof(info));
789*858ea5e5SAndroid Build Coastguard Worker 		len = sizeof(info);
790*858ea5e5SAndroid Build Coastguard Worker 
791*858ea5e5SAndroid Build Coastguard Worker 		err = bpf_link_get_info_by_fd(fd, &info, &len);
792*858ea5e5SAndroid Build Coastguard Worker 
793*858ea5e5SAndroid Build Coastguard Worker 		close(fd);
794*858ea5e5SAndroid Build Coastguard Worker 
795*858ea5e5SAndroid Build Coastguard Worker 		if (err) {
796*858ea5e5SAndroid Build Coastguard Worker 			p_err("can't get link info for fd %d: %s", fd, strerror(errno));
797*858ea5e5SAndroid Build Coastguard Worker 			continue;
798*858ea5e5SAndroid Build Coastguard Worker 		}
799*858ea5e5SAndroid Build Coastguard Worker 
800*858ea5e5SAndroid Build Coastguard Worker 		if (info.type != BPF_LINK_TYPE_NETFILTER)
801*858ea5e5SAndroid Build Coastguard Worker 			continue;
802*858ea5e5SAndroid Build Coastguard Worker 
803*858ea5e5SAndroid Build Coastguard Worker 		if (nf_link_count >= nf_link_len) {
804*858ea5e5SAndroid Build Coastguard Worker 			static const unsigned int max_link_count = INT_MAX / sizeof(info);
805*858ea5e5SAndroid Build Coastguard Worker 			struct bpf_link_info *expand;
806*858ea5e5SAndroid Build Coastguard Worker 
807*858ea5e5SAndroid Build Coastguard Worker 			if (nf_link_count > max_link_count) {
808*858ea5e5SAndroid Build Coastguard Worker 				p_err("cannot handle more than %u links\n", max_link_count);
809*858ea5e5SAndroid Build Coastguard Worker 				break;
810*858ea5e5SAndroid Build Coastguard Worker 			}
811*858ea5e5SAndroid Build Coastguard Worker 
812*858ea5e5SAndroid Build Coastguard Worker 			nf_link_len += 16;
813*858ea5e5SAndroid Build Coastguard Worker 
814*858ea5e5SAndroid Build Coastguard Worker 			expand = realloc(nf_link_info, nf_link_len * sizeof(info));
815*858ea5e5SAndroid Build Coastguard Worker 			if (!expand) {
816*858ea5e5SAndroid Build Coastguard Worker 				p_err("realloc: %s",  strerror(errno));
817*858ea5e5SAndroid Build Coastguard Worker 				break;
818*858ea5e5SAndroid Build Coastguard Worker 			}
819*858ea5e5SAndroid Build Coastguard Worker 
820*858ea5e5SAndroid Build Coastguard Worker 			nf_link_info = expand;
821*858ea5e5SAndroid Build Coastguard Worker 		}
822*858ea5e5SAndroid Build Coastguard Worker 
823*858ea5e5SAndroid Build Coastguard Worker 		nf_link_info[nf_link_count] = info;
824*858ea5e5SAndroid Build Coastguard Worker 		nf_link_count++;
825*858ea5e5SAndroid Build Coastguard Worker 	}
826*858ea5e5SAndroid Build Coastguard Worker 
827*858ea5e5SAndroid Build Coastguard Worker 	qsort(nf_link_info, nf_link_count, sizeof(*nf_link_info), netfilter_link_compar);
828*858ea5e5SAndroid Build Coastguard Worker 
829*858ea5e5SAndroid Build Coastguard Worker 	for (id = 0; id < nf_link_count; id++) {
830*858ea5e5SAndroid Build Coastguard Worker 		NET_START_OBJECT;
831*858ea5e5SAndroid Build Coastguard Worker 		if (json_output)
832*858ea5e5SAndroid Build Coastguard Worker 			netfilter_dump_json(&nf_link_info[id], json_wtr);
833*858ea5e5SAndroid Build Coastguard Worker 		else
834*858ea5e5SAndroid Build Coastguard Worker 			netfilter_dump_plain(&nf_link_info[id]);
835*858ea5e5SAndroid Build Coastguard Worker 
836*858ea5e5SAndroid Build Coastguard Worker 		NET_DUMP_UINT("id", " prog_id %u", nf_link_info[id].prog_id);
837*858ea5e5SAndroid Build Coastguard Worker 		NET_END_OBJECT;
838*858ea5e5SAndroid Build Coastguard Worker 	}
839*858ea5e5SAndroid Build Coastguard Worker 
840*858ea5e5SAndroid Build Coastguard Worker 	free(nf_link_info);
841*858ea5e5SAndroid Build Coastguard Worker }
842*858ea5e5SAndroid Build Coastguard Worker 
do_show(int argc,char ** argv)843*858ea5e5SAndroid Build Coastguard Worker static int do_show(int argc, char **argv)
844*858ea5e5SAndroid Build Coastguard Worker {
845*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_attach_info attach_info = {};
846*858ea5e5SAndroid Build Coastguard Worker 	int i, sock, ret, filter_idx = -1;
847*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_netdev_t dev_array;
848*858ea5e5SAndroid Build Coastguard Worker 	unsigned int nl_pid = 0;
849*858ea5e5SAndroid Build Coastguard Worker 	char err_buf[256];
850*858ea5e5SAndroid Build Coastguard Worker 
851*858ea5e5SAndroid Build Coastguard Worker 	if (argc == 2) {
852*858ea5e5SAndroid Build Coastguard Worker 		filter_idx = net_parse_dev(&argc, &argv);
853*858ea5e5SAndroid Build Coastguard Worker 		if (filter_idx < 1)
854*858ea5e5SAndroid Build Coastguard Worker 			return -1;
855*858ea5e5SAndroid Build Coastguard Worker 	} else if (argc != 0) {
856*858ea5e5SAndroid Build Coastguard Worker 		usage();
857*858ea5e5SAndroid Build Coastguard Worker 	}
858*858ea5e5SAndroid Build Coastguard Worker 
859*858ea5e5SAndroid Build Coastguard Worker 	ret = query_flow_dissector(&attach_info);
860*858ea5e5SAndroid Build Coastguard Worker 	if (ret)
861*858ea5e5SAndroid Build Coastguard Worker 		return -1;
862*858ea5e5SAndroid Build Coastguard Worker 
863*858ea5e5SAndroid Build Coastguard Worker 	sock = netlink_open(&nl_pid);
864*858ea5e5SAndroid Build Coastguard Worker 	if (sock < 0) {
865*858ea5e5SAndroid Build Coastguard Worker 		fprintf(stderr, "failed to open netlink sock\n");
866*858ea5e5SAndroid Build Coastguard Worker 		return -1;
867*858ea5e5SAndroid Build Coastguard Worker 	}
868*858ea5e5SAndroid Build Coastguard Worker 
869*858ea5e5SAndroid Build Coastguard Worker 	dev_array.devices = NULL;
870*858ea5e5SAndroid Build Coastguard Worker 	dev_array.used_len = 0;
871*858ea5e5SAndroid Build Coastguard Worker 	dev_array.array_len = 0;
872*858ea5e5SAndroid Build Coastguard Worker 	dev_array.filter_idx = filter_idx;
873*858ea5e5SAndroid Build Coastguard Worker 
874*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
875*858ea5e5SAndroid Build Coastguard Worker 		jsonw_start_array(json_wtr);
876*858ea5e5SAndroid Build Coastguard Worker 	NET_START_OBJECT;
877*858ea5e5SAndroid Build Coastguard Worker 	NET_START_ARRAY("xdp", "%s:\n");
878*858ea5e5SAndroid Build Coastguard Worker 	ret = netlink_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array);
879*858ea5e5SAndroid Build Coastguard Worker 	NET_END_ARRAY("\n");
880*858ea5e5SAndroid Build Coastguard Worker 
881*858ea5e5SAndroid Build Coastguard Worker 	if (!ret) {
882*858ea5e5SAndroid Build Coastguard Worker 		NET_START_ARRAY("tc", "%s:\n");
883*858ea5e5SAndroid Build Coastguard Worker 		for (i = 0; i < dev_array.used_len; i++) {
884*858ea5e5SAndroid Build Coastguard Worker 			show_dev_tc_bpf(&dev_array.devices[i]);
885*858ea5e5SAndroid Build Coastguard Worker 			ret = show_dev_tc_bpf_classic(sock, nl_pid,
886*858ea5e5SAndroid Build Coastguard Worker 						      &dev_array.devices[i]);
887*858ea5e5SAndroid Build Coastguard Worker 			if (ret)
888*858ea5e5SAndroid Build Coastguard Worker 				break;
889*858ea5e5SAndroid Build Coastguard Worker 		}
890*858ea5e5SAndroid Build Coastguard Worker 		NET_END_ARRAY("\n");
891*858ea5e5SAndroid Build Coastguard Worker 	}
892*858ea5e5SAndroid Build Coastguard Worker 
893*858ea5e5SAndroid Build Coastguard Worker 	NET_START_ARRAY("flow_dissector", "%s:\n");
894*858ea5e5SAndroid Build Coastguard Worker 	if (attach_info.flow_dissector_id > 0)
895*858ea5e5SAndroid Build Coastguard Worker 		NET_DUMP_UINT("id", "id %u", attach_info.flow_dissector_id);
896*858ea5e5SAndroid Build Coastguard Worker 	NET_END_ARRAY("\n");
897*858ea5e5SAndroid Build Coastguard Worker 
898*858ea5e5SAndroid Build Coastguard Worker 	NET_START_ARRAY("netfilter", "%s:\n");
899*858ea5e5SAndroid Build Coastguard Worker 	show_link_netfilter();
900*858ea5e5SAndroid Build Coastguard Worker 	NET_END_ARRAY("\n");
901*858ea5e5SAndroid Build Coastguard Worker 
902*858ea5e5SAndroid Build Coastguard Worker 	NET_END_OBJECT;
903*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
904*858ea5e5SAndroid Build Coastguard Worker 		jsonw_end_array(json_wtr);
905*858ea5e5SAndroid Build Coastguard Worker 
906*858ea5e5SAndroid Build Coastguard Worker 	if (ret) {
907*858ea5e5SAndroid Build Coastguard Worker 		if (json_output)
908*858ea5e5SAndroid Build Coastguard Worker 			jsonw_null(json_wtr);
909*858ea5e5SAndroid Build Coastguard Worker 		libbpf_strerror(ret, err_buf, sizeof(err_buf));
910*858ea5e5SAndroid Build Coastguard Worker 		fprintf(stderr, "Error: %s\n", err_buf);
911*858ea5e5SAndroid Build Coastguard Worker 	}
912*858ea5e5SAndroid Build Coastguard Worker 	free(dev_array.devices);
913*858ea5e5SAndroid Build Coastguard Worker 	close(sock);
914*858ea5e5SAndroid Build Coastguard Worker 	return ret;
915*858ea5e5SAndroid Build Coastguard Worker }
916*858ea5e5SAndroid Build Coastguard Worker 
do_help(int argc,char ** argv)917*858ea5e5SAndroid Build Coastguard Worker static int do_help(int argc, char **argv)
918*858ea5e5SAndroid Build Coastguard Worker {
919*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
920*858ea5e5SAndroid Build Coastguard Worker 		jsonw_null(json_wtr);
921*858ea5e5SAndroid Build Coastguard Worker 		return 0;
922*858ea5e5SAndroid Build Coastguard Worker 	}
923*858ea5e5SAndroid Build Coastguard Worker 
924*858ea5e5SAndroid Build Coastguard Worker 	fprintf(stderr,
925*858ea5e5SAndroid Build Coastguard Worker 		"Usage: %1$s %2$s { show | list } [dev <devname>]\n"
926*858ea5e5SAndroid Build Coastguard Worker 		"       %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite ]\n"
927*858ea5e5SAndroid Build Coastguard Worker 		"       %1$s %2$s detach ATTACH_TYPE dev <devname>\n"
928*858ea5e5SAndroid Build Coastguard Worker 		"       %1$s %2$s help\n"
929*858ea5e5SAndroid Build Coastguard Worker 		"\n"
930*858ea5e5SAndroid Build Coastguard Worker 		"       " HELP_SPEC_PROGRAM "\n"
931*858ea5e5SAndroid Build Coastguard Worker 		"       ATTACH_TYPE := { xdp | xdpgeneric | xdpdrv | xdpoffload }\n"
932*858ea5e5SAndroid Build Coastguard Worker 		"       " HELP_SPEC_OPTIONS " }\n"
933*858ea5e5SAndroid Build Coastguard Worker 		"\n"
934*858ea5e5SAndroid Build Coastguard Worker 		"Note: Only xdp, tcx, tc, netkit, flow_dissector and netfilter attachments\n"
935*858ea5e5SAndroid Build Coastguard Worker 		"      are currently supported.\n"
936*858ea5e5SAndroid Build Coastguard Worker 		"      For progs attached to cgroups, use \"bpftool cgroup\"\n"
937*858ea5e5SAndroid Build Coastguard Worker 		"      to dump program attachments. For program types\n"
938*858ea5e5SAndroid Build Coastguard Worker 		"      sk_{filter,skb,msg,reuseport} and lwt/seg6, please\n"
939*858ea5e5SAndroid Build Coastguard Worker 		"      consult iproute2.\n"
940*858ea5e5SAndroid Build Coastguard Worker 		"",
941*858ea5e5SAndroid Build Coastguard Worker 		bin_name, argv[-2]);
942*858ea5e5SAndroid Build Coastguard Worker 
943*858ea5e5SAndroid Build Coastguard Worker 	return 0;
944*858ea5e5SAndroid Build Coastguard Worker }
945*858ea5e5SAndroid Build Coastguard Worker 
946*858ea5e5SAndroid Build Coastguard Worker static const struct cmd cmds[] = {
947*858ea5e5SAndroid Build Coastguard Worker 	{ "show",	do_show },
948*858ea5e5SAndroid Build Coastguard Worker 	{ "list",	do_show },
949*858ea5e5SAndroid Build Coastguard Worker 	{ "attach",	do_attach },
950*858ea5e5SAndroid Build Coastguard Worker 	{ "detach",	do_detach },
951*858ea5e5SAndroid Build Coastguard Worker 	{ "help",	do_help },
952*858ea5e5SAndroid Build Coastguard Worker 	{ 0 }
953*858ea5e5SAndroid Build Coastguard Worker };
954*858ea5e5SAndroid Build Coastguard Worker 
do_net(int argc,char ** argv)955*858ea5e5SAndroid Build Coastguard Worker int do_net(int argc, char **argv)
956*858ea5e5SAndroid Build Coastguard Worker {
957*858ea5e5SAndroid Build Coastguard Worker 	return cmd_select(cmds, argc, argv, do_help);
958*858ea5e5SAndroid Build Coastguard Worker }
959