diff options
author | Yonghong Song <yhs@fb.com> | 2018-09-05 19:58:04 -0400 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2018-09-07 01:34:08 -0400 |
commit | f7010770fbac47b1fc9fb723b1d2019eb23c04f2 (patch) | |
tree | 4c58b2106198e64b4712fc3d27a6dcc5ba5b87a7 /tools/lib/bpf | |
parent | 52b7b7843d9523ebc3c60c51c7afc4a45cc10aad (diff) |
tools/bpf: move bpf/lib netlink related functions into a new file
There are no functionality change for this patch.
In the subsequent patches, more netlink related library functions
will be added and a separate file is better than cluttering bpf.c.
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/lib/bpf')
-rw-r--r-- | tools/lib/bpf/Build | 2 | ||||
-rw-r--r-- | tools/lib/bpf/bpf.c | 129 | ||||
-rw-r--r-- | tools/lib/bpf/netlink.c | 165 |
3 files changed, 166 insertions, 130 deletions
diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build index 13a861135127..512b2c0ba0d2 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 | libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.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 | ||
502 | int 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 | |||
618 | cleanup: | ||
619 | close(sock); | ||
620 | return ret; | ||
621 | } | ||
622 | |||
623 | int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, | 494 | int 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/netlink.c b/tools/lib/bpf/netlink.c new file mode 100644 index 000000000000..ccaa991fe9d8 --- /dev/null +++ b/tools/lib/bpf/netlink.c | |||
@@ -0,0 +1,165 @@ | |||
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 | |||
21 | static int 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 | |||
59 | cleanup: | ||
60 | close(sock); | ||
61 | return ret; | ||
62 | } | ||
63 | |||
64 | static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq) | ||
65 | { | ||
66 | struct nlmsgerr *err; | ||
67 | struct nlmsghdr *nh; | ||
68 | char buf[4096]; | ||
69 | int len, ret; | ||
70 | |||
71 | while (1) { | ||
72 | len = recv(sock, buf, sizeof(buf), 0); | ||
73 | if (len < 0) { | ||
74 | ret = -errno; | ||
75 | goto done; | ||
76 | } | ||
77 | |||
78 | for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); | ||
79 | nh = NLMSG_NEXT(nh, len)) { | ||
80 | if (nh->nlmsg_pid != nl_pid) { | ||
81 | ret = -LIBBPF_ERRNO__WRNGPID; | ||
82 | goto done; | ||
83 | } | ||
84 | if (nh->nlmsg_seq != seq) { | ||
85 | ret = -LIBBPF_ERRNO__INVSEQ; | ||
86 | goto done; | ||
87 | } | ||
88 | switch (nh->nlmsg_type) { | ||
89 | case NLMSG_ERROR: | ||
90 | err = (struct nlmsgerr *)NLMSG_DATA(nh); | ||
91 | if (!err->error) | ||
92 | continue; | ||
93 | ret = err->error; | ||
94 | nla_dump_errormsg(nh); | ||
95 | goto done; | ||
96 | case NLMSG_DONE: | ||
97 | return 0; | ||
98 | default: | ||
99 | break; | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | ret = 0; | ||
104 | done: | ||
105 | return ret; | ||
106 | } | ||
107 | |||
108 | int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) | ||
109 | { | ||
110 | int sock, seq = 0, ret; | ||
111 | struct nlattr *nla, *nla_xdp; | ||
112 | struct { | ||
113 | struct nlmsghdr nh; | ||
114 | struct ifinfomsg ifinfo; | ||
115 | char attrbuf[64]; | ||
116 | } req; | ||
117 | __u32 nl_pid; | ||
118 | |||
119 | sock = bpf_netlink_open(&nl_pid); | ||
120 | if (sock < 0) | ||
121 | return sock; | ||
122 | |||
123 | memset(&req, 0, sizeof(req)); | ||
124 | req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | ||
125 | req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | ||
126 | req.nh.nlmsg_type = RTM_SETLINK; | ||
127 | req.nh.nlmsg_pid = 0; | ||
128 | req.nh.nlmsg_seq = ++seq; | ||
129 | req.ifinfo.ifi_family = AF_UNSPEC; | ||
130 | req.ifinfo.ifi_index = ifindex; | ||
131 | |||
132 | /* started nested attribute for XDP */ | ||
133 | nla = (struct nlattr *)(((char *)&req) | ||
134 | + NLMSG_ALIGN(req.nh.nlmsg_len)); | ||
135 | nla->nla_type = NLA_F_NESTED | IFLA_XDP; | ||
136 | nla->nla_len = NLA_HDRLEN; | ||
137 | |||
138 | /* add XDP fd */ | ||
139 | nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); | ||
140 | nla_xdp->nla_type = IFLA_XDP_FD; | ||
141 | nla_xdp->nla_len = NLA_HDRLEN + sizeof(int); | ||
142 | memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd)); | ||
143 | nla->nla_len += nla_xdp->nla_len; | ||
144 | |||
145 | /* if user passed in any flags, add those too */ | ||
146 | if (flags) { | ||
147 | nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); | ||
148 | nla_xdp->nla_type = IFLA_XDP_FLAGS; | ||
149 | nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags); | ||
150 | memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags)); | ||
151 | nla->nla_len += nla_xdp->nla_len; | ||
152 | } | ||
153 | |||
154 | req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len); | ||
155 | |||
156 | if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) { | ||
157 | ret = -errno; | ||
158 | goto cleanup; | ||
159 | } | ||
160 | ret = bpf_netlink_recv(sock, nl_pid, seq); | ||
161 | |||
162 | cleanup: | ||
163 | close(sock); | ||
164 | return ret; | ||
165 | } | ||