1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2
3 /*
4 * Topology:
5 * ---------
6 * NS0 namespace | NS1 namespace
7 * |
8 * +--------------+ | +--------------+
9 * | veth01 |----------| veth10 |
10 * | 172.16.1.100 | | | 172.16.1.200 |
11 * | bpf | | +--------------+
12 * +--------------+ |
13 * server(UDP/TCP) |
14 * +-------------------+ |
15 * | vrf1 | |
16 * | +--------------+ | | +--------------+
17 * | | veth02 |----------| veth20 |
18 * | | 172.16.2.100 | | | | 172.16.2.200 |
19 * | | bpf | | | +--------------+
20 * | +--------------+ | |
21 * | server(UDP/TCP) | |
22 * +-------------------+ |
23 *
24 * Test flow
25 * -----------
26 * The tests verifies that socket lookup via TC is VRF aware:
27 * 1) Creates two veth pairs between NS0 and NS1:
28 * a) veth01 <-> veth10 outside the VRF
29 * b) veth02 <-> veth20 in the VRF
30 * 2) Attaches to veth01 and veth02 a program that calls:
31 * a) bpf_skc_lookup_tcp() with TCP and tcp_skc is true
32 * b) bpf_sk_lookup_tcp() with TCP and tcp_skc is false
33 * c) bpf_sk_lookup_udp() with UDP
34 * The program stores the lookup result in bss->lookup_status.
35 * 3) Creates a socket TCP/UDP server in/outside the VRF.
36 * 4) The test expects lookup_status to be:
37 * a) 0 from device in VRF to server outside VRF
38 * b) 0 from device outside VRF to server in VRF
39 * c) 1 from device in VRF to server in VRF
40 * d) 1 from device outside VRF to server outside VRF
41 */
42
43 #include <net/if.h>
44
45 #include "test_progs.h"
46 #include "network_helpers.h"
47 #include "vrf_socket_lookup.skel.h"
48
49 #define NS0 "vrf_socket_lookup_0"
50 #define NS1 "vrf_socket_lookup_1"
51
52 #define IP4_ADDR_VETH01 "172.16.1.100"
53 #define IP4_ADDR_VETH10 "172.16.1.200"
54 #define IP4_ADDR_VETH02 "172.16.2.100"
55 #define IP4_ADDR_VETH20 "172.16.2.200"
56
57 #define NON_VRF_PORT 5000
58 #define IN_VRF_PORT 5001
59
60 #define TIMEOUT_MS 3000
61
make_socket(int sotype,const char * ip,int port,struct sockaddr_storage * addr)62 static int make_socket(int sotype, const char *ip, int port,
63 struct sockaddr_storage *addr)
64 {
65 int err, fd;
66
67 err = make_sockaddr(AF_INET, ip, port, addr, NULL);
68 if (!ASSERT_OK(err, "make_address"))
69 return -1;
70
71 fd = socket(AF_INET, sotype, 0);
72 if (!ASSERT_GE(fd, 0, "socket"))
73 return -1;
74
75 if (!ASSERT_OK(settimeo(fd, TIMEOUT_MS), "settimeo"))
76 goto fail;
77
78 return fd;
79 fail:
80 close(fd);
81 return -1;
82 }
83
make_server(int sotype,const char * ip,int port,const char * ifname)84 static int make_server(int sotype, const char *ip, int port, const char *ifname)
85 {
86 int err, fd = -1;
87
88 fd = start_server(AF_INET, sotype, ip, port, TIMEOUT_MS);
89 if (!ASSERT_GE(fd, 0, "start_server"))
90 return -1;
91
92 if (ifname) {
93 err = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
94 ifname, strlen(ifname) + 1);
95 if (!ASSERT_OK(err, "setsockopt(SO_BINDTODEVICE)"))
96 goto fail;
97 }
98
99 return fd;
100 fail:
101 close(fd);
102 return -1;
103 }
104
attach_progs(char * ifname,int tc_prog_fd,int xdp_prog_fd)105 static int attach_progs(char *ifname, int tc_prog_fd, int xdp_prog_fd)
106 {
107 LIBBPF_OPTS(bpf_tc_hook, hook, .attach_point = BPF_TC_INGRESS);
108 LIBBPF_OPTS(bpf_tc_opts, opts, .handle = 1, .priority = 1,
109 .prog_fd = tc_prog_fd);
110 int ret, ifindex;
111
112 ifindex = if_nametoindex(ifname);
113 if (!ASSERT_NEQ(ifindex, 0, "if_nametoindex"))
114 return -1;
115 hook.ifindex = ifindex;
116
117 ret = bpf_tc_hook_create(&hook);
118 if (!ASSERT_OK(ret, "bpf_tc_hook_create"))
119 return ret;
120
121 ret = bpf_tc_attach(&hook, &opts);
122 if (!ASSERT_OK(ret, "bpf_tc_attach")) {
123 bpf_tc_hook_destroy(&hook);
124 return ret;
125 }
126 ret = bpf_xdp_attach(ifindex, xdp_prog_fd, 0, NULL);
127 if (!ASSERT_OK(ret, "bpf_xdp_attach")) {
128 bpf_tc_hook_destroy(&hook);
129 return ret;
130 }
131
132 return 0;
133 }
134
cleanup(void)135 static void cleanup(void)
136 {
137 SYS_NOFAIL("test -f /var/run/netns/" NS0 " && ip netns delete "
138 NS0);
139 SYS_NOFAIL("test -f /var/run/netns/" NS1 " && ip netns delete "
140 NS1);
141 }
142
setup(struct vrf_socket_lookup * skel)143 static int setup(struct vrf_socket_lookup *skel)
144 {
145 int tc_prog_fd, xdp_prog_fd, ret = 0;
146 struct nstoken *nstoken = NULL;
147
148 SYS(fail, "ip netns add " NS0);
149 SYS(fail, "ip netns add " NS1);
150
151 /* NS0 <-> NS1 [veth01 <-> veth10] */
152 SYS(fail, "ip link add veth01 netns " NS0 " type veth peer name veth10"
153 " netns " NS1);
154 SYS(fail, "ip -net " NS0 " addr add " IP4_ADDR_VETH01 "/24 dev veth01");
155 SYS(fail, "ip -net " NS0 " link set dev veth01 up");
156 SYS(fail, "ip -net " NS1 " addr add " IP4_ADDR_VETH10 "/24 dev veth10");
157 SYS(fail, "ip -net " NS1 " link set dev veth10 up");
158
159 /* NS0 <-> NS1 [veth02 <-> veth20] */
160 SYS(fail, "ip link add veth02 netns " NS0 " type veth peer name veth20"
161 " netns " NS1);
162 SYS(fail, "ip -net " NS0 " addr add " IP4_ADDR_VETH02 "/24 dev veth02");
163 SYS(fail, "ip -net " NS0 " link set dev veth02 up");
164 SYS(fail, "ip -net " NS1 " addr add " IP4_ADDR_VETH20 "/24 dev veth20");
165 SYS(fail, "ip -net " NS1 " link set dev veth20 up");
166
167 /* veth02 -> vrf1 */
168 SYS(fail, "ip -net " NS0 " link add vrf1 type vrf table 11");
169 SYS(fail, "ip -net " NS0 " route add vrf vrf1 unreachable default"
170 " metric 4278198272");
171 SYS(fail, "ip -net " NS0 " link set vrf1 alias vrf");
172 SYS(fail, "ip -net " NS0 " link set vrf1 up");
173 SYS(fail, "ip -net " NS0 " link set veth02 master vrf1");
174
175 /* Attach TC and XDP progs to veth devices in NS0 */
176 nstoken = open_netns(NS0);
177 if (!ASSERT_OK_PTR(nstoken, "setns " NS0))
178 goto fail;
179 tc_prog_fd = bpf_program__fd(skel->progs.tc_socket_lookup);
180 if (!ASSERT_GE(tc_prog_fd, 0, "bpf_program__tc_fd"))
181 goto fail;
182 xdp_prog_fd = bpf_program__fd(skel->progs.xdp_socket_lookup);
183 if (!ASSERT_GE(xdp_prog_fd, 0, "bpf_program__xdp_fd"))
184 goto fail;
185
186 if (attach_progs("veth01", tc_prog_fd, xdp_prog_fd))
187 goto fail;
188
189 if (attach_progs("veth02", tc_prog_fd, xdp_prog_fd))
190 goto fail;
191
192 goto close;
193 fail:
194 ret = -1;
195 close:
196 if (nstoken)
197 close_netns(nstoken);
198 return ret;
199 }
200
test_lookup(struct vrf_socket_lookup * skel,int sotype,const char * ip,int port,bool test_xdp,bool tcp_skc,int lookup_status_exp)201 static int test_lookup(struct vrf_socket_lookup *skel, int sotype,
202 const char *ip, int port, bool test_xdp, bool tcp_skc,
203 int lookup_status_exp)
204 {
205 static const char msg[] = "Hello Server";
206 struct sockaddr_storage addr = {};
207 int fd, ret = 0;
208
209 fd = make_socket(sotype, ip, port, &addr);
210 if (fd < 0)
211 return -1;
212
213 skel->bss->test_xdp = test_xdp;
214 skel->bss->tcp_skc = tcp_skc;
215 skel->bss->lookup_status = -1;
216
217 if (sotype == SOCK_STREAM)
218 connect(fd, (void *)&addr, sizeof(struct sockaddr_in));
219 else
220 sendto(fd, msg, sizeof(msg), 0, (void *)&addr,
221 sizeof(struct sockaddr_in));
222
223 if (!ASSERT_EQ(skel->bss->lookup_status, lookup_status_exp,
224 "lookup_status"))
225 goto fail;
226
227 goto close;
228
229 fail:
230 ret = -1;
231 close:
232 close(fd);
233 return ret;
234 }
235
_test_vrf_socket_lookup(struct vrf_socket_lookup * skel,int sotype,bool test_xdp,bool tcp_skc)236 static void _test_vrf_socket_lookup(struct vrf_socket_lookup *skel, int sotype,
237 bool test_xdp, bool tcp_skc)
238 {
239 int in_vrf_server = -1, non_vrf_server = -1;
240 struct nstoken *nstoken = NULL;
241
242 nstoken = open_netns(NS0);
243 if (!ASSERT_OK_PTR(nstoken, "setns " NS0))
244 goto done;
245
246 /* Open sockets in and outside VRF */
247 non_vrf_server = make_server(sotype, "0.0.0.0", NON_VRF_PORT, NULL);
248 if (!ASSERT_GE(non_vrf_server, 0, "make_server__outside_vrf_fd"))
249 goto done;
250
251 in_vrf_server = make_server(sotype, "0.0.0.0", IN_VRF_PORT, "veth02");
252 if (!ASSERT_GE(in_vrf_server, 0, "make_server__in_vrf_fd"))
253 goto done;
254
255 /* Perform test from NS1 */
256 close_netns(nstoken);
257 nstoken = open_netns(NS1);
258 if (!ASSERT_OK_PTR(nstoken, "setns " NS1))
259 goto done;
260
261 if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH02, NON_VRF_PORT,
262 test_xdp, tcp_skc, 0), "in_to_out"))
263 goto done;
264 if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH02, IN_VRF_PORT,
265 test_xdp, tcp_skc, 1), "in_to_in"))
266 goto done;
267 if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH01, NON_VRF_PORT,
268 test_xdp, tcp_skc, 1), "out_to_out"))
269 goto done;
270 if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH01, IN_VRF_PORT,
271 test_xdp, tcp_skc, 0), "out_to_in"))
272 goto done;
273
274 done:
275 if (non_vrf_server >= 0)
276 close(non_vrf_server);
277 if (in_vrf_server >= 0)
278 close(in_vrf_server);
279 if (nstoken)
280 close_netns(nstoken);
281 }
282
test_vrf_socket_lookup(void)283 void test_vrf_socket_lookup(void)
284 {
285 struct vrf_socket_lookup *skel;
286
287 cleanup();
288
289 skel = vrf_socket_lookup__open_and_load();
290 if (!ASSERT_OK_PTR(skel, "vrf_socket_lookup__open_and_load"))
291 return;
292
293 if (!ASSERT_OK(setup(skel), "setup"))
294 goto done;
295
296 if (test__start_subtest("tc_socket_lookup_tcp"))
297 _test_vrf_socket_lookup(skel, SOCK_STREAM, false, false);
298 if (test__start_subtest("tc_socket_lookup_tcp_skc"))
299 _test_vrf_socket_lookup(skel, SOCK_STREAM, false, false);
300 if (test__start_subtest("tc_socket_lookup_udp"))
301 _test_vrf_socket_lookup(skel, SOCK_STREAM, false, false);
302 if (test__start_subtest("xdp_socket_lookup_tcp"))
303 _test_vrf_socket_lookup(skel, SOCK_STREAM, true, false);
304 if (test__start_subtest("xdp_socket_lookup_tcp_skc"))
305 _test_vrf_socket_lookup(skel, SOCK_STREAM, true, false);
306 if (test__start_subtest("xdp_socket_lookup_udp"))
307 _test_vrf_socket_lookup(skel, SOCK_STREAM, true, false);
308
309 done:
310 vrf_socket_lookup__destroy(skel);
311 cleanup();
312 }
313