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