aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Ignatov <rdna@fb.com>2018-03-30 18:08:06 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-03-30 20:16:14 -0400
commit622adafb2a12cac6042d4d0d7eb735b7621bf28c (patch)
treee5bd9df3d2bc48b84e3733314965e76e1e12903b
parentd74bad4e74ee373787a9ae24197c17b7cdc428d5 (diff)
selftests/bpf: Selftest for sys_connect hooks
Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT attach types. Try to connect(2) to specified IP:port and test that: * remote IP:port pair is overridden; * local end of connection is bound to specified IP. All combinations of IPv4/IPv6 and TCP/UDP are tested. Example: # tcpdump -pn -i lo -w connect.pcap 2>/dev/null & [1] 478 # strace -qqf -e connect -o connect.trace ./test_sock_addr.sh Wait for testing IPv4/IPv6 to become available ... OK Load bind4 with invalid type (can pollute stderr) ... REJECTED Load bind4 with valid type ... OK Attach bind4 with invalid type ... REJECTED Attach bind4 with valid type ... OK Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \ program failed: Permission denied libbpf: -- BEGIN DUMP LOG --- libbpf: 0: (b7) r2 = 23569 1: (63) *(u32 *)(r1 +24) = r2 2: (b7) r2 = 16777343 3: (63) *(u32 *)(r1 +4) = r2 invalid bpf_context access off=4 size=4 [ 1518.404609] random: crng init done libbpf: -- END LOG -- libbpf: failed to load program 'cgroup/connect4' libbpf: failed to load object './connect4_prog.o' ... REJECTED Load connect4 with valid type ... OK Attach connect4 with invalid type ... REJECTED Attach connect4 with valid type ... OK Test case #1 (IPv4/TCP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Requested: connect(192.168.1.254, 4040) from (*, *) .. Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068) Test case #2 (IPv4/UDP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Requested: connect(192.168.1.254, 4040) from (*, *) .. Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447) Load bind6 with invalid type (can pollute stderr) ... REJECTED Load bind6 with valid type ... OK Attach bind6 with invalid type ... REJECTED Attach bind6 with valid type ... OK Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \ program failed: Permission denied libbpf: -- BEGIN DUMP LOG --- libbpf: 0: (b7) r6 = 0 1: (63) *(u32 *)(r1 +12) = r6 invalid bpf_context access off=12 size=4 libbpf: -- END LOG -- libbpf: failed to load program 'cgroup/connect6' libbpf: failed to load object './connect6_prog.o' ... REJECTED Load connect6 with valid type ... OK Attach connect6 with invalid type ... REJECTED Attach connect6 with valid type ... OK Test case #3 (IPv6/TCP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *) Actual: connect(::1, 6666) from (::6, 37458) Test case #4 (IPv6/UDP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *) Actual: connect(::1, 6666) from (::6, 39315) ### SUCCESS # egrep 'connect\(.*AF_INET' connect.trace | \ > egrep -vw 'htons\(1025\)' | fold -b -s -w 72 502 connect(7, {sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, 128) = 0 502 connect(8, {sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, 128) = 0 502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0 502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0 # fg tcpdump -pn -i lo -w connect.pcap 2> /dev/null # tcpdump -r connect.pcap -n tcp | cut -c 1-72 reading from file connect.pcap, link-type EN10MB (Ethernet) 17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333 17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112 17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w 17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1, 17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win 17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac 17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt 17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win Signed-off-by: Andrey Ignatov <rdna@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r--tools/include/uapi/linux/bpf.h12
-rw-r--r--tools/lib/bpf/libbpf.c2
-rw-r--r--tools/testing/selftests/bpf/Makefile5
-rw-r--r--tools/testing/selftests/bpf/bpf_helpers.h2
-rw-r--r--tools/testing/selftests/bpf/connect4_prog.c45
-rw-r--r--tools/testing/selftests/bpf/connect6_prog.c61
-rw-r--r--tools/testing/selftests/bpf/test_sock_addr.c104
-rwxr-xr-xtools/testing/selftests/bpf/test_sock_addr.sh57
8 files changed, 284 insertions, 4 deletions
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index f2120c5c0578..71051d01e8dd 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -150,6 +150,8 @@ enum bpf_attach_type {
150 BPF_SK_MSG_VERDICT, 150 BPF_SK_MSG_VERDICT,
151 BPF_CGROUP_INET4_BIND, 151 BPF_CGROUP_INET4_BIND,
152 BPF_CGROUP_INET6_BIND, 152 BPF_CGROUP_INET6_BIND,
153 BPF_CGROUP_INET4_CONNECT,
154 BPF_CGROUP_INET6_CONNECT,
153 __MAX_BPF_ATTACH_TYPE 155 __MAX_BPF_ATTACH_TYPE
154}; 156};
155 157
@@ -744,6 +746,13 @@ union bpf_attr {
744 * @flags: reserved for future use 746 * @flags: reserved for future use
745 * Return: SK_PASS 747 * Return: SK_PASS
746 * 748 *
749 * int bpf_bind(ctx, addr, addr_len)
750 * Bind socket to address. Only binding to IP is supported, no port can be
751 * set in addr.
752 * @ctx: pointer to context of type bpf_sock_addr
753 * @addr: pointer to struct sockaddr to bind socket to
754 * @addr_len: length of sockaddr structure
755 * Return: 0 on success or negative error code
747 */ 756 */
748#define __BPF_FUNC_MAPPER(FN) \ 757#define __BPF_FUNC_MAPPER(FN) \
749 FN(unspec), \ 758 FN(unspec), \
@@ -809,7 +818,8 @@ union bpf_attr {
809 FN(msg_redirect_map), \ 818 FN(msg_redirect_map), \
810 FN(msg_apply_bytes), \ 819 FN(msg_apply_bytes), \
811 FN(msg_cork_bytes), \ 820 FN(msg_cork_bytes), \
812 FN(msg_pull_data), 821 FN(msg_pull_data), \
822 FN(bind),
813 823
814/* integer value in 'imm' field of BPF_CALL instruction selects which helper 824/* integer value in 'imm' field of BPF_CALL instruction selects which helper
815 * function eBPF program intends to call 825 * function eBPF program intends to call
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index d7ce8818982c..5922443063f0 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1887,6 +1887,8 @@ static const struct {
1887 BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), 1887 BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG),
1888 BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), 1888 BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND),
1889 BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), 1889 BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND),
1890 BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT),
1891 BPF_SA_PROG_SEC("cgroup/connect6", BPF_CGROUP_INET6_CONNECT),
1890}; 1892};
1891 1893
1892#undef BPF_PROG_SEC 1894#undef BPF_PROG_SEC
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index f4717c910874..c64d4ebc77ff 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -30,14 +30,15 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test
30 sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \ 30 sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \
31 test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \ 31 test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \
32 sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o \ 32 sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o \
33 sockmap_tcp_msg_prog.o 33 sockmap_tcp_msg_prog.o connect4_prog.o connect6_prog.o
34 34
35# Order correspond to 'make run_tests' order 35# Order correspond to 'make run_tests' order
36TEST_PROGS := test_kmod.sh \ 36TEST_PROGS := test_kmod.sh \
37 test_libbpf.sh \ 37 test_libbpf.sh \
38 test_xdp_redirect.sh \ 38 test_xdp_redirect.sh \
39 test_xdp_meta.sh \ 39 test_xdp_meta.sh \
40 test_offload.py 40 test_offload.py \
41 test_sock_addr.sh
41 42
42# Compile but not part of 'make run_tests' 43# Compile but not part of 'make run_tests'
43TEST_GEN_PROGS_EXTENDED = test_libbpf_open 44TEST_GEN_PROGS_EXTENDED = test_libbpf_open
diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h
index 7cae376d8d0c..d8223d99f96d 100644
--- a/tools/testing/selftests/bpf/bpf_helpers.h
+++ b/tools/testing/selftests/bpf/bpf_helpers.h
@@ -94,6 +94,8 @@ static int (*bpf_msg_cork_bytes)(void *ctx, int len) =
94 (void *) BPF_FUNC_msg_cork_bytes; 94 (void *) BPF_FUNC_msg_cork_bytes;
95static int (*bpf_msg_pull_data)(void *ctx, int start, int end, int flags) = 95static int (*bpf_msg_pull_data)(void *ctx, int start, int end, int flags) =
96 (void *) BPF_FUNC_msg_pull_data; 96 (void *) BPF_FUNC_msg_pull_data;
97static int (*bpf_bind)(void *ctx, void *addr, int addr_len) =
98 (void *) BPF_FUNC_bind;
97 99
98/* llvm builtin functions that eBPF C program may use to 100/* llvm builtin functions that eBPF C program may use to
99 * emit BPF_LD_ABS and BPF_LD_IND instructions 101 * emit BPF_LD_ABS and BPF_LD_IND instructions
diff --git a/tools/testing/selftests/bpf/connect4_prog.c b/tools/testing/selftests/bpf/connect4_prog.c
new file mode 100644
index 000000000000..5a88a681d2ab
--- /dev/null
+++ b/tools/testing/selftests/bpf/connect4_prog.c
@@ -0,0 +1,45 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2018 Facebook
3
4#include <string.h>
5
6#include <linux/stddef.h>
7#include <linux/bpf.h>
8#include <linux/in.h>
9#include <linux/in6.h>
10#include <sys/socket.h>
11
12#include "bpf_helpers.h"
13#include "bpf_endian.h"
14
15#define SRC_REWRITE_IP4 0x7f000004U
16#define DST_REWRITE_IP4 0x7f000001U
17#define DST_REWRITE_PORT4 4444
18
19int _version SEC("version") = 1;
20
21SEC("cgroup/connect4")
22int connect_v4_prog(struct bpf_sock_addr *ctx)
23{
24 struct sockaddr_in sa;
25
26 /* Rewrite destination. */
27 ctx->user_ip4 = bpf_htonl(DST_REWRITE_IP4);
28 ctx->user_port = bpf_htons(DST_REWRITE_PORT4);
29
30 if (ctx->type == SOCK_DGRAM || ctx->type == SOCK_STREAM) {
31 ///* Rewrite source. */
32 memset(&sa, 0, sizeof(sa));
33
34 sa.sin_family = AF_INET;
35 sa.sin_port = bpf_htons(0);
36 sa.sin_addr.s_addr = bpf_htonl(SRC_REWRITE_IP4);
37
38 if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0)
39 return 0;
40 }
41
42 return 1;
43}
44
45char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/connect6_prog.c b/tools/testing/selftests/bpf/connect6_prog.c
new file mode 100644
index 000000000000..8ea3f7d12dee
--- /dev/null
+++ b/tools/testing/selftests/bpf/connect6_prog.c
@@ -0,0 +1,61 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2018 Facebook
3
4#include <string.h>
5
6#include <linux/stddef.h>
7#include <linux/bpf.h>
8#include <linux/in.h>
9#include <linux/in6.h>
10#include <sys/socket.h>
11
12#include "bpf_helpers.h"
13#include "bpf_endian.h"
14
15#define SRC_REWRITE_IP6_0 0
16#define SRC_REWRITE_IP6_1 0
17#define SRC_REWRITE_IP6_2 0
18#define SRC_REWRITE_IP6_3 6
19
20#define DST_REWRITE_IP6_0 0
21#define DST_REWRITE_IP6_1 0
22#define DST_REWRITE_IP6_2 0
23#define DST_REWRITE_IP6_3 1
24
25#define DST_REWRITE_PORT6 6666
26
27int _version SEC("version") = 1;
28
29SEC("cgroup/connect6")
30int connect_v6_prog(struct bpf_sock_addr *ctx)
31{
32 struct sockaddr_in6 sa;
33
34 /* Rewrite destination. */
35 ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0);
36 ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1);
37 ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2);
38 ctx->user_ip6[3] = bpf_htonl(DST_REWRITE_IP6_3);
39
40 ctx->user_port = bpf_htons(DST_REWRITE_PORT6);
41
42 if (ctx->type == SOCK_DGRAM || ctx->type == SOCK_STREAM) {
43 /* Rewrite source. */
44 memset(&sa, 0, sizeof(sa));
45
46 sa.sin6_family = AF_INET6;
47 sa.sin6_port = bpf_htons(0);
48
49 sa.sin6_addr.s6_addr32[0] = bpf_htonl(SRC_REWRITE_IP6_0);
50 sa.sin6_addr.s6_addr32[1] = bpf_htonl(SRC_REWRITE_IP6_1);
51 sa.sin6_addr.s6_addr32[2] = bpf_htonl(SRC_REWRITE_IP6_2);
52 sa.sin6_addr.s6_addr32[3] = bpf_htonl(SRC_REWRITE_IP6_3);
53
54 if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0)
55 return 0;
56 }
57
58 return 1;
59}
60
61char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c
index a57e13a65e37..d488f20926e8 100644
--- a/tools/testing/selftests/bpf/test_sock_addr.c
+++ b/tools/testing/selftests/bpf/test_sock_addr.c
@@ -12,10 +12,13 @@
12#include <linux/filter.h> 12#include <linux/filter.h>
13 13
14#include <bpf/bpf.h> 14#include <bpf/bpf.h>
15#include <bpf/libbpf.h>
15 16
16#include "cgroup_helpers.h" 17#include "cgroup_helpers.h"
17 18
18#define CG_PATH "/foo" 19#define CG_PATH "/foo"
20#define CONNECT4_PROG_PATH "./connect4_prog.o"
21#define CONNECT6_PROG_PATH "./connect6_prog.o"
19 22
20#define SERV4_IP "192.168.1.254" 23#define SERV4_IP "192.168.1.254"
21#define SERV4_REWRITE_IP "127.0.0.1" 24#define SERV4_REWRITE_IP "127.0.0.1"
@@ -254,6 +257,41 @@ static int bind6_prog_load(enum bpf_attach_type attach_type,
254 sizeof(insns) / sizeof(struct bpf_insn), comment); 257 sizeof(insns) / sizeof(struct bpf_insn), comment);
255} 258}
256 259
260static int connect_prog_load_path(const char *path,
261 enum bpf_attach_type attach_type,
262 const char *comment)
263{
264 struct bpf_prog_load_attr attr;
265 struct bpf_object *obj;
266 int prog_fd;
267
268 memset(&attr, 0, sizeof(struct bpf_prog_load_attr));
269 attr.file = path;
270 attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
271 attr.expected_attach_type = attach_type;
272
273 if (bpf_prog_load_xattr(&attr, &obj, &prog_fd)) {
274 if (comment)
275 log_err(">>> Loading %s program at %s error.\n",
276 comment, path);
277 return -1;
278 }
279
280 return prog_fd;
281}
282
283static int connect4_prog_load(enum bpf_attach_type attach_type,
284 const char *comment)
285{
286 return connect_prog_load_path(CONNECT4_PROG_PATH, attach_type, comment);
287}
288
289static int connect6_prog_load(enum bpf_attach_type attach_type,
290 const char *comment)
291{
292 return connect_prog_load_path(CONNECT6_PROG_PATH, attach_type, comment);
293}
294
257static void print_ip_port(int sockfd, info_fn fn, const char *fmt) 295static void print_ip_port(int sockfd, info_fn fn, const char *fmt)
258{ 296{
259 char addr_buf[INET_NTOP_BUF]; 297 char addr_buf[INET_NTOP_BUF];
@@ -290,6 +328,11 @@ static void print_local_ip_port(int sockfd, const char *fmt)
290 print_ip_port(sockfd, getsockname, fmt); 328 print_ip_port(sockfd, getsockname, fmt);
291} 329}
292 330
331static void print_remote_ip_port(int sockfd, const char *fmt)
332{
333 print_ip_port(sockfd, getpeername, fmt);
334}
335
293static int start_server(int type, const struct sockaddr_storage *addr, 336static int start_server(int type, const struct sockaddr_storage *addr,
294 socklen_t addr_len) 337 socklen_t addr_len)
295{ 338{
@@ -324,6 +367,39 @@ out:
324 return fd; 367 return fd;
325} 368}
326 369
370static int connect_to_server(int type, const struct sockaddr_storage *addr,
371 socklen_t addr_len)
372{
373 int domain;
374 int fd;
375
376 domain = addr->ss_family;
377
378 if (domain != AF_INET && domain != AF_INET6) {
379 log_err("Unsupported address family");
380 return -1;
381 }
382
383 fd = socket(domain, type, 0);
384 if (fd == -1) {
385 log_err("Failed to creating client socket");
386 return -1;
387 }
388
389 if (connect(fd, (const struct sockaddr *)addr, addr_len) == -1) {
390 log_err("Fail to connect to server");
391 goto err;
392 }
393
394 print_remote_ip_port(fd, "\t Actual: connect(%s, %d)");
395 print_local_ip_port(fd, " from (%s, %d)\n");
396
397 return 0;
398err:
399 close(fd);
400 return -1;
401}
402
327static void print_test_case_num(int domain, int type) 403static void print_test_case_num(int domain, int type)
328{ 404{
329 static int test_num; 405 static int test_num;
@@ -356,6 +432,10 @@ static int run_test_case(int domain, int type, const char *ip,
356 if (servfd == -1) 432 if (servfd == -1)
357 goto err; 433 goto err;
358 434
435 printf("\tRequested: connect(%s, %d) from (*, *) ..\n", ip, port);
436 if (connect_to_server(type, &addr, addr_len))
437 goto err;
438
359 goto out; 439 goto out;
360err: 440err:
361 err = -1; 441 err = -1;
@@ -380,29 +460,41 @@ static int load_and_attach_progs(int cgfd, struct program *progs,
380 size_t i; 460 size_t i;
381 461
382 for (i = 0; i < prog_cnt; ++i) { 462 for (i = 0; i < prog_cnt; ++i) {
463 printf("Load %s with invalid type (can pollute stderr) ",
464 progs[i].name);
465 fflush(stdout);
383 progs[i].fd = progs[i].loadfn(progs[i].invalid_type, NULL); 466 progs[i].fd = progs[i].loadfn(progs[i].invalid_type, NULL);
384 if (progs[i].fd != -1) { 467 if (progs[i].fd != -1) {
385 log_err("Load with invalid type accepted for %s", 468 log_err("Load with invalid type accepted for %s",
386 progs[i].name); 469 progs[i].name);
387 goto err; 470 goto err;
388 } 471 }
472 printf("... REJECTED\n");
473
474 printf("Load %s with valid type", progs[i].name);
389 progs[i].fd = progs[i].loadfn(progs[i].type, progs[i].name); 475 progs[i].fd = progs[i].loadfn(progs[i].type, progs[i].name);
390 if (progs[i].fd == -1) { 476 if (progs[i].fd == -1) {
391 log_err("Failed to load program %s", progs[i].name); 477 log_err("Failed to load program %s", progs[i].name);
392 goto err; 478 goto err;
393 } 479 }
480 printf(" ... OK\n");
481
482 printf("Attach %s with invalid type", progs[i].name);
394 if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].invalid_type, 483 if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].invalid_type,
395 BPF_F_ALLOW_OVERRIDE) != -1) { 484 BPF_F_ALLOW_OVERRIDE) != -1) {
396 log_err("Attach with invalid type accepted for %s", 485 log_err("Attach with invalid type accepted for %s",
397 progs[i].name); 486 progs[i].name);
398 goto err; 487 goto err;
399 } 488 }
489 printf(" ... REJECTED\n");
490
491 printf("Attach %s with valid type", progs[i].name);
400 if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].type, 492 if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].type,
401 BPF_F_ALLOW_OVERRIDE) == -1) { 493 BPF_F_ALLOW_OVERRIDE) == -1) {
402 log_err("Failed to attach program %s", progs[i].name); 494 log_err("Failed to attach program %s", progs[i].name);
403 goto err; 495 goto err;
404 } 496 }
405 printf("Attached %s program.\n", progs[i].name); 497 printf(" ... OK\n");
406 } 498 }
407 499
408 return 0; 500 return 0;
@@ -443,12 +535,16 @@ static int run_test(void)
443 struct program inet6_progs[] = { 535 struct program inet6_progs[] = {
444 {BPF_CGROUP_INET6_BIND, bind6_prog_load, -1, "bind6", 536 {BPF_CGROUP_INET6_BIND, bind6_prog_load, -1, "bind6",
445 BPF_CGROUP_INET4_BIND}, 537 BPF_CGROUP_INET4_BIND},
538 {BPF_CGROUP_INET6_CONNECT, connect6_prog_load, -1, "connect6",
539 BPF_CGROUP_INET4_CONNECT},
446 }; 540 };
447 inet6_prog_cnt = sizeof(inet6_progs) / sizeof(struct program); 541 inet6_prog_cnt = sizeof(inet6_progs) / sizeof(struct program);
448 542
449 struct program inet_progs[] = { 543 struct program inet_progs[] = {
450 {BPF_CGROUP_INET4_BIND, bind4_prog_load, -1, "bind4", 544 {BPF_CGROUP_INET4_BIND, bind4_prog_load, -1, "bind4",
451 BPF_CGROUP_INET6_BIND}, 545 BPF_CGROUP_INET6_BIND},
546 {BPF_CGROUP_INET4_CONNECT, connect4_prog_load, -1, "connect4",
547 BPF_CGROUP_INET6_CONNECT},
452 }; 548 };
453 inet_prog_cnt = sizeof(inet_progs) / sizeof(struct program); 549 inet_prog_cnt = sizeof(inet_progs) / sizeof(struct program);
454 550
@@ -482,5 +578,11 @@ out:
482 578
483int main(int argc, char **argv) 579int main(int argc, char **argv)
484{ 580{
581 if (argc < 2) {
582 fprintf(stderr,
583 "%s has to be run via %s.sh. Skip direct run.\n",
584 argv[0], argv[0]);
585 exit(0);
586 }
485 return run_test(); 587 return run_test();
486} 588}
diff --git a/tools/testing/selftests/bpf/test_sock_addr.sh b/tools/testing/selftests/bpf/test_sock_addr.sh
new file mode 100755
index 000000000000..c6e1dcf992c4
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_sock_addr.sh
@@ -0,0 +1,57 @@
1#!/bin/sh
2
3set -eu
4
5ping_once()
6{
7 ping -q -c 1 -W 1 ${1%%/*} >/dev/null 2>&1
8}
9
10wait_for_ip()
11{
12 local _i
13 echo -n "Wait for testing IPv4/IPv6 to become available "
14 for _i in $(seq ${MAX_PING_TRIES}); do
15 echo -n "."
16 if ping_once ${TEST_IPv4} && ping_once ${TEST_IPv6}; then
17 echo " OK"
18 return
19 fi
20 done
21 echo 1>&2 "ERROR: Timeout waiting for test IP to become available."
22 exit 1
23}
24
25setup()
26{
27 # Create testing interfaces not to interfere with current environment.
28 ip link add dev ${TEST_IF} type veth peer name ${TEST_IF_PEER}
29 ip link set ${TEST_IF} up
30 ip link set ${TEST_IF_PEER} up
31
32 ip -4 addr add ${TEST_IPv4} dev ${TEST_IF}
33 ip -6 addr add ${TEST_IPv6} dev ${TEST_IF}
34 wait_for_ip
35}
36
37cleanup()
38{
39 ip link del ${TEST_IF} 2>/dev/null || :
40 ip link del ${TEST_IF_PEER} 2>/dev/null || :
41}
42
43main()
44{
45 trap cleanup EXIT 2 3 6 15
46 setup
47 ./test_sock_addr setup_done
48}
49
50BASENAME=$(basename $0 .sh)
51TEST_IF="${BASENAME}1"
52TEST_IF_PEER="${BASENAME}2"
53TEST_IPv4="127.0.0.4/8"
54TEST_IPv6="::6/128"
55MAX_PING_TRIES=5
56
57main