aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-09-25 23:29:38 -0400
committerDavid S. Miller <davem@davemloft.net>2018-09-25 23:29:38 -0400
commit105bc1306e9b29c2aa2783b9524f7aec9b5a5b1f (patch)
treea3350d692a612e9536033e203200bd8eb8c47f48 /tools/lib/bpf
parent3475372ff60e4181d3845ed605958daf71c3e3b8 (diff)
parentd0e13a1488ad30dc3c2c9347b931cb10f892e3a4 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Daniel Borkmann says: ==================== pull-request: bpf-next 2018-09-25 The following pull-request contains BPF updates for your *net-next* tree. The main changes are: 1) Allow for RX stack hardening by implementing the kernel's flow dissector in BPF. Idea was originally presented at netconf 2017 [0]. Quote from merge commit: [...] Because of the rigorous checks of the BPF verifier, this provides significant security guarantees. In particular, the BPF flow dissector cannot get inside of an infinite loop, as with CVE-2013-4348, because BPF programs are guaranteed to terminate. It cannot read outside of packet bounds, because all memory accesses are checked. Also, with BPF the administrator can decide which protocols to support, reducing potential attack surface. Rarely encountered protocols can be excluded from dissection and the program can be updated without kernel recompile or reboot if a bug is discovered. [...] Also, a sample flow dissector has been implemented in BPF as part of this work, from Petar and Willem. [0] http://vger.kernel.org/netconf2017_files/rx_hardening_and_udp_gso.pdf 2) Add support for bpftool to list currently active attachment points of BPF networking programs providing a quick overview similar to bpftool's perf subcommand, from Yonghong. 3) Fix a verifier pruning instability bug where a union member from the register state was not cleared properly leading to branches not being pruned despite them being valid candidates, from Alexei. 4) Various smaller fast-path optimizations in XDP's map redirect code, from Jesper. 5) Enable to recognize BPF_MAP_TYPE_REUSEPORT_SOCKARRAY maps in bpftool, from Roman. 6) Remove a duplicate check in libbpf that probes for function storage, from Taeung. 7) Fix an issue in test_progs by avoid checking for errno since on success its value should not be checked, from Mauricio. 8) Fix unused variable warning in bpf_getsockopt() helper when CONFIG_INET is not configured, from Anders. 9) Fix a compilation failure in the BPF sample code's use of bpf_flow_keys, from Prashant. 10) Minor cleanups in BPF code, from Yue and Zhong. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'tools/lib/bpf')
-rw-r--r--tools/lib/bpf/Build2
-rw-r--r--tools/lib/bpf/bpf.c129
-rw-r--r--tools/lib/bpf/libbpf.c4
-rw-r--r--tools/lib/bpf/libbpf.h16
-rw-r--r--tools/lib/bpf/libbpf_errno.c1
-rw-r--r--tools/lib/bpf/netlink.c331
-rw-r--r--tools/lib/bpf/nlattr.c33
-rw-r--r--tools/lib/bpf/nlattr.h38
8 files changed, 411 insertions, 143 deletions
diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
index 6eb9bacd1948..7bc31c905018 100644
--- a/tools/lib/bpf/Build
+++ b/tools/lib/bpf/Build
@@ -1 +1 @@
libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 60aa4ca8b2c5..3878a26a2071 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -28,16 +28,8 @@
28#include <linux/bpf.h> 28#include <linux/bpf.h>
29#include "bpf.h" 29#include "bpf.h"
30#include "libbpf.h" 30#include "libbpf.h"
31#include "nlattr.h"
32#include <linux/rtnetlink.h>
33#include <linux/if_link.h>
34#include <sys/socket.h>
35#include <errno.h> 31#include <errno.h>
36 32
37#ifndef SOL_NETLINK
38#define SOL_NETLINK 270
39#endif
40
41/* 33/*
42 * When building perf, unistd.h is overridden. __NR_bpf is 34 * When building perf, unistd.h is overridden. __NR_bpf is
43 * required to be defined explicitly. 35 * required to be defined explicitly.
@@ -499,127 +491,6 @@ int bpf_raw_tracepoint_open(const char *name, int prog_fd)
499 return sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr)); 491 return sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr));
500} 492}
501 493
502int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
503{
504 struct sockaddr_nl sa;
505 int sock, seq = 0, len, ret = -1;
506 char buf[4096];
507 struct nlattr *nla, *nla_xdp;
508 struct {
509 struct nlmsghdr nh;
510 struct ifinfomsg ifinfo;
511 char attrbuf[64];
512 } req;
513 struct nlmsghdr *nh;
514 struct nlmsgerr *err;
515 socklen_t addrlen;
516 int one = 1;
517
518 memset(&sa, 0, sizeof(sa));
519 sa.nl_family = AF_NETLINK;
520
521 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
522 if (sock < 0) {
523 return -errno;
524 }
525
526 if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
527 &one, sizeof(one)) < 0) {
528 fprintf(stderr, "Netlink error reporting not supported\n");
529 }
530
531 if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
532 ret = -errno;
533 goto cleanup;
534 }
535
536 addrlen = sizeof(sa);
537 if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
538 ret = -errno;
539 goto cleanup;
540 }
541
542 if (addrlen != sizeof(sa)) {
543 ret = -LIBBPF_ERRNO__INTERNAL;
544 goto cleanup;
545 }
546
547 memset(&req, 0, sizeof(req));
548 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
549 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
550 req.nh.nlmsg_type = RTM_SETLINK;
551 req.nh.nlmsg_pid = 0;
552 req.nh.nlmsg_seq = ++seq;
553 req.ifinfo.ifi_family = AF_UNSPEC;
554 req.ifinfo.ifi_index = ifindex;
555
556 /* started nested attribute for XDP */
557 nla = (struct nlattr *)(((char *)&req)
558 + NLMSG_ALIGN(req.nh.nlmsg_len));
559 nla->nla_type = NLA_F_NESTED | IFLA_XDP;
560 nla->nla_len = NLA_HDRLEN;
561
562 /* add XDP fd */
563 nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
564 nla_xdp->nla_type = IFLA_XDP_FD;
565 nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
566 memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
567 nla->nla_len += nla_xdp->nla_len;
568
569 /* if user passed in any flags, add those too */
570 if (flags) {
571 nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
572 nla_xdp->nla_type = IFLA_XDP_FLAGS;
573 nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
574 memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
575 nla->nla_len += nla_xdp->nla_len;
576 }
577
578 req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
579
580 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
581 ret = -errno;
582 goto cleanup;
583 }
584
585 len = recv(sock, buf, sizeof(buf), 0);
586 if (len < 0) {
587 ret = -errno;
588 goto cleanup;
589 }
590
591 for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
592 nh = NLMSG_NEXT(nh, len)) {
593 if (nh->nlmsg_pid != sa.nl_pid) {
594 ret = -LIBBPF_ERRNO__WRNGPID;
595 goto cleanup;
596 }
597 if (nh->nlmsg_seq != seq) {
598 ret = -LIBBPF_ERRNO__INVSEQ;
599 goto cleanup;
600 }
601 switch (nh->nlmsg_type) {
602 case NLMSG_ERROR:
603 err = (struct nlmsgerr *)NLMSG_DATA(nh);
604 if (!err->error)
605 continue;
606 ret = err->error;
607 nla_dump_errormsg(nh);
608 goto cleanup;
609 case NLMSG_DONE:
610 break;
611 default:
612 break;
613 }
614 }
615
616 ret = 0;
617
618cleanup:
619 close(sock);
620 return ret;
621}
622
623int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, 494int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size,
624 bool do_log) 495 bool do_log)
625{ 496{
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index bdb94939fd60..4f8d43ae20d2 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1502,6 +1502,7 @@ static bool bpf_prog_type__needs_kver(enum bpf_prog_type type)
1502 case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 1502 case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
1503 case BPF_PROG_TYPE_LIRC_MODE2: 1503 case BPF_PROG_TYPE_LIRC_MODE2:
1504 case BPF_PROG_TYPE_SK_REUSEPORT: 1504 case BPF_PROG_TYPE_SK_REUSEPORT:
1505 case BPF_PROG_TYPE_FLOW_DISSECTOR:
1505 return false; 1506 return false;
1506 case BPF_PROG_TYPE_UNSPEC: 1507 case BPF_PROG_TYPE_UNSPEC:
1507 case BPF_PROG_TYPE_KPROBE: 1508 case BPF_PROG_TYPE_KPROBE:
@@ -2121,6 +2122,7 @@ static const struct {
2121 BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), 2122 BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB),
2122 BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), 2123 BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG),
2123 BPF_PROG_SEC("lirc_mode2", BPF_PROG_TYPE_LIRC_MODE2), 2124 BPF_PROG_SEC("lirc_mode2", BPF_PROG_TYPE_LIRC_MODE2),
2125 BPF_PROG_SEC("flow_dissector", BPF_PROG_TYPE_FLOW_DISSECTOR),
2124 BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), 2126 BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND),
2125 BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), 2127 BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND),
2126 BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT), 2128 BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT),
@@ -2336,7 +2338,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
2336 bpf_program__set_expected_attach_type(prog, 2338 bpf_program__set_expected_attach_type(prog,
2337 expected_attach_type); 2339 expected_attach_type);
2338 2340
2339 if (!bpf_program__is_function_storage(prog, obj) && !first_prog) 2341 if (!first_prog)
2340 first_prog = prog; 2342 first_prog = prog;
2341 } 2343 }
2342 2344
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 96c55fac54c3..e3b00e23e181 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -46,6 +46,7 @@ enum libbpf_errno {
46 LIBBPF_ERRNO__PROGTYPE, /* Kernel doesn't support this program type */ 46 LIBBPF_ERRNO__PROGTYPE, /* Kernel doesn't support this program type */
47 LIBBPF_ERRNO__WRNGPID, /* Wrong pid in netlink message */ 47 LIBBPF_ERRNO__WRNGPID, /* Wrong pid in netlink message */
48 LIBBPF_ERRNO__INVSEQ, /* Invalid netlink sequence */ 48 LIBBPF_ERRNO__INVSEQ, /* Invalid netlink sequence */
49 LIBBPF_ERRNO__NLPARSE, /* netlink parsing error */
49 __LIBBPF_ERRNO__END, 50 __LIBBPF_ERRNO__END,
50}; 51};
51 52
@@ -297,4 +298,19 @@ int bpf_perf_event_read_simple(void *mem, unsigned long size,
297 unsigned long page_size, 298 unsigned long page_size,
298 void **buf, size_t *buf_len, 299 void **buf, size_t *buf_len,
299 bpf_perf_event_print_t fn, void *priv); 300 bpf_perf_event_print_t fn, void *priv);
301
302struct nlmsghdr;
303struct nlattr;
304typedef int (*dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
305typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, dump_nlmsg_t,
306 void *cookie);
307int bpf_netlink_open(unsigned int *nl_pid);
308int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg,
309 void *cookie);
310int nl_get_class(int sock, unsigned int nl_pid, int ifindex,
311 dump_nlmsg_t dump_class_nlmsg, void *cookie);
312int nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
313 dump_nlmsg_t dump_qdisc_nlmsg, void *cookie);
314int nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
315 dump_nlmsg_t dump_filter_nlmsg, void *cookie);
300#endif 316#endif
diff --git a/tools/lib/bpf/libbpf_errno.c b/tools/lib/bpf/libbpf_errno.c
index d9ba851bd7f9..2464ade3b326 100644
--- a/tools/lib/bpf/libbpf_errno.c
+++ b/tools/lib/bpf/libbpf_errno.c
@@ -42,6 +42,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {
42 [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type", 42 [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type",
43 [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message", 43 [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message",
44 [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence", 44 [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence",
45 [ERRCODE_OFFSET(NLPARSE)] = "Incorrect netlink message parsing",
45}; 46};
46 47
47int libbpf_strerror(int err, char *buf, size_t size) 48int libbpf_strerror(int err, char *buf, size_t size)
diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c
new file mode 100644
index 000000000000..fde1d7bf8199
--- /dev/null
+++ b/tools/lib/bpf/netlink.c
@@ -0,0 +1,331 @@
1// SPDX-License-Identifier: LGPL-2.1
2/* Copyright (c) 2018 Facebook */
3
4#include <stdlib.h>
5#include <memory.h>
6#include <unistd.h>
7#include <linux/bpf.h>
8#include <linux/rtnetlink.h>
9#include <sys/socket.h>
10#include <errno.h>
11#include <time.h>
12
13#include "bpf.h"
14#include "libbpf.h"
15#include "nlattr.h"
16
17#ifndef SOL_NETLINK
18#define SOL_NETLINK 270
19#endif
20
21int bpf_netlink_open(__u32 *nl_pid)
22{
23 struct sockaddr_nl sa;
24 socklen_t addrlen;
25 int one = 1, ret;
26 int sock;
27
28 memset(&sa, 0, sizeof(sa));
29 sa.nl_family = AF_NETLINK;
30
31 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
32 if (sock < 0)
33 return -errno;
34
35 if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
36 &one, sizeof(one)) < 0) {
37 fprintf(stderr, "Netlink error reporting not supported\n");
38 }
39
40 if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
41 ret = -errno;
42 goto cleanup;
43 }
44
45 addrlen = sizeof(sa);
46 if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
47 ret = -errno;
48 goto cleanup;
49 }
50
51 if (addrlen != sizeof(sa)) {
52 ret = -LIBBPF_ERRNO__INTERNAL;
53 goto cleanup;
54 }
55
56 *nl_pid = sa.nl_pid;
57 return sock;
58
59cleanup:
60 close(sock);
61 return ret;
62}
63
64static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq,
65 __dump_nlmsg_t _fn, dump_nlmsg_t fn,
66 void *cookie)
67{
68 bool multipart = true;
69 struct nlmsgerr *err;
70 struct nlmsghdr *nh;
71 char buf[4096];
72 int len, ret;
73
74 while (multipart) {
75 multipart = false;
76 len = recv(sock, buf, sizeof(buf), 0);
77 if (len < 0) {
78 ret = -errno;
79 goto done;
80 }
81
82 if (len == 0)
83 break;
84
85 for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
86 nh = NLMSG_NEXT(nh, len)) {
87 if (nh->nlmsg_pid != nl_pid) {
88 ret = -LIBBPF_ERRNO__WRNGPID;
89 goto done;
90 }
91 if (nh->nlmsg_seq != seq) {
92 ret = -LIBBPF_ERRNO__INVSEQ;
93 goto done;
94 }
95 if (nh->nlmsg_flags & NLM_F_MULTI)
96 multipart = true;
97 switch (nh->nlmsg_type) {
98 case NLMSG_ERROR:
99 err = (struct nlmsgerr *)NLMSG_DATA(nh);
100 if (!err->error)
101 continue;
102 ret = err->error;
103 nla_dump_errormsg(nh);
104 goto done;
105 case NLMSG_DONE:
106 return 0;
107 default:
108 break;
109 }
110 if (_fn) {
111 ret = _fn(nh, fn, cookie);
112 if (ret)
113 return ret;
114 }
115 }
116 }
117 ret = 0;
118done:
119 return ret;
120}
121
122int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
123{
124 int sock, seq = 0, ret;
125 struct nlattr *nla, *nla_xdp;
126 struct {
127 struct nlmsghdr nh;
128 struct ifinfomsg ifinfo;
129 char attrbuf[64];
130 } req;
131 __u32 nl_pid;
132
133 sock = bpf_netlink_open(&nl_pid);
134 if (sock < 0)
135 return sock;
136
137 memset(&req, 0, sizeof(req));
138 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
139 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
140 req.nh.nlmsg_type = RTM_SETLINK;
141 req.nh.nlmsg_pid = 0;
142 req.nh.nlmsg_seq = ++seq;
143 req.ifinfo.ifi_family = AF_UNSPEC;
144 req.ifinfo.ifi_index = ifindex;
145
146 /* started nested attribute for XDP */
147 nla = (struct nlattr *)(((char *)&req)
148 + NLMSG_ALIGN(req.nh.nlmsg_len));
149 nla->nla_type = NLA_F_NESTED | IFLA_XDP;
150 nla->nla_len = NLA_HDRLEN;
151
152 /* add XDP fd */
153 nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
154 nla_xdp->nla_type = IFLA_XDP_FD;
155 nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
156 memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
157 nla->nla_len += nla_xdp->nla_len;
158
159 /* if user passed in any flags, add those too */
160 if (flags) {
161 nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
162 nla_xdp->nla_type = IFLA_XDP_FLAGS;
163 nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
164 memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
165 nla->nla_len += nla_xdp->nla_len;
166 }
167
168 req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
169
170 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
171 ret = -errno;
172 goto cleanup;
173 }
174 ret = bpf_netlink_recv(sock, nl_pid, seq, NULL, NULL, NULL);
175
176cleanup:
177 close(sock);
178 return ret;
179}
180
181static int __dump_link_nlmsg(struct nlmsghdr *nlh, dump_nlmsg_t dump_link_nlmsg,
182 void *cookie)
183{
184 struct nlattr *tb[IFLA_MAX + 1], *attr;
185 struct ifinfomsg *ifi = NLMSG_DATA(nlh);
186 int len;
187
188 len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
189 attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
190 if (nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
191 return -LIBBPF_ERRNO__NLPARSE;
192
193 return dump_link_nlmsg(cookie, ifi, tb);
194}
195
196int nl_get_link(int sock, unsigned int nl_pid, dump_nlmsg_t dump_link_nlmsg,
197 void *cookie)
198{
199 struct {
200 struct nlmsghdr nlh;
201 struct ifinfomsg ifm;
202 } req = {
203 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
204 .nlh.nlmsg_type = RTM_GETLINK,
205 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
206 .ifm.ifi_family = AF_PACKET,
207 };
208 int seq = time(NULL);
209
210 req.nlh.nlmsg_seq = seq;
211 if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
212 return -errno;
213
214 return bpf_netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg,
215 dump_link_nlmsg, cookie);
216}
217
218static int __dump_class_nlmsg(struct nlmsghdr *nlh,
219 dump_nlmsg_t dump_class_nlmsg, void *cookie)
220{
221 struct nlattr *tb[TCA_MAX + 1], *attr;
222 struct tcmsg *t = NLMSG_DATA(nlh);
223 int len;
224
225 len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
226 attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
227 if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
228 return -LIBBPF_ERRNO__NLPARSE;
229
230 return dump_class_nlmsg(cookie, t, tb);
231}
232
233int nl_get_class(int sock, unsigned int nl_pid, int ifindex,
234 dump_nlmsg_t dump_class_nlmsg, void *cookie)
235{
236 struct {
237 struct nlmsghdr nlh;
238 struct tcmsg t;
239 } req = {
240 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
241 .nlh.nlmsg_type = RTM_GETTCLASS,
242 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
243 .t.tcm_family = AF_UNSPEC,
244 .t.tcm_ifindex = ifindex,
245 };
246 int seq = time(NULL);
247
248 req.nlh.nlmsg_seq = seq;
249 if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
250 return -errno;
251
252 return bpf_netlink_recv(sock, nl_pid, seq, __dump_class_nlmsg,
253 dump_class_nlmsg, cookie);
254}
255
256static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh,
257 dump_nlmsg_t dump_qdisc_nlmsg, void *cookie)
258{
259 struct nlattr *tb[TCA_MAX + 1], *attr;
260 struct tcmsg *t = NLMSG_DATA(nlh);
261 int len;
262
263 len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
264 attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
265 if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
266 return -LIBBPF_ERRNO__NLPARSE;
267
268 return dump_qdisc_nlmsg(cookie, t, tb);
269}
270
271int nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
272 dump_nlmsg_t dump_qdisc_nlmsg, void *cookie)
273{
274 struct {
275 struct nlmsghdr nlh;
276 struct tcmsg t;
277 } req = {
278 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
279 .nlh.nlmsg_type = RTM_GETQDISC,
280 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
281 .t.tcm_family = AF_UNSPEC,
282 .t.tcm_ifindex = ifindex,
283 };
284 int seq = time(NULL);
285
286 req.nlh.nlmsg_seq = seq;
287 if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
288 return -errno;
289
290 return bpf_netlink_recv(sock, nl_pid, seq, __dump_qdisc_nlmsg,
291 dump_qdisc_nlmsg, cookie);
292}
293
294static int __dump_filter_nlmsg(struct nlmsghdr *nlh,
295 dump_nlmsg_t dump_filter_nlmsg, void *cookie)
296{
297 struct nlattr *tb[TCA_MAX + 1], *attr;
298 struct tcmsg *t = NLMSG_DATA(nlh);
299 int len;
300
301 len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
302 attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
303 if (nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
304 return -LIBBPF_ERRNO__NLPARSE;
305
306 return dump_filter_nlmsg(cookie, t, tb);
307}
308
309int nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
310 dump_nlmsg_t dump_filter_nlmsg, void *cookie)
311{
312 struct {
313 struct nlmsghdr nlh;
314 struct tcmsg t;
315 } req = {
316 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
317 .nlh.nlmsg_type = RTM_GETTFILTER,
318 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
319 .t.tcm_family = AF_UNSPEC,
320 .t.tcm_ifindex = ifindex,
321 .t.tcm_parent = handle,
322 };
323 int seq = time(NULL);
324
325 req.nlh.nlmsg_seq = seq;
326 if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
327 return -errno;
328
329 return bpf_netlink_recv(sock, nl_pid, seq, __dump_filter_nlmsg,
330 dump_filter_nlmsg, cookie);
331}
diff --git a/tools/lib/bpf/nlattr.c b/tools/lib/bpf/nlattr.c
index 4719434278b2..49f514119bdb 100644
--- a/tools/lib/bpf/nlattr.c
+++ b/tools/lib/bpf/nlattr.c
@@ -26,11 +26,6 @@ static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = {
26 [NLA_FLAG] = 0, 26 [NLA_FLAG] = 0,
27}; 27};
28 28
29static int nla_len(const struct nlattr *nla)
30{
31 return nla->nla_len - NLA_HDRLEN;
32}
33
34static struct nlattr *nla_next(const struct nlattr *nla, int *remaining) 29static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
35{ 30{
36 int totlen = NLA_ALIGN(nla->nla_len); 31 int totlen = NLA_ALIGN(nla->nla_len);
@@ -46,11 +41,6 @@ static int nla_ok(const struct nlattr *nla, int remaining)
46 nla->nla_len <= remaining; 41 nla->nla_len <= remaining;
47} 42}
48 43
49static void *nla_data(const struct nlattr *nla)
50{
51 return (char *) nla + NLA_HDRLEN;
52}
53
54static int nla_type(const struct nlattr *nla) 44static int nla_type(const struct nlattr *nla)
55{ 45{
56 return nla->nla_type & NLA_TYPE_MASK; 46 return nla->nla_type & NLA_TYPE_MASK;
@@ -114,8 +104,8 @@ static inline int nlmsg_len(const struct nlmsghdr *nlh)
114 * @see nla_validate 104 * @see nla_validate
115 * @return 0 on success or a negative error code. 105 * @return 0 on success or a negative error code.
116 */ 106 */
117static int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, 107int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
118 struct nla_policy *policy) 108 struct nla_policy *policy)
119{ 109{
120 struct nlattr *nla; 110 struct nlattr *nla;
121 int rem, err; 111 int rem, err;
@@ -146,6 +136,25 @@ errout:
146 return err; 136 return err;
147} 137}
148 138
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 */
152int 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
149/* dump netlink extended ack error message */ 158/* dump netlink extended ack error message */
150int nla_dump_errormsg(struct nlmsghdr *nlh) 159int nla_dump_errormsg(struct nlmsghdr *nlh)
151{ 160{
diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h
index 931a71f68f93..a6e2396bce7c 100644
--- a/tools/lib/bpf/nlattr.h
+++ b/tools/lib/bpf/nlattr.h
@@ -67,6 +67,44 @@ struct nla_policy {
67 nla_ok(pos, rem); \ 67 nla_ok(pos, rem); \
68 pos = nla_next(pos, &(rem))) 68 pos = nla_next(pos, &(rem)))
69 69
70/**
71 * nla_data - head of payload
72 * @nla: netlink attribute
73 */
74static inline void *nla_data(const struct nlattr *nla)
75{
76 return (char *) nla + NLA_HDRLEN;
77}
78
79static inline uint8_t nla_getattr_u8(const struct nlattr *nla)
80{
81 return *(uint8_t *)nla_data(nla);
82}
83
84static inline uint32_t nla_getattr_u32(const struct nlattr *nla)
85{
86 return *(uint32_t *)nla_data(nla);
87}
88
89static 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 */
98static inline int nla_len(const struct nlattr *nla)
99{
100 return nla->nla_len - NLA_HDRLEN;
101}
102
103int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
104 struct nla_policy *policy);
105int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
106 struct nla_policy *policy);
107
70int nla_dump_errormsg(struct nlmsghdr *nlh); 108int nla_dump_errormsg(struct nlmsghdr *nlh);
71 109
72#endif /* __NLATTR_H */ 110#endif /* __NLATTR_H */