blob: e12494fd1d2e9849d255ff7efe96ddceab328ebf [file] [log] [blame]
Yonghong Songf6f3bac2018-09-05 16:58:06 -07001// 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
14static 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
23static 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
58int 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
67static 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
83static 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
107static 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
123static 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
142static 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
168int 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}