Skip to content

Commit 36f1678

Browse files
yonghong-songAlexei Starovoitov
authored andcommitted
tools/bpf: add more netlink functionalities in lib/bpf
This patch added a few netlink attribute parsing functions and the netlink API functions to query networking links, tc classes, tc qdiscs and tc filters. For example, the following API is to get networking links: int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg, void *cookie); Note that when the API is called, the user also provided a callback function with the following signature: int (*dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb); The "cookie" is the parameter the user passed to the API and will be available for the callback function. The "msg" is the information about the result, e.g., ifinfomsg or tcmsg. The "tb" is the parsed netlink attributes. Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent f701077 commit 36f1678

File tree

5 files changed

+238
-15
lines changed

5 files changed

+238
-15
lines changed

tools/lib/bpf/libbpf.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ enum libbpf_errno {
4646
LIBBPF_ERRNO__PROGTYPE, /* Kernel doesn't support this program type */
4747
LIBBPF_ERRNO__WRNGPID, /* Wrong pid in netlink message */
4848
LIBBPF_ERRNO__INVSEQ, /* Invalid netlink sequence */
49+
LIBBPF_ERRNO__NLPARSE, /* netlink parsing error */
4950
__LIBBPF_ERRNO__END,
5051
};
5152

@@ -297,4 +298,19 @@ int bpf_perf_event_read_simple(void *mem, unsigned long size,
297298
unsigned long page_size,
298299
void **buf, size_t *buf_len,
299300
bpf_perf_event_print_t fn, void *priv);
301+
302+
struct nlmsghdr;
303+
struct nlattr;
304+
typedef int (*dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
305+
typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, dump_nlmsg_t,
306+
void *cookie);
307+
int bpf_netlink_open(unsigned int *nl_pid);
308+
int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg,
309+
void *cookie);
310+
int nl_get_class(int sock, unsigned int nl_pid, int ifindex,
311+
dump_nlmsg_t dump_class_nlmsg, void *cookie);
312+
int nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
313+
dump_nlmsg_t dump_qdisc_nlmsg, void *cookie);
314+
int nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
315+
dump_nlmsg_t dump_filter_nlmsg, void *cookie);
300316
#endif

tools/lib/bpf/libbpf_errno.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {
4242
[ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type",
4343
[ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message",
4444
[ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence",
45+
[ERRCODE_OFFSET(NLPARSE)] = "Incorrect netlink message parsing",
4546
};
4647

4748
int libbpf_strerror(int err, char *buf, size_t size)

tools/lib/bpf/netlink.c

Lines changed: 162 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#define SOL_NETLINK 270
1919
#endif
2020

21-
static int bpf_netlink_open(__u32 *nl_pid)
21+
int bpf_netlink_open(__u32 *nl_pid)
2222
{
2323
struct sockaddr_nl sa;
2424
socklen_t addrlen;
@@ -61,7 +61,9 @@ static int bpf_netlink_open(__u32 *nl_pid)
6161
return ret;
6262
}
6363

64-
static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq)
64+
static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq,
65+
__dump_nlmsg_t _fn, dump_nlmsg_t fn,
66+
void *cookie)
6567
{
6668
struct nlmsgerr *err;
6769
struct nlmsghdr *nh;
@@ -98,6 +100,11 @@ static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq)
98100
default:
99101
break;
100102
}
103+
if (_fn) {
104+
ret = _fn(nh, fn, cookie);
105+
if (ret)
106+
return ret;
107+
}
101108
}
102109
}
103110
ret = 0;
@@ -157,9 +164,161 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
157164
ret = -errno;
158165
goto cleanup;
159166
}
160-
ret = bpf_netlink_recv(sock, nl_pid, seq);
167+
ret = bpf_netlink_recv(sock, nl_pid, seq, NULL, NULL, NULL);
161168

162169
cleanup:
163170
close(sock);
164171
return ret;
165172
}
173+
174+
static int __dump_link_nlmsg(struct nlmsghdr *nlh, dump_nlmsg_t dump_link_nlmsg,
175+
void *cookie)
176+
{
177+
struct nlattr *tb[IFLA_MAX + 1], *attr;
178+
struct ifinfomsg *ifi = NLMSG_DATA(nlh);
179+
int len;
180+
181+
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
182+
attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
183+
if (nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
184+
return -LIBBPF_ERRNO__NLPARSE;
185+
186+
return dump_link_nlmsg(cookie, ifi, tb);
187+
}
188+
189+
int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg,
190+
void *cookie)
191+
{
192+
struct {
193+
struct nlmsghdr nlh;
194+
struct ifinfomsg ifm;
195+
} req = {
196+
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
197+
.nlh.nlmsg_type = RTM_GETLINK,
198+
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
199+
.ifm.ifi_family = AF_PACKET,
200+
};
201+
int seq = time(NULL);
202+
203+
req.nlh.nlmsg_seq = seq;
204+
if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
205+
return -errno;
206+
207+
return bpf_netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg,
208+
dump_link_nlmsg, cookie);
209+
}
210+
211+
static int __dump_class_nlmsg(struct nlmsghdr *nlh,
212+
dump_nlmsg_t dump_class_nlmsg, void *cookie)
213+
{
214+
struct nlattr *tb[TCA_MAX + 1], *attr;
215+
struct tcmsg *t = NLMSG_DATA(nlh);
216+
int len;
217+
218+
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
219+
attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
220+
if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
221+
return -LIBBPF_ERRNO__NLPARSE;
222+
223+
return dump_class_nlmsg(cookie, t, tb);
224+
}
225+
226+
int nl_get_class(int sock, unsigned int nl_pid, int ifindex,
227+
dump_nlmsg_t dump_class_nlmsg, void *cookie)
228+
{
229+
struct {
230+
struct nlmsghdr nlh;
231+
struct tcmsg t;
232+
} req = {
233+
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
234+
.nlh.nlmsg_type = RTM_GETTCLASS,
235+
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
236+
.t.tcm_family = AF_UNSPEC,
237+
.t.tcm_ifindex = ifindex,
238+
};
239+
int seq = time(NULL);
240+
241+
req.nlh.nlmsg_seq = seq;
242+
if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
243+
return -errno;
244+
245+
return bpf_netlink_recv(sock, nl_pid, seq, __dump_class_nlmsg,
246+
dump_class_nlmsg, cookie);
247+
}
248+
249+
static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh,
250+
dump_nlmsg_t dump_qdisc_nlmsg, void *cookie)
251+
{
252+
struct nlattr *tb[TCA_MAX + 1], *attr;
253+
struct tcmsg *t = NLMSG_DATA(nlh);
254+
int len;
255+
256+
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
257+
attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
258+
if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
259+
return -LIBBPF_ERRNO__NLPARSE;
260+
261+
return dump_qdisc_nlmsg(cookie, t, tb);
262+
}
263+
264+
int nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
265+
dump_nlmsg_t dump_qdisc_nlmsg, void *cookie)
266+
{
267+
struct {
268+
struct nlmsghdr nlh;
269+
struct tcmsg t;
270+
} req = {
271+
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
272+
.nlh.nlmsg_type = RTM_GETQDISC,
273+
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
274+
.t.tcm_family = AF_UNSPEC,
275+
.t.tcm_ifindex = ifindex,
276+
};
277+
int seq = time(NULL);
278+
279+
req.nlh.nlmsg_seq = seq;
280+
if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
281+
return -errno;
282+
283+
return bpf_netlink_recv(sock, nl_pid, seq, __dump_qdisc_nlmsg,
284+
dump_qdisc_nlmsg, cookie);
285+
}
286+
287+
static int __dump_filter_nlmsg(struct nlmsghdr *nlh,
288+
dump_nlmsg_t dump_filter_nlmsg, void *cookie)
289+
{
290+
struct nlattr *tb[TCA_MAX + 1], *attr;
291+
struct tcmsg *t = NLMSG_DATA(nlh);
292+
int len;
293+
294+
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
295+
attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
296+
if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
297+
return -LIBBPF_ERRNO__NLPARSE;
298+
299+
return dump_filter_nlmsg(cookie, t, tb);
300+
}
301+
302+
int nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
303+
dump_nlmsg_t dump_filter_nlmsg, void *cookie)
304+
{
305+
struct {
306+
struct nlmsghdr nlh;
307+
struct tcmsg t;
308+
} req = {
309+
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
310+
.nlh.nlmsg_type = RTM_GETTFILTER,
311+
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
312+
.t.tcm_family = AF_UNSPEC,
313+
.t.tcm_ifindex = ifindex,
314+
.t.tcm_parent = handle,
315+
};
316+
int seq = time(NULL);
317+
318+
req.nlh.nlmsg_seq = seq;
319+
if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
320+
return -errno;
321+
322+
return bpf_netlink_recv(sock, nl_pid, seq, __dump_filter_nlmsg,
323+
dump_filter_nlmsg, cookie);
324+
}

tools/lib/bpf/nlattr.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,6 @@ static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = {
2626
[NLA_FLAG] = 0,
2727
};
2828

29-
static int nla_len(const struct nlattr *nla)
30-
{
31-
return nla->nla_len - NLA_HDRLEN;
32-
}
33-
3429
static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
3530
{
3631
int totlen = NLA_ALIGN(nla->nla_len);
@@ -46,11 +41,6 @@ static int nla_ok(const struct nlattr *nla, int remaining)
4641
nla->nla_len <= remaining;
4742
}
4843

49-
static void *nla_data(const struct nlattr *nla)
50-
{
51-
return (char *) nla + NLA_HDRLEN;
52-
}
53-
5444
static int nla_type(const struct nlattr *nla)
5545
{
5646
return nla->nla_type & NLA_TYPE_MASK;
@@ -114,8 +104,8 @@ static inline int nlmsg_len(const struct nlmsghdr *nlh)
114104
* @see nla_validate
115105
* @return 0 on success or a negative error code.
116106
*/
117-
static int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
118-
struct nla_policy *policy)
107+
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
108+
struct nla_policy *policy)
119109
{
120110
struct nlattr *nla;
121111
int rem, err;
@@ -146,6 +136,25 @@ static int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int
146136
return err;
147137
}
148138

139+
/**
140+
* Create attribute index based on nested attribute
141+
* @arg tb Index array to be filled (maxtype+1 elements).
142+
* @arg maxtype Maximum attribute type expected and accepted.
143+
* @arg nla Nested Attribute.
144+
* @arg policy Attribute validation policy.
145+
*
146+
* Feeds the stream of attributes nested into the specified attribute
147+
* to nla_parse().
148+
*
149+
* @see nla_parse
150+
* @return 0 on success or a negative error code.
151+
*/
152+
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
153+
struct nla_policy *policy)
154+
{
155+
return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
156+
}
157+
149158
/* dump netlink extended ack error message */
150159
int nla_dump_errormsg(struct nlmsghdr *nlh)
151160
{

tools/lib/bpf/nlattr.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,44 @@ struct nla_policy {
6767
nla_ok(pos, rem); \
6868
pos = nla_next(pos, &(rem)))
6969

70+
/**
71+
* nla_data - head of payload
72+
* @nla: netlink attribute
73+
*/
74+
static inline void *nla_data(const struct nlattr *nla)
75+
{
76+
return (char *) nla + NLA_HDRLEN;
77+
}
78+
79+
static inline uint8_t nla_getattr_u8(const struct nlattr *nla)
80+
{
81+
return *(uint8_t *)nla_data(nla);
82+
}
83+
84+
static inline uint32_t nla_getattr_u32(const struct nlattr *nla)
85+
{
86+
return *(uint32_t *)nla_data(nla);
87+
}
88+
89+
static inline const char *nla_getattr_str(const struct nlattr *nla)
90+
{
91+
return (const char *)nla_data(nla);
92+
}
93+
94+
/**
95+
* nla_len - length of payload
96+
* @nla: netlink attribute
97+
*/
98+
static inline int nla_len(const struct nlattr *nla)
99+
{
100+
return nla->nla_len - NLA_HDRLEN;
101+
}
102+
103+
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
104+
struct nla_policy *policy);
105+
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
106+
struct nla_policy *policy);
107+
70108
int nla_dump_errormsg(struct nlmsghdr *nlh);
71109

72110
#endif /* __NLATTR_H */

0 commit comments

Comments
 (0)