1907b2236SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2f6f3bac0SYonghong Song // Copyright (C) 2018 Facebook
3f6f3bac0SYonghong Song 
4f6f3bac0SYonghong Song #include <stdlib.h>
5f6f3bac0SYonghong Song #include <string.h>
6229c3b47SToke Høiland-Jørgensen #include <bpf/libbpf.h>
7f6f3bac0SYonghong Song #include <linux/rtnetlink.h>
8f6f3bac0SYonghong Song #include <linux/tc_act/tc_bpf.h>
9f6f3bac0SYonghong Song 
10229c3b47SToke Høiland-Jørgensen #include "bpf/nlattr.h"
11f6f3bac0SYonghong Song #include "main.h"
12f6f3bac0SYonghong Song #include "netlink_dumper.h"
13f6f3bac0SYonghong Song 
xdp_dump_prog_id(struct nlattr ** tb,int attr,const char * mode,bool new_json_object)14f6f3bac0SYonghong Song static void xdp_dump_prog_id(struct nlattr **tb, int attr,
157900efc1SYonghong Song 			     const char *mode,
167900efc1SYonghong Song 			     bool new_json_object)
17f6f3bac0SYonghong Song {
18f6f3bac0SYonghong Song 	if (!tb[attr])
19f6f3bac0SYonghong Song 		return;
20f6f3bac0SYonghong Song 
217900efc1SYonghong Song 	if (new_json_object)
227900efc1SYonghong Song 		NET_START_OBJECT
237900efc1SYonghong Song 	NET_DUMP_STR("mode", " %s", mode);
24f04bc8a4SAndrey Ignatov 	NET_DUMP_UINT("id", " id %u", libbpf_nla_getattr_u32(tb[attr]))
257900efc1SYonghong Song 	if (new_json_object)
267900efc1SYonghong Song 		NET_END_OBJECT
27f6f3bac0SYonghong Song }
28f6f3bac0SYonghong Song 
do_xdp_dump_one(struct nlattr * attr,unsigned int ifindex,const char * name)29f6f3bac0SYonghong Song static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex,
30f6f3bac0SYonghong Song 			   const char *name)
31f6f3bac0SYonghong Song {
32f6f3bac0SYonghong Song 	struct nlattr *tb[IFLA_XDP_MAX + 1];
33f6f3bac0SYonghong Song 	unsigned char mode;
34f6f3bac0SYonghong Song 
35f04bc8a4SAndrey Ignatov 	if (libbpf_nla_parse_nested(tb, IFLA_XDP_MAX, attr, NULL) < 0)
36f6f3bac0SYonghong Song 		return -1;
37f6f3bac0SYonghong Song 
38f6f3bac0SYonghong Song 	if (!tb[IFLA_XDP_ATTACHED])
39f6f3bac0SYonghong Song 		return 0;
40f6f3bac0SYonghong Song 
41f04bc8a4SAndrey Ignatov 	mode = libbpf_nla_getattr_u8(tb[IFLA_XDP_ATTACHED]);
42f6f3bac0SYonghong Song 	if (mode == XDP_ATTACHED_NONE)
43f6f3bac0SYonghong Song 		return 0;
44f6f3bac0SYonghong Song 
45f6f3bac0SYonghong Song 	NET_START_OBJECT;
46f6f3bac0SYonghong Song 	if (name)
477900efc1SYonghong Song 		NET_DUMP_STR("devname", "%s", name);
487900efc1SYonghong Song 	NET_DUMP_UINT("ifindex", "(%d)", ifindex);
49f6f3bac0SYonghong Song 
50f6f3bac0SYonghong Song 	if (mode == XDP_ATTACHED_MULTI) {
517900efc1SYonghong Song 		if (json_output) {
527900efc1SYonghong Song 			jsonw_name(json_wtr, "multi_attachments");
537900efc1SYonghong Song 			jsonw_start_array(json_wtr);
547900efc1SYonghong Song 		}
557900efc1SYonghong Song 		xdp_dump_prog_id(tb, IFLA_XDP_SKB_PROG_ID, "generic", true);
567900efc1SYonghong Song 		xdp_dump_prog_id(tb, IFLA_XDP_DRV_PROG_ID, "driver", true);
577900efc1SYonghong Song 		xdp_dump_prog_id(tb, IFLA_XDP_HW_PROG_ID, "offload", true);
587900efc1SYonghong Song 		if (json_output)
597900efc1SYonghong Song 			jsonw_end_array(json_wtr);
607900efc1SYonghong Song 	} else if (mode == XDP_ATTACHED_DRV) {
617900efc1SYonghong Song 		xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "driver", false);
627900efc1SYonghong Song 	} else if (mode == XDP_ATTACHED_SKB) {
637900efc1SYonghong Song 		xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "generic", false);
647900efc1SYonghong Song 	} else if (mode == XDP_ATTACHED_HW) {
657900efc1SYonghong Song 		xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "offload", false);
66f6f3bac0SYonghong Song 	}
67f6f3bac0SYonghong Song 
68f6f3bac0SYonghong Song 	NET_END_OBJECT_FINAL;
69f6f3bac0SYonghong Song 	return 0;
70f6f3bac0SYonghong Song }
71f6f3bac0SYonghong Song 
do_xdp_dump(struct ifinfomsg * ifinfo,struct nlattr ** tb)72f6f3bac0SYonghong Song int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb)
73f6f3bac0SYonghong Song {
74f6f3bac0SYonghong Song 	if (!tb[IFLA_XDP])
75f6f3bac0SYonghong Song 		return 0;
76f6f3bac0SYonghong Song 
77f6f3bac0SYonghong Song 	return do_xdp_dump_one(tb[IFLA_XDP], ifinfo->ifi_index,
78f04bc8a4SAndrey Ignatov 			       libbpf_nla_getattr_str(tb[IFLA_IFNAME]));
79f6f3bac0SYonghong Song }
80f6f3bac0SYonghong Song 
do_bpf_dump_one_act(struct nlattr * attr)81f6f3bac0SYonghong Song static int do_bpf_dump_one_act(struct nlattr *attr)
82f6f3bac0SYonghong Song {
83f6f3bac0SYonghong Song 	struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
84f6f3bac0SYonghong Song 
85f04bc8a4SAndrey Ignatov 	if (libbpf_nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0)
86f6f3bac0SYonghong Song 		return -LIBBPF_ERRNO__NLPARSE;
87f6f3bac0SYonghong Song 
88f6f3bac0SYonghong Song 	if (!tb[TCA_ACT_BPF_PARMS])
89f6f3bac0SYonghong Song 		return -LIBBPF_ERRNO__NLPARSE;
90f6f3bac0SYonghong Song 
91f6f3bac0SYonghong Song 	NET_START_OBJECT_NESTED2;
92f6f3bac0SYonghong Song 	if (tb[TCA_ACT_BPF_NAME])
937900efc1SYonghong Song 		NET_DUMP_STR("name", "%s",
94f04bc8a4SAndrey Ignatov 			     libbpf_nla_getattr_str(tb[TCA_ACT_BPF_NAME]));
95f6f3bac0SYonghong Song 	if (tb[TCA_ACT_BPF_ID])
967900efc1SYonghong Song 		NET_DUMP_UINT("id", " id %u",
97f04bc8a4SAndrey Ignatov 			      libbpf_nla_getattr_u32(tb[TCA_ACT_BPF_ID]));
98f6f3bac0SYonghong Song 	NET_END_OBJECT_NESTED;
99f6f3bac0SYonghong Song 	return 0;
100f6f3bac0SYonghong Song }
101f6f3bac0SYonghong Song 
do_dump_one_act(struct nlattr * attr)102f6f3bac0SYonghong Song static int do_dump_one_act(struct nlattr *attr)
103f6f3bac0SYonghong Song {
104f6f3bac0SYonghong Song 	struct nlattr *tb[TCA_ACT_MAX + 1];
105f6f3bac0SYonghong Song 
106f6f3bac0SYonghong Song 	if (!attr)
107f6f3bac0SYonghong Song 		return 0;
108f6f3bac0SYonghong Song 
109f04bc8a4SAndrey Ignatov 	if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX, attr, NULL) < 0)
110f6f3bac0SYonghong Song 		return -LIBBPF_ERRNO__NLPARSE;
111f6f3bac0SYonghong Song 
112f04bc8a4SAndrey Ignatov 	if (tb[TCA_ACT_KIND] &&
113f04bc8a4SAndrey Ignatov 	    strcmp(libbpf_nla_data(tb[TCA_ACT_KIND]), "bpf") == 0)
114f6f3bac0SYonghong Song 		return do_bpf_dump_one_act(tb[TCA_ACT_OPTIONS]);
115f6f3bac0SYonghong Song 
116f6f3bac0SYonghong Song 	return 0;
117f6f3bac0SYonghong Song }
118f6f3bac0SYonghong Song 
do_bpf_act_dump(struct nlattr * attr)119f6f3bac0SYonghong Song static int do_bpf_act_dump(struct nlattr *attr)
120f6f3bac0SYonghong Song {
121f6f3bac0SYonghong Song 	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
122f6f3bac0SYonghong Song 	int act, ret;
123f6f3bac0SYonghong Song 
124f04bc8a4SAndrey Ignatov 	if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0)
125f6f3bac0SYonghong Song 		return -LIBBPF_ERRNO__NLPARSE;
126f6f3bac0SYonghong Song 
1277900efc1SYonghong Song 	NET_START_ARRAY("act", " %s [");
128f6f3bac0SYonghong Song 	for (act = 0; act <= TCA_ACT_MAX_PRIO; act++) {
129f6f3bac0SYonghong Song 		ret = do_dump_one_act(tb[act]);
130f6f3bac0SYonghong Song 		if (ret)
131f6f3bac0SYonghong Song 			break;
132f6f3bac0SYonghong Song 	}
1337900efc1SYonghong Song 	NET_END_ARRAY("] ");
134f6f3bac0SYonghong Song 
135f6f3bac0SYonghong Song 	return ret;
136f6f3bac0SYonghong Song }
137f6f3bac0SYonghong Song 
do_bpf_filter_dump(struct nlattr * attr)138f6f3bac0SYonghong Song static int do_bpf_filter_dump(struct nlattr *attr)
139f6f3bac0SYonghong Song {
140f6f3bac0SYonghong Song 	struct nlattr *tb[TCA_BPF_MAX + 1];
141f6f3bac0SYonghong Song 	int ret;
142f6f3bac0SYonghong Song 
143f04bc8a4SAndrey Ignatov 	if (libbpf_nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0)
144f6f3bac0SYonghong Song 		return -LIBBPF_ERRNO__NLPARSE;
145f6f3bac0SYonghong Song 
146f6f3bac0SYonghong Song 	if (tb[TCA_BPF_NAME])
147f04bc8a4SAndrey Ignatov 		NET_DUMP_STR("name", " %s",
148f04bc8a4SAndrey Ignatov 			     libbpf_nla_getattr_str(tb[TCA_BPF_NAME]));
149f6f3bac0SYonghong Song 	if (tb[TCA_BPF_ID])
150f04bc8a4SAndrey Ignatov 		NET_DUMP_UINT("id", " id %u",
151f04bc8a4SAndrey Ignatov 			      libbpf_nla_getattr_u32(tb[TCA_BPF_ID]));
152f6f3bac0SYonghong Song 	if (tb[TCA_BPF_ACT]) {
153f6f3bac0SYonghong Song 		ret = do_bpf_act_dump(tb[TCA_BPF_ACT]);
154f6f3bac0SYonghong Song 		if (ret)
155f6f3bac0SYonghong Song 			return ret;
156f6f3bac0SYonghong Song 	}
157f6f3bac0SYonghong Song 
158f6f3bac0SYonghong Song 	return 0;
159f6f3bac0SYonghong Song }
160f6f3bac0SYonghong Song 
do_filter_dump(struct tcmsg * info,struct nlattr ** tb,const char * kind,const char * devname,int ifindex)1617900efc1SYonghong Song int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind,
1627900efc1SYonghong Song 		   const char *devname, int ifindex)
163f6f3bac0SYonghong Song {
164f6f3bac0SYonghong Song 	int ret = 0;
165f6f3bac0SYonghong Song 
166f04bc8a4SAndrey Ignatov 	if (tb[TCA_OPTIONS] &&
167f04bc8a4SAndrey Ignatov 	    strcmp(libbpf_nla_data(tb[TCA_KIND]), "bpf") == 0) {
168f6f3bac0SYonghong Song 		NET_START_OBJECT;
1697900efc1SYonghong Song 		if (devname[0] != '\0')
1707900efc1SYonghong Song 			NET_DUMP_STR("devname", "%s", devname);
1717900efc1SYonghong Song 		NET_DUMP_UINT("ifindex", "(%u)", ifindex);
1727900efc1SYonghong Song 		NET_DUMP_STR("kind", " %s", kind);
173f6f3bac0SYonghong Song 		ret = do_bpf_filter_dump(tb[TCA_OPTIONS]);
174f6f3bac0SYonghong Song 		NET_END_OBJECT_FINAL;
175f6f3bac0SYonghong Song 	}
176f6f3bac0SYonghong Song 
177f6f3bac0SYonghong Song 	return ret;
178f6f3bac0SYonghong Song }
179