xref: /linux/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c (revision ae22a94997b8a03dcb3c922857c203246711f9d4)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright Amazon.com Inc. or its affiliates. */
3 
4 #define _GNU_SOURCE
5 #include <sched.h>
6 #include <stdlib.h>
7 #include <net/if.h>
8 
9 #include "test_progs.h"
10 #include "cgroup_helpers.h"
11 #include "network_helpers.h"
12 #include "test_tcp_custom_syncookie.skel.h"
13 
14 static struct test_tcp_custom_syncookie_case {
15 	int family, type;
16 	char addr[16];
17 	char name[10];
18 } test_cases[] = {
19 	{
20 		.name = "IPv4 TCP",
21 		.family = AF_INET,
22 		.type = SOCK_STREAM,
23 		.addr = "127.0.0.1",
24 	},
25 	{
26 		.name = "IPv6 TCP",
27 		.family = AF_INET6,
28 		.type = SOCK_STREAM,
29 		.addr = "::1",
30 	},
31 };
32 
33 static int setup_netns(void)
34 {
35 	if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns"))
36 		return -1;
37 
38 	if (!ASSERT_OK(system("ip link set dev lo up"), "ip"))
39 		goto err;
40 
41 	if (!ASSERT_OK(write_sysctl("/proc/sys/net/ipv4/tcp_ecn", "1"),
42 		       "write_sysctl"))
43 		goto err;
44 
45 	return 0;
46 err:
47 	return -1;
48 }
49 
50 static int setup_tc(struct test_tcp_custom_syncookie *skel)
51 {
52 	LIBBPF_OPTS(bpf_tc_hook, qdisc_lo, .attach_point = BPF_TC_INGRESS);
53 	LIBBPF_OPTS(bpf_tc_opts, tc_attach,
54 		    .prog_fd = bpf_program__fd(skel->progs.tcp_custom_syncookie));
55 
56 	qdisc_lo.ifindex = if_nametoindex("lo");
57 	if (!ASSERT_OK(bpf_tc_hook_create(&qdisc_lo), "qdisc add dev lo clsact"))
58 		goto err;
59 
60 	if (!ASSERT_OK(bpf_tc_attach(&qdisc_lo, &tc_attach),
61 		       "filter add dev lo ingress"))
62 		goto err;
63 
64 	return 0;
65 err:
66 	return -1;
67 }
68 
69 #define msg "Hello World"
70 #define msglen 11
71 
72 static void transfer_message(int sender, int receiver)
73 {
74 	char buf[msglen];
75 	int ret;
76 
77 	ret = send(sender, msg, msglen, 0);
78 	if (!ASSERT_EQ(ret, msglen, "send"))
79 		return;
80 
81 	memset(buf, 0, sizeof(buf));
82 
83 	ret = recv(receiver, buf, msglen, 0);
84 	if (!ASSERT_EQ(ret, msglen, "recv"))
85 		return;
86 
87 	ret = strncmp(buf, msg, msglen);
88 	if (!ASSERT_EQ(ret, 0, "strncmp"))
89 		return;
90 }
91 
92 static void create_connection(struct test_tcp_custom_syncookie_case *test_case)
93 {
94 	int server, client, child;
95 
96 	server = start_server(test_case->family, test_case->type, test_case->addr, 0, 0);
97 	if (!ASSERT_NEQ(server, -1, "start_server"))
98 		return;
99 
100 	client = connect_to_fd(server, 0);
101 	if (!ASSERT_NEQ(client, -1, "connect_to_fd"))
102 		goto close_server;
103 
104 	child = accept(server, NULL, 0);
105 	if (!ASSERT_NEQ(child, -1, "accept"))
106 		goto close_client;
107 
108 	transfer_message(client, child);
109 	transfer_message(child, client);
110 
111 	close(child);
112 close_client:
113 	close(client);
114 close_server:
115 	close(server);
116 }
117 
118 void test_tcp_custom_syncookie(void)
119 {
120 	struct test_tcp_custom_syncookie *skel;
121 	int i;
122 
123 	if (setup_netns())
124 		return;
125 
126 	skel = test_tcp_custom_syncookie__open_and_load();
127 	if (!ASSERT_OK_PTR(skel, "open_and_load"))
128 		return;
129 
130 	if (setup_tc(skel))
131 		goto destroy_skel;
132 
133 	for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
134 		if (!test__start_subtest(test_cases[i].name))
135 			continue;
136 
137 		skel->bss->handled_syn = false;
138 		skel->bss->handled_ack = false;
139 
140 		create_connection(&test_cases[i]);
141 
142 		ASSERT_EQ(skel->bss->handled_syn, true, "SYN is not handled at tc.");
143 		ASSERT_EQ(skel->bss->handled_ack, true, "ACK is not handled at tc");
144 	}
145 
146 destroy_skel:
147 	system("tc qdisc del dev lo clsact");
148 
149 	test_tcp_custom_syncookie__destroy(skel);
150 }
151