]> Git Repo - linux.git/blob - tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c
selftests/bpf: Store BPF object files with .bpf.o extension
[linux.git] / tools / testing / selftests / bpf / prog_tests / xdp_synproxy.c
1 // SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
2 /* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3
4 #define _GNU_SOURCE
5 #include <test_progs.h>
6 #include <network_helpers.h>
7 #include <ctype.h>
8
9 #define CMD_OUT_BUF_SIZE 1023
10
11 #define SYS(cmd) ({ \
12         if (!ASSERT_OK(system(cmd), (cmd))) \
13                 goto out; \
14 })
15
16 #define SYS_OUT(cmd, ...) ({ \
17         char buf[1024]; \
18         snprintf(buf, sizeof(buf), (cmd), ##__VA_ARGS__); \
19         FILE *f = popen(buf, "r"); \
20         if (!ASSERT_OK_PTR(f, buf)) \
21                 goto out; \
22         f; \
23 })
24
25 /* out must be at least `size * 4 + 1` bytes long */
26 static void escape_str(char *out, const char *in, size_t size)
27 {
28         static const char *hex = "0123456789ABCDEF";
29         size_t i;
30
31         for (i = 0; i < size; i++) {
32                 if (isprint(in[i]) && in[i] != '\\' && in[i] != '\'') {
33                         *out++ = in[i];
34                 } else {
35                         *out++ = '\\';
36                         *out++ = 'x';
37                         *out++ = hex[(in[i] >> 4) & 0xf];
38                         *out++ = hex[in[i] & 0xf];
39                 }
40         }
41         *out++ = '\0';
42 }
43
44 static bool expect_str(char *buf, size_t size, const char *str, const char *name)
45 {
46         static char escbuf_expected[CMD_OUT_BUF_SIZE * 4];
47         static char escbuf_actual[CMD_OUT_BUF_SIZE * 4];
48         static int duration = 0;
49         bool ok;
50
51         ok = size == strlen(str) && !memcmp(buf, str, size);
52
53         if (!ok) {
54                 escape_str(escbuf_expected, str, strlen(str));
55                 escape_str(escbuf_actual, buf, size);
56         }
57         CHECK(!ok, name, "unexpected %s: actual '%s' != expected '%s'\n",
58               name, escbuf_actual, escbuf_expected);
59
60         return ok;
61 }
62
63 static void test_synproxy(bool xdp)
64 {
65         int server_fd = -1, client_fd = -1, accept_fd = -1;
66         char *prog_id = NULL, *prog_id_end;
67         struct nstoken *ns = NULL;
68         FILE *ctrl_file = NULL;
69         char buf[CMD_OUT_BUF_SIZE];
70         size_t size;
71
72         SYS("ip netns add synproxy");
73
74         SYS("ip link add tmp0 type veth peer name tmp1");
75         SYS("ip link set tmp1 netns synproxy");
76         SYS("ip link set tmp0 up");
77         SYS("ip addr replace 198.18.0.1/24 dev tmp0");
78
79         /* When checksum offload is enabled, the XDP program sees wrong
80          * checksums and drops packets.
81          */
82         SYS("ethtool -K tmp0 tx off");
83         if (xdp)
84                 /* Workaround required for veth. */
85                 SYS("ip link set tmp0 xdp object xdp_dummy.bpf.o section xdp 2> /dev/null");
86
87         ns = open_netns("synproxy");
88         if (!ASSERT_OK_PTR(ns, "setns"))
89                 goto out;
90
91         SYS("ip link set lo up");
92         SYS("ip link set tmp1 up");
93         SYS("ip addr replace 198.18.0.2/24 dev tmp1");
94         SYS("sysctl -w net.ipv4.tcp_syncookies=2");
95         SYS("sysctl -w net.ipv4.tcp_timestamps=1");
96         SYS("sysctl -w net.netfilter.nf_conntrack_tcp_loose=0");
97         SYS("iptables -t raw -I PREROUTING \
98             -i tmp1 -p tcp -m tcp --syn --dport 8080 -j CT --notrack");
99         SYS("iptables -t filter -A INPUT \
100             -i tmp1 -p tcp -m tcp --dport 8080 -m state --state INVALID,UNTRACKED \
101             -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460");
102         SYS("iptables -t filter -A INPUT \
103             -i tmp1 -m state --state INVALID -j DROP");
104
105         ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --ports 8080 \
106                             --single --mss4 1460 --mss6 1440 \
107                             --wscale 7 --ttl 64%s", xdp ? "" : " --tc");
108         size = fread(buf, 1, sizeof(buf), ctrl_file);
109         pclose(ctrl_file);
110         if (!expect_str(buf, size, "Total SYNACKs generated: 0\n",
111                         "initial SYNACKs"))
112                 goto out;
113
114         if (!xdp) {
115                 ctrl_file = SYS_OUT("tc filter show dev tmp1 ingress");
116                 size = fread(buf, 1, sizeof(buf), ctrl_file);
117                 pclose(ctrl_file);
118                 prog_id = memmem(buf, size, " id ", 4);
119                 if (!ASSERT_OK_PTR(prog_id, "find prog id"))
120                         goto out;
121                 prog_id += 4;
122                 if (!ASSERT_LT(prog_id, buf + size, "find prog id begin"))
123                         goto out;
124                 prog_id_end = prog_id;
125                 while (prog_id_end < buf + size && *prog_id_end >= '0' &&
126                        *prog_id_end <= '9')
127                         prog_id_end++;
128                 if (!ASSERT_LT(prog_id_end, buf + size, "find prog id end"))
129                         goto out;
130                 *prog_id_end = '\0';
131         }
132
133         server_fd = start_server(AF_INET, SOCK_STREAM, "198.18.0.2", 8080, 0);
134         if (!ASSERT_GE(server_fd, 0, "start_server"))
135                 goto out;
136
137         close_netns(ns);
138         ns = NULL;
139
140         client_fd = connect_to_fd(server_fd, 10000);
141         if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
142                 goto out;
143
144         accept_fd = accept(server_fd, NULL, NULL);
145         if (!ASSERT_GE(accept_fd, 0, "accept"))
146                 goto out;
147
148         ns = open_netns("synproxy");
149         if (!ASSERT_OK_PTR(ns, "setns"))
150                 goto out;
151
152         if (xdp)
153                 ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --single");
154         else
155                 ctrl_file = SYS_OUT("./xdp_synproxy --prog %s --single",
156                                     prog_id);
157         size = fread(buf, 1, sizeof(buf), ctrl_file);
158         pclose(ctrl_file);
159         if (!expect_str(buf, size, "Total SYNACKs generated: 1\n",
160                         "SYNACKs after connection"))
161                 goto out;
162
163 out:
164         if (accept_fd >= 0)
165                 close(accept_fd);
166         if (client_fd >= 0)
167                 close(client_fd);
168         if (server_fd >= 0)
169                 close(server_fd);
170         if (ns)
171                 close_netns(ns);
172
173         system("ip link del tmp0");
174         system("ip netns del synproxy");
175 }
176
177 void test_xdp_synproxy(void)
178 {
179         if (test__start_subtest("xdp"))
180                 test_synproxy(true);
181         if (test__start_subtest("tc"))
182                 test_synproxy(false);
183 }
This page took 0.04504 seconds and 4 git commands to generate.