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