diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/include/uapi/linux/bpf.h | 86 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/Makefile | 4 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/bpf_helpers.h | 2 | ||||
-rwxr-xr-x | tools/testing/selftests/bpf/tcp_client.py | 51 | ||||
-rwxr-xr-x | tools/testing/selftests/bpf/tcp_server.py | 83 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/test_tcpbpf.h | 16 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/test_tcpbpf_kern.c | 118 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/test_tcpbpf_user.c | 126 |
8 files changed, 480 insertions, 6 deletions
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index af1f49ad8b88..db6bdc375126 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h | |||
@@ -17,7 +17,7 @@ | |||
17 | #define BPF_ALU64 0x07 /* alu mode in double word width */ | 17 | #define BPF_ALU64 0x07 /* alu mode in double word width */ |
18 | 18 | ||
19 | /* ld/ldx fields */ | 19 | /* ld/ldx fields */ |
20 | #define BPF_DW 0x18 /* double word */ | 20 | #define BPF_DW 0x18 /* double word (64-bit) */ |
21 | #define BPF_XADD 0xc0 /* exclusive add */ | 21 | #define BPF_XADD 0xc0 /* exclusive add */ |
22 | 22 | ||
23 | /* alu/jmp fields */ | 23 | /* alu/jmp fields */ |
@@ -642,6 +642,14 @@ union bpf_attr { | |||
642 | * @optlen: length of optval in bytes | 642 | * @optlen: length of optval in bytes |
643 | * Return: 0 or negative error | 643 | * Return: 0 or negative error |
644 | * | 644 | * |
645 | * int bpf_sock_ops_cb_flags_set(bpf_sock_ops, flags) | ||
646 | * Set callback flags for sock_ops | ||
647 | * @bpf_sock_ops: pointer to bpf_sock_ops_kern struct | ||
648 | * @flags: flags value | ||
649 | * Return: 0 for no error | ||
650 | * -EINVAL if there is no full tcp socket | ||
651 | * bits in flags that are not supported by current kernel | ||
652 | * | ||
645 | * int bpf_skb_adjust_room(skb, len_diff, mode, flags) | 653 | * int bpf_skb_adjust_room(skb, len_diff, mode, flags) |
646 | * Grow or shrink room in sk_buff. | 654 | * Grow or shrink room in sk_buff. |
647 | * @skb: pointer to skb | 655 | * @skb: pointer to skb |
@@ -748,7 +756,8 @@ union bpf_attr { | |||
748 | FN(perf_event_read_value), \ | 756 | FN(perf_event_read_value), \ |
749 | FN(perf_prog_read_value), \ | 757 | FN(perf_prog_read_value), \ |
750 | FN(getsockopt), \ | 758 | FN(getsockopt), \ |
751 | FN(override_return), | 759 | FN(override_return), \ |
760 | FN(sock_ops_cb_flags_set), | ||
752 | 761 | ||
753 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper | 762 | /* integer value in 'imm' field of BPF_CALL instruction selects which helper |
754 | * function eBPF program intends to call | 763 | * function eBPF program intends to call |
@@ -952,8 +961,9 @@ struct bpf_map_info { | |||
952 | struct bpf_sock_ops { | 961 | struct bpf_sock_ops { |
953 | __u32 op; | 962 | __u32 op; |
954 | union { | 963 | union { |
955 | __u32 reply; | 964 | __u32 args[4]; /* Optionally passed to bpf program */ |
956 | __u32 replylong[4]; | 965 | __u32 reply; /* Returned by bpf program */ |
966 | __u32 replylong[4]; /* Optionally returned by bpf prog */ | ||
957 | }; | 967 | }; |
958 | __u32 family; | 968 | __u32 family; |
959 | __u32 remote_ip4; /* Stored in network byte order */ | 969 | __u32 remote_ip4; /* Stored in network byte order */ |
@@ -968,8 +978,39 @@ struct bpf_sock_ops { | |||
968 | */ | 978 | */ |
969 | __u32 snd_cwnd; | 979 | __u32 snd_cwnd; |
970 | __u32 srtt_us; /* Averaged RTT << 3 in usecs */ | 980 | __u32 srtt_us; /* Averaged RTT << 3 in usecs */ |
981 | __u32 bpf_sock_ops_cb_flags; /* flags defined in uapi/linux/tcp.h */ | ||
982 | __u32 state; | ||
983 | __u32 rtt_min; | ||
984 | __u32 snd_ssthresh; | ||
985 | __u32 rcv_nxt; | ||
986 | __u32 snd_nxt; | ||
987 | __u32 snd_una; | ||
988 | __u32 mss_cache; | ||
989 | __u32 ecn_flags; | ||
990 | __u32 rate_delivered; | ||
991 | __u32 rate_interval_us; | ||
992 | __u32 packets_out; | ||
993 | __u32 retrans_out; | ||
994 | __u32 total_retrans; | ||
995 | __u32 segs_in; | ||
996 | __u32 data_segs_in; | ||
997 | __u32 segs_out; | ||
998 | __u32 data_segs_out; | ||
999 | __u32 lost_out; | ||
1000 | __u32 sacked_out; | ||
1001 | __u32 sk_txhash; | ||
1002 | __u64 bytes_received; | ||
1003 | __u64 bytes_acked; | ||
971 | }; | 1004 | }; |
972 | 1005 | ||
1006 | /* Definitions for bpf_sock_ops_cb_flags */ | ||
1007 | #define BPF_SOCK_OPS_RTO_CB_FLAG (1<<0) | ||
1008 | #define BPF_SOCK_OPS_RETRANS_CB_FLAG (1<<1) | ||
1009 | #define BPF_SOCK_OPS_STATE_CB_FLAG (1<<2) | ||
1010 | #define BPF_SOCK_OPS_ALL_CB_FLAGS 0x7 /* Mask of all currently | ||
1011 | * supported cb flags | ||
1012 | */ | ||
1013 | |||
973 | /* List of known BPF sock_ops operators. | 1014 | /* List of known BPF sock_ops operators. |
974 | * New entries can only be added at the end | 1015 | * New entries can only be added at the end |
975 | */ | 1016 | */ |
@@ -1003,6 +1044,43 @@ enum { | |||
1003 | * a congestion threshold. RTTs above | 1044 | * a congestion threshold. RTTs above |
1004 | * this indicate congestion | 1045 | * this indicate congestion |
1005 | */ | 1046 | */ |
1047 | BPF_SOCK_OPS_RTO_CB, /* Called when an RTO has triggered. | ||
1048 | * Arg1: value of icsk_retransmits | ||
1049 | * Arg2: value of icsk_rto | ||
1050 | * Arg3: whether RTO has expired | ||
1051 | */ | ||
1052 | BPF_SOCK_OPS_RETRANS_CB, /* Called when skb is retransmitted. | ||
1053 | * Arg1: sequence number of 1st byte | ||
1054 | * Arg2: # segments | ||
1055 | * Arg3: return value of | ||
1056 | * tcp_transmit_skb (0 => success) | ||
1057 | */ | ||
1058 | BPF_SOCK_OPS_STATE_CB, /* Called when TCP changes state. | ||
1059 | * Arg1: old_state | ||
1060 | * Arg2: new_state | ||
1061 | */ | ||
1062 | }; | ||
1063 | |||
1064 | /* List of TCP states. There is a build check in net/ipv4/tcp.c to detect | ||
1065 | * changes between the TCP and BPF versions. Ideally this should never happen. | ||
1066 | * If it does, we need to add code to convert them before calling | ||
1067 | * the BPF sock_ops function. | ||
1068 | */ | ||
1069 | enum { | ||
1070 | BPF_TCP_ESTABLISHED = 1, | ||
1071 | BPF_TCP_SYN_SENT, | ||
1072 | BPF_TCP_SYN_RECV, | ||
1073 | BPF_TCP_FIN_WAIT1, | ||
1074 | BPF_TCP_FIN_WAIT2, | ||
1075 | BPF_TCP_TIME_WAIT, | ||
1076 | BPF_TCP_CLOSE, | ||
1077 | BPF_TCP_CLOSE_WAIT, | ||
1078 | BPF_TCP_LAST_ACK, | ||
1079 | BPF_TCP_LISTEN, | ||
1080 | BPF_TCP_CLOSING, /* Now a valid state */ | ||
1081 | BPF_TCP_NEW_SYN_RECV, | ||
1082 | |||
1083 | BPF_TCP_MAX_STATES /* Leave at the end! */ | ||
1006 | }; | 1084 | }; |
1007 | 1085 | ||
1008 | #define TCP_BPF_IW 1001 /* Set TCP initial congestion window */ | 1086 | #define TCP_BPF_IW 1001 /* Set TCP initial congestion window */ |
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 3a44b655d852..98688352208b 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile | |||
@@ -14,13 +14,13 @@ CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../i | |||
14 | LDLIBS += -lcap -lelf -lrt | 14 | LDLIBS += -lcap -lelf -lrt |
15 | 15 | ||
16 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ | 16 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ |
17 | test_align test_verifier_log test_dev_cgroup | 17 | test_align test_verifier_log test_dev_cgroup test_tcpbpf_user |
18 | 18 | ||
19 | TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ | 19 | TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ |
20 | test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ | 20 | test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ |
21 | sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \ | 21 | sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \ |
22 | test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \ | 22 | test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \ |
23 | sample_map_ret0.o | 23 | sample_map_ret0.o test_tcpbpf_kern.o |
24 | 24 | ||
25 | TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh \ | 25 | TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh \ |
26 | test_offload.py | 26 | test_offload.py |
diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 33cb00e46c49..dde2c11d7771 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h | |||
@@ -71,6 +71,8 @@ static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, | |||
71 | static int (*bpf_getsockopt)(void *ctx, int level, int optname, void *optval, | 71 | static int (*bpf_getsockopt)(void *ctx, int level, int optname, void *optval, |
72 | int optlen) = | 72 | int optlen) = |
73 | (void *) BPF_FUNC_getsockopt; | 73 | (void *) BPF_FUNC_getsockopt; |
74 | static int (*bpf_sock_ops_cb_flags_set)(void *ctx, int flags) = | ||
75 | (void *) BPF_FUNC_sock_ops_cb_flags_set; | ||
74 | static int (*bpf_sk_redirect_map)(void *ctx, void *map, int key, int flags) = | 76 | static int (*bpf_sk_redirect_map)(void *ctx, void *map, int key, int flags) = |
75 | (void *) BPF_FUNC_sk_redirect_map; | 77 | (void *) BPF_FUNC_sk_redirect_map; |
76 | static int (*bpf_sock_map_update)(void *map, void *key, void *value, | 78 | static int (*bpf_sock_map_update)(void *map, void *key, void *value, |
diff --git a/tools/testing/selftests/bpf/tcp_client.py b/tools/testing/selftests/bpf/tcp_client.py new file mode 100755 index 000000000000..481dccdf140c --- /dev/null +++ b/tools/testing/selftests/bpf/tcp_client.py | |||
@@ -0,0 +1,51 @@ | |||
1 | #!/usr/bin/env python2 | ||
2 | # | ||
3 | # SPDX-License-Identifier: GPL-2.0 | ||
4 | # | ||
5 | |||
6 | import sys, os, os.path, getopt | ||
7 | import socket, time | ||
8 | import subprocess | ||
9 | import select | ||
10 | |||
11 | def read(sock, n): | ||
12 | buf = '' | ||
13 | while len(buf) < n: | ||
14 | rem = n - len(buf) | ||
15 | try: s = sock.recv(rem) | ||
16 | except (socket.error), e: return '' | ||
17 | buf += s | ||
18 | return buf | ||
19 | |||
20 | def send(sock, s): | ||
21 | total = len(s) | ||
22 | count = 0 | ||
23 | while count < total: | ||
24 | try: n = sock.send(s) | ||
25 | except (socket.error), e: n = 0 | ||
26 | if n == 0: | ||
27 | return count; | ||
28 | count += n | ||
29 | return count | ||
30 | |||
31 | |||
32 | serverPort = int(sys.argv[1]) | ||
33 | HostName = socket.gethostname() | ||
34 | |||
35 | # create active socket | ||
36 | sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) | ||
37 | try: | ||
38 | sock.connect((HostName, serverPort)) | ||
39 | except socket.error as e: | ||
40 | sys.exit(1) | ||
41 | |||
42 | buf = '' | ||
43 | n = 0 | ||
44 | while n < 1000: | ||
45 | buf += '+' | ||
46 | n += 1 | ||
47 | |||
48 | sock.settimeout(1); | ||
49 | n = send(sock, buf) | ||
50 | n = read(sock, 500) | ||
51 | sys.exit(0) | ||
diff --git a/tools/testing/selftests/bpf/tcp_server.py b/tools/testing/selftests/bpf/tcp_server.py new file mode 100755 index 000000000000..bc454d7d0be2 --- /dev/null +++ b/tools/testing/selftests/bpf/tcp_server.py | |||
@@ -0,0 +1,83 @@ | |||
1 | #!/usr/bin/env python2 | ||
2 | # | ||
3 | # SPDX-License-Identifier: GPL-2.0 | ||
4 | # | ||
5 | |||
6 | import sys, os, os.path, getopt | ||
7 | import socket, time | ||
8 | import subprocess | ||
9 | import select | ||
10 | |||
11 | def read(sock, n): | ||
12 | buf = '' | ||
13 | while len(buf) < n: | ||
14 | rem = n - len(buf) | ||
15 | try: s = sock.recv(rem) | ||
16 | except (socket.error), e: return '' | ||
17 | buf += s | ||
18 | return buf | ||
19 | |||
20 | def send(sock, s): | ||
21 | total = len(s) | ||
22 | count = 0 | ||
23 | while count < total: | ||
24 | try: n = sock.send(s) | ||
25 | except (socket.error), e: n = 0 | ||
26 | if n == 0: | ||
27 | return count; | ||
28 | count += n | ||
29 | return count | ||
30 | |||
31 | |||
32 | SERVER_PORT = 12877 | ||
33 | MAX_PORTS = 2 | ||
34 | |||
35 | serverPort = SERVER_PORT | ||
36 | serverSocket = None | ||
37 | |||
38 | HostName = socket.gethostname() | ||
39 | |||
40 | # create passive socket | ||
41 | serverSocket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) | ||
42 | host = socket.gethostname() | ||
43 | |||
44 | try: serverSocket.bind((host, 0)) | ||
45 | except socket.error as msg: | ||
46 | print 'bind fails: ', msg | ||
47 | |||
48 | sn = serverSocket.getsockname() | ||
49 | serverPort = sn[1] | ||
50 | |||
51 | cmdStr = ("./tcp_client.py %d &") % (serverPort) | ||
52 | os.system(cmdStr) | ||
53 | |||
54 | buf = '' | ||
55 | n = 0 | ||
56 | while n < 500: | ||
57 | buf += '.' | ||
58 | n += 1 | ||
59 | |||
60 | serverSocket.listen(MAX_PORTS) | ||
61 | readList = [serverSocket] | ||
62 | |||
63 | while True: | ||
64 | readyRead, readyWrite, inError = \ | ||
65 | select.select(readList, [], [], 2) | ||
66 | |||
67 | if len(readyRead) > 0: | ||
68 | waitCount = 0 | ||
69 | for sock in readyRead: | ||
70 | if sock == serverSocket: | ||
71 | (clientSocket, address) = serverSocket.accept() | ||
72 | address = str(address[0]) | ||
73 | readList.append(clientSocket) | ||
74 | else: | ||
75 | sock.settimeout(1); | ||
76 | s = read(sock, 1000) | ||
77 | n = send(sock, buf) | ||
78 | sock.close() | ||
79 | serverSocket.close() | ||
80 | sys.exit(0) | ||
81 | else: | ||
82 | print 'Select timeout!' | ||
83 | sys.exit(1) | ||
diff --git a/tools/testing/selftests/bpf/test_tcpbpf.h b/tools/testing/selftests/bpf/test_tcpbpf.h new file mode 100644 index 000000000000..2fe43289943c --- /dev/null +++ b/tools/testing/selftests/bpf/test_tcpbpf.h | |||
@@ -0,0 +1,16 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | #ifndef _TEST_TCPBPF_H | ||
4 | #define _TEST_TCPBPF_H | ||
5 | |||
6 | struct tcpbpf_globals { | ||
7 | __u32 event_map; | ||
8 | __u32 total_retrans; | ||
9 | __u32 data_segs_in; | ||
10 | __u32 data_segs_out; | ||
11 | __u32 bad_cb_test_rv; | ||
12 | __u32 good_cb_test_rv; | ||
13 | __u64 bytes_received; | ||
14 | __u64 bytes_acked; | ||
15 | }; | ||
16 | #endif | ||
diff --git a/tools/testing/selftests/bpf/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/test_tcpbpf_kern.c new file mode 100644 index 000000000000..66bf71541903 --- /dev/null +++ b/tools/testing/selftests/bpf/test_tcpbpf_kern.c | |||
@@ -0,0 +1,118 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <stddef.h> | ||
3 | #include <string.h> | ||
4 | #include <linux/bpf.h> | ||
5 | #include <linux/if_ether.h> | ||
6 | #include <linux/if_packet.h> | ||
7 | #include <linux/ip.h> | ||
8 | #include <linux/in6.h> | ||
9 | #include <linux/types.h> | ||
10 | #include <linux/socket.h> | ||
11 | #include <linux/tcp.h> | ||
12 | #include <netinet/in.h> | ||
13 | #include "bpf_helpers.h" | ||
14 | #include "bpf_endian.h" | ||
15 | #include "test_tcpbpf.h" | ||
16 | |||
17 | struct bpf_map_def SEC("maps") global_map = { | ||
18 | .type = BPF_MAP_TYPE_ARRAY, | ||
19 | .key_size = sizeof(__u32), | ||
20 | .value_size = sizeof(struct tcpbpf_globals), | ||
21 | .max_entries = 2, | ||
22 | }; | ||
23 | |||
24 | static inline void update_event_map(int event) | ||
25 | { | ||
26 | __u32 key = 0; | ||
27 | struct tcpbpf_globals g, *gp; | ||
28 | |||
29 | gp = bpf_map_lookup_elem(&global_map, &key); | ||
30 | if (gp == NULL) { | ||
31 | struct tcpbpf_globals g = {0}; | ||
32 | |||
33 | g.event_map |= (1 << event); | ||
34 | bpf_map_update_elem(&global_map, &key, &g, | ||
35 | BPF_ANY); | ||
36 | } else { | ||
37 | g = *gp; | ||
38 | g.event_map |= (1 << event); | ||
39 | bpf_map_update_elem(&global_map, &key, &g, | ||
40 | BPF_ANY); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | int _version SEC("version") = 1; | ||
45 | |||
46 | SEC("sockops") | ||
47 | int bpf_testcb(struct bpf_sock_ops *skops) | ||
48 | { | ||
49 | int rv = -1; | ||
50 | int bad_call_rv = 0; | ||
51 | int good_call_rv = 0; | ||
52 | int op; | ||
53 | int v = 0; | ||
54 | |||
55 | op = (int) skops->op; | ||
56 | |||
57 | update_event_map(op); | ||
58 | |||
59 | switch (op) { | ||
60 | case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: | ||
61 | /* Test failure to set largest cb flag (assumes not defined) */ | ||
62 | bad_call_rv = bpf_sock_ops_cb_flags_set(skops, 0x80); | ||
63 | /* Set callback */ | ||
64 | good_call_rv = bpf_sock_ops_cb_flags_set(skops, | ||
65 | BPF_SOCK_OPS_STATE_CB_FLAG); | ||
66 | /* Update results */ | ||
67 | { | ||
68 | __u32 key = 0; | ||
69 | struct tcpbpf_globals g, *gp; | ||
70 | |||
71 | gp = bpf_map_lookup_elem(&global_map, &key); | ||
72 | if (!gp) | ||
73 | break; | ||
74 | g = *gp; | ||
75 | g.bad_cb_test_rv = bad_call_rv; | ||
76 | g.good_cb_test_rv = good_call_rv; | ||
77 | bpf_map_update_elem(&global_map, &key, &g, | ||
78 | BPF_ANY); | ||
79 | } | ||
80 | break; | ||
81 | case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: | ||
82 | /* Set callback */ | ||
83 | // good_call_rv = bpf_sock_ops_cb_flags_set(skops, | ||
84 | // BPF_SOCK_OPS_STATE_CB_FLAG); | ||
85 | skops->sk_txhash = 0x12345f; | ||
86 | v = 0xff; | ||
87 | rv = bpf_setsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v, | ||
88 | sizeof(v)); | ||
89 | break; | ||
90 | case BPF_SOCK_OPS_RTO_CB: | ||
91 | break; | ||
92 | case BPF_SOCK_OPS_RETRANS_CB: | ||
93 | break; | ||
94 | case BPF_SOCK_OPS_STATE_CB: | ||
95 | if (skops->args[1] == BPF_TCP_CLOSE) { | ||
96 | __u32 key = 0; | ||
97 | struct tcpbpf_globals g, *gp; | ||
98 | |||
99 | gp = bpf_map_lookup_elem(&global_map, &key); | ||
100 | if (!gp) | ||
101 | break; | ||
102 | g = *gp; | ||
103 | g.total_retrans = skops->total_retrans; | ||
104 | g.data_segs_in = skops->data_segs_in; | ||
105 | g.data_segs_out = skops->data_segs_out; | ||
106 | g.bytes_received = skops->bytes_received; | ||
107 | g.bytes_acked = skops->bytes_acked; | ||
108 | bpf_map_update_elem(&global_map, &key, &g, | ||
109 | BPF_ANY); | ||
110 | } | ||
111 | break; | ||
112 | default: | ||
113 | rv = -1; | ||
114 | } | ||
115 | skops->reply = rv; | ||
116 | return 1; | ||
117 | } | ||
118 | char _license[] SEC("license") = "GPL"; | ||
diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/test_tcpbpf_user.c new file mode 100644 index 000000000000..95a370f3d378 --- /dev/null +++ b/tools/testing/selftests/bpf/test_tcpbpf_user.c | |||
@@ -0,0 +1,126 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <stdio.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <stdio.h> | ||
5 | #include <unistd.h> | ||
6 | #include <errno.h> | ||
7 | #include <signal.h> | ||
8 | #include <string.h> | ||
9 | #include <assert.h> | ||
10 | #include <linux/perf_event.h> | ||
11 | #include <linux/ptrace.h> | ||
12 | #include <linux/bpf.h> | ||
13 | #include <sys/ioctl.h> | ||
14 | #include <sys/types.h> | ||
15 | #include <sys/stat.h> | ||
16 | #include <fcntl.h> | ||
17 | #include <bpf/bpf.h> | ||
18 | #include <bpf/libbpf.h> | ||
19 | #include "bpf_util.h" | ||
20 | #include <linux/perf_event.h> | ||
21 | #include "test_tcpbpf.h" | ||
22 | |||
23 | static int bpf_find_map(const char *test, struct bpf_object *obj, | ||
24 | const char *name) | ||
25 | { | ||
26 | struct bpf_map *map; | ||
27 | |||
28 | map = bpf_object__find_map_by_name(obj, name); | ||
29 | if (!map) { | ||
30 | printf("%s:FAIL:map '%s' not found\n", test, name); | ||
31 | return -1; | ||
32 | } | ||
33 | return bpf_map__fd(map); | ||
34 | } | ||
35 | |||
36 | #define SYSTEM(CMD) \ | ||
37 | do { \ | ||
38 | if (system(CMD)) { \ | ||
39 | printf("system(%s) FAILS!\n", CMD); \ | ||
40 | } \ | ||
41 | } while (0) | ||
42 | |||
43 | int main(int argc, char **argv) | ||
44 | { | ||
45 | const char *file = "test_tcpbpf_kern.o"; | ||
46 | struct tcpbpf_globals g = {0}; | ||
47 | int cg_fd, prog_fd, map_fd; | ||
48 | bool debug_flag = false; | ||
49 | int error = EXIT_FAILURE; | ||
50 | struct bpf_object *obj; | ||
51 | char cmd[100], *dir; | ||
52 | struct stat buffer; | ||
53 | __u32 key = 0; | ||
54 | int pid; | ||
55 | int rv; | ||
56 | |||
57 | if (argc > 1 && strcmp(argv[1], "-d") == 0) | ||
58 | debug_flag = true; | ||
59 | |||
60 | dir = "/tmp/cgroupv2/foo"; | ||
61 | |||
62 | if (stat(dir, &buffer) != 0) { | ||
63 | SYSTEM("mkdir -p /tmp/cgroupv2"); | ||
64 | SYSTEM("mount -t cgroup2 none /tmp/cgroupv2"); | ||
65 | SYSTEM("mkdir -p /tmp/cgroupv2/foo"); | ||
66 | } | ||
67 | pid = (int) getpid(); | ||
68 | sprintf(cmd, "echo %d >> /tmp/cgroupv2/foo/cgroup.procs", pid); | ||
69 | SYSTEM(cmd); | ||
70 | |||
71 | cg_fd = open(dir, O_DIRECTORY, O_RDONLY); | ||
72 | if (bpf_prog_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) { | ||
73 | printf("FAILED: load_bpf_file failed for: %s\n", file); | ||
74 | goto err; | ||
75 | } | ||
76 | |||
77 | rv = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_SOCK_OPS, 0); | ||
78 | if (rv) { | ||
79 | printf("FAILED: bpf_prog_attach: %d (%s)\n", | ||
80 | error, strerror(errno)); | ||
81 | goto err; | ||
82 | } | ||
83 | |||
84 | SYSTEM("./tcp_server.py"); | ||
85 | |||
86 | map_fd = bpf_find_map(__func__, obj, "global_map"); | ||
87 | if (map_fd < 0) | ||
88 | goto err; | ||
89 | |||
90 | rv = bpf_map_lookup_elem(map_fd, &key, &g); | ||
91 | if (rv != 0) { | ||
92 | printf("FAILED: bpf_map_lookup_elem returns %d\n", rv); | ||
93 | goto err; | ||
94 | } | ||
95 | |||
96 | if (g.bytes_received != 501 || g.bytes_acked != 1002 || | ||
97 | g.data_segs_in != 1 || g.data_segs_out != 1 || | ||
98 | (g.event_map ^ 0x47e) != 0 || g.bad_cb_test_rv != 0x80 || | ||
99 | g.good_cb_test_rv != 0) { | ||
100 | printf("FAILED: Wrong stats\n"); | ||
101 | if (debug_flag) { | ||
102 | printf("\n"); | ||
103 | printf("bytes_received: %d (expecting 501)\n", | ||
104 | (int)g.bytes_received); | ||
105 | printf("bytes_acked: %d (expecting 1002)\n", | ||
106 | (int)g.bytes_acked); | ||
107 | printf("data_segs_in: %d (expecting 1)\n", | ||
108 | g.data_segs_in); | ||
109 | printf("data_segs_out: %d (expecting 1)\n", | ||
110 | g.data_segs_out); | ||
111 | printf("event_map: 0x%x (at least 0x47e)\n", | ||
112 | g.event_map); | ||
113 | printf("bad_cb_test_rv: 0x%x (expecting 0x80)\n", | ||
114 | g.bad_cb_test_rv); | ||
115 | printf("good_cb_test_rv:0x%x (expecting 0)\n", | ||
116 | g.good_cb_test_rv); | ||
117 | } | ||
118 | goto err; | ||
119 | } | ||
120 | printf("PASSED!\n"); | ||
121 | error = 0; | ||
122 | err: | ||
123 | bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS); | ||
124 | return error; | ||
125 | |||
126 | } | ||