1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2*4882a593Smuzhiyun // Copyright (C) 2018 Facebook
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <stdlib.h>
5*4882a593Smuzhiyun #include <string.h>
6*4882a593Smuzhiyun #include <bpf/libbpf.h>
7*4882a593Smuzhiyun #include <linux/rtnetlink.h>
8*4882a593Smuzhiyun #include <linux/tc_act/tc_bpf.h>
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include "bpf/nlattr.h"
11*4882a593Smuzhiyun #include "main.h"
12*4882a593Smuzhiyun #include "netlink_dumper.h"
13*4882a593Smuzhiyun
xdp_dump_prog_id(struct nlattr ** tb,int attr,const char * mode,bool new_json_object)14*4882a593Smuzhiyun static void xdp_dump_prog_id(struct nlattr **tb, int attr,
15*4882a593Smuzhiyun const char *mode,
16*4882a593Smuzhiyun bool new_json_object)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun if (!tb[attr])
19*4882a593Smuzhiyun return;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun if (new_json_object)
22*4882a593Smuzhiyun NET_START_OBJECT
23*4882a593Smuzhiyun NET_DUMP_STR("mode", " %s", mode);
24*4882a593Smuzhiyun NET_DUMP_UINT("id", " id %u", libbpf_nla_getattr_u32(tb[attr]))
25*4882a593Smuzhiyun if (new_json_object)
26*4882a593Smuzhiyun NET_END_OBJECT
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun
do_xdp_dump_one(struct nlattr * attr,unsigned int ifindex,const char * name)29*4882a593Smuzhiyun static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex,
30*4882a593Smuzhiyun const char *name)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun struct nlattr *tb[IFLA_XDP_MAX + 1];
33*4882a593Smuzhiyun unsigned char mode;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun if (libbpf_nla_parse_nested(tb, IFLA_XDP_MAX, attr, NULL) < 0)
36*4882a593Smuzhiyun return -1;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun if (!tb[IFLA_XDP_ATTACHED])
39*4882a593Smuzhiyun return 0;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun mode = libbpf_nla_getattr_u8(tb[IFLA_XDP_ATTACHED]);
42*4882a593Smuzhiyun if (mode == XDP_ATTACHED_NONE)
43*4882a593Smuzhiyun return 0;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun NET_START_OBJECT;
46*4882a593Smuzhiyun if (name)
47*4882a593Smuzhiyun NET_DUMP_STR("devname", "%s", name);
48*4882a593Smuzhiyun NET_DUMP_UINT("ifindex", "(%d)", ifindex);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun if (mode == XDP_ATTACHED_MULTI) {
51*4882a593Smuzhiyun if (json_output) {
52*4882a593Smuzhiyun jsonw_name(json_wtr, "multi_attachments");
53*4882a593Smuzhiyun jsonw_start_array(json_wtr);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun xdp_dump_prog_id(tb, IFLA_XDP_SKB_PROG_ID, "generic", true);
56*4882a593Smuzhiyun xdp_dump_prog_id(tb, IFLA_XDP_DRV_PROG_ID, "driver", true);
57*4882a593Smuzhiyun xdp_dump_prog_id(tb, IFLA_XDP_HW_PROG_ID, "offload", true);
58*4882a593Smuzhiyun if (json_output)
59*4882a593Smuzhiyun jsonw_end_array(json_wtr);
60*4882a593Smuzhiyun } else if (mode == XDP_ATTACHED_DRV) {
61*4882a593Smuzhiyun xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "driver", false);
62*4882a593Smuzhiyun } else if (mode == XDP_ATTACHED_SKB) {
63*4882a593Smuzhiyun xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "generic", false);
64*4882a593Smuzhiyun } else if (mode == XDP_ATTACHED_HW) {
65*4882a593Smuzhiyun xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "offload", false);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun NET_END_OBJECT_FINAL;
69*4882a593Smuzhiyun return 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
do_xdp_dump(struct ifinfomsg * ifinfo,struct nlattr ** tb)72*4882a593Smuzhiyun int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun if (!tb[IFLA_XDP])
75*4882a593Smuzhiyun return 0;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun return do_xdp_dump_one(tb[IFLA_XDP], ifinfo->ifi_index,
78*4882a593Smuzhiyun libbpf_nla_getattr_str(tb[IFLA_IFNAME]));
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
do_bpf_dump_one_act(struct nlattr * attr)81*4882a593Smuzhiyun static int do_bpf_dump_one_act(struct nlattr *attr)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (libbpf_nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0)
86*4882a593Smuzhiyun return -LIBBPF_ERRNO__NLPARSE;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun if (!tb[TCA_ACT_BPF_PARMS])
89*4882a593Smuzhiyun return -LIBBPF_ERRNO__NLPARSE;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun NET_START_OBJECT_NESTED2;
92*4882a593Smuzhiyun if (tb[TCA_ACT_BPF_NAME])
93*4882a593Smuzhiyun NET_DUMP_STR("name", "%s",
94*4882a593Smuzhiyun libbpf_nla_getattr_str(tb[TCA_ACT_BPF_NAME]));
95*4882a593Smuzhiyun if (tb[TCA_ACT_BPF_ID])
96*4882a593Smuzhiyun NET_DUMP_UINT("id", " id %u",
97*4882a593Smuzhiyun libbpf_nla_getattr_u32(tb[TCA_ACT_BPF_ID]));
98*4882a593Smuzhiyun NET_END_OBJECT_NESTED;
99*4882a593Smuzhiyun return 0;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
do_dump_one_act(struct nlattr * attr)102*4882a593Smuzhiyun static int do_dump_one_act(struct nlattr *attr)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun struct nlattr *tb[TCA_ACT_MAX + 1];
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (!attr)
107*4882a593Smuzhiyun return 0;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX, attr, NULL) < 0)
110*4882a593Smuzhiyun return -LIBBPF_ERRNO__NLPARSE;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun if (tb[TCA_ACT_KIND] &&
113*4882a593Smuzhiyun strcmp(libbpf_nla_data(tb[TCA_ACT_KIND]), "bpf") == 0)
114*4882a593Smuzhiyun return do_bpf_dump_one_act(tb[TCA_ACT_OPTIONS]);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun return 0;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
do_bpf_act_dump(struct nlattr * attr)119*4882a593Smuzhiyun static int do_bpf_act_dump(struct nlattr *attr)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
122*4882a593Smuzhiyun int act, ret;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0)
125*4882a593Smuzhiyun return -LIBBPF_ERRNO__NLPARSE;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun NET_START_ARRAY("act", " %s [");
128*4882a593Smuzhiyun for (act = 0; act <= TCA_ACT_MAX_PRIO; act++) {
129*4882a593Smuzhiyun ret = do_dump_one_act(tb[act]);
130*4882a593Smuzhiyun if (ret)
131*4882a593Smuzhiyun break;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun NET_END_ARRAY("] ");
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun return ret;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
do_bpf_filter_dump(struct nlattr * attr)138*4882a593Smuzhiyun static int do_bpf_filter_dump(struct nlattr *attr)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun struct nlattr *tb[TCA_BPF_MAX + 1];
141*4882a593Smuzhiyun int ret;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun if (libbpf_nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0)
144*4882a593Smuzhiyun return -LIBBPF_ERRNO__NLPARSE;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun if (tb[TCA_BPF_NAME])
147*4882a593Smuzhiyun NET_DUMP_STR("name", " %s",
148*4882a593Smuzhiyun libbpf_nla_getattr_str(tb[TCA_BPF_NAME]));
149*4882a593Smuzhiyun if (tb[TCA_BPF_ID])
150*4882a593Smuzhiyun NET_DUMP_UINT("id", " id %u",
151*4882a593Smuzhiyun libbpf_nla_getattr_u32(tb[TCA_BPF_ID]));
152*4882a593Smuzhiyun if (tb[TCA_BPF_ACT]) {
153*4882a593Smuzhiyun ret = do_bpf_act_dump(tb[TCA_BPF_ACT]);
154*4882a593Smuzhiyun if (ret)
155*4882a593Smuzhiyun return ret;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun return 0;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
do_filter_dump(struct tcmsg * info,struct nlattr ** tb,const char * kind,const char * devname,int ifindex)161*4882a593Smuzhiyun int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind,
162*4882a593Smuzhiyun const char *devname, int ifindex)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun int ret = 0;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun if (tb[TCA_OPTIONS] &&
167*4882a593Smuzhiyun strcmp(libbpf_nla_data(tb[TCA_KIND]), "bpf") == 0) {
168*4882a593Smuzhiyun NET_START_OBJECT;
169*4882a593Smuzhiyun if (devname[0] != '\0')
170*4882a593Smuzhiyun NET_DUMP_STR("devname", "%s", devname);
171*4882a593Smuzhiyun NET_DUMP_UINT("ifindex", "(%u)", ifindex);
172*4882a593Smuzhiyun NET_DUMP_STR("kind", " %s", kind);
173*4882a593Smuzhiyun ret = do_bpf_filter_dump(tb[TCA_OPTIONS]);
174*4882a593Smuzhiyun NET_END_OBJECT_FINAL;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun return ret;
178*4882a593Smuzhiyun }
179