1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */
3 
4 #define _GNU_SOURCE
5 #include <sched.h>
6 #include <linux/socket.h>
7 #include <net/if.h>
8 
9 #include "test_progs.h"
10 #include "cgroup_helpers.h"
11 #include "network_helpers.h"
12 
13 #include "setget_sockopt.skel.h"
14 
15 #define CG_NAME "/setget-sockopt-test"
16 
17 static const char addr4_str[] = "127.0.0.1";
18 static const char addr6_str[] = "::1";
19 static struct setget_sockopt *skel;
20 static int cg_fd;
21 
22 static int create_netns(void)
23 {
24 	if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns"))
25 		return -1;
26 
27 	if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up"))
28 		return -1;
29 
30 	if (!ASSERT_OK(system("ip link add dev binddevtest1 type veth peer name binddevtest2"),
31 		       "add veth"))
32 		return -1;
33 
34 	if (!ASSERT_OK(system("ip link set dev binddevtest1 up"),
35 		       "bring veth up"))
36 		return -1;
37 
38 	return 0;
39 }
40 
41 static void test_tcp(int family)
42 {
43 	struct setget_sockopt__bss *bss = skel->bss;
44 	int sfd, cfd;
45 
46 	memset(bss, 0, sizeof(*bss));
47 
48 	sfd = start_server(family, SOCK_STREAM,
49 			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
50 	if (!ASSERT_GE(sfd, 0, "start_server"))
51 		return;
52 
53 	cfd = connect_to_fd(sfd, 0);
54 	if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) {
55 		close(sfd);
56 		return;
57 	}
58 	close(sfd);
59 	close(cfd);
60 
61 	ASSERT_EQ(bss->nr_listen, 1, "nr_listen");
62 	ASSERT_EQ(bss->nr_connect, 1, "nr_connect");
63 	ASSERT_EQ(bss->nr_active, 1, "nr_active");
64 	ASSERT_EQ(bss->nr_passive, 1, "nr_passive");
65 	ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create");
66 	ASSERT_EQ(bss->nr_binddev, 2, "nr_bind");
67 }
68 
69 static void test_udp(int family)
70 {
71 	struct setget_sockopt__bss *bss = skel->bss;
72 	int sfd;
73 
74 	memset(bss, 0, sizeof(*bss));
75 
76 	sfd = start_server(family, SOCK_DGRAM,
77 			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
78 	if (!ASSERT_GE(sfd, 0, "start_server"))
79 		return;
80 	close(sfd);
81 
82 	ASSERT_GE(bss->nr_socket_post_create, 1, "nr_socket_post_create");
83 	ASSERT_EQ(bss->nr_binddev, 1, "nr_bind");
84 }
85 
86 void test_setget_sockopt(void)
87 {
88 	cg_fd = test__join_cgroup(CG_NAME);
89 	if (cg_fd < 0)
90 		return;
91 
92 	if (create_netns())
93 		goto done;
94 
95 	skel = setget_sockopt__open();
96 	if (!ASSERT_OK_PTR(skel, "open skel"))
97 		goto done;
98 
99 	strcpy(skel->rodata->veth, "binddevtest1");
100 	skel->rodata->veth_ifindex = if_nametoindex("binddevtest1");
101 	if (!ASSERT_GT(skel->rodata->veth_ifindex, 0, "if_nametoindex"))
102 		goto done;
103 
104 	if (!ASSERT_OK(setget_sockopt__load(skel), "load skel"))
105 		goto done;
106 
107 	skel->links.skops_sockopt =
108 		bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd);
109 	if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup"))
110 		goto done;
111 
112 	skel->links.socket_post_create =
113 		bpf_program__attach_cgroup(skel->progs.socket_post_create, cg_fd);
114 	if (!ASSERT_OK_PTR(skel->links.socket_post_create, "attach_cgroup"))
115 		goto done;
116 
117 	test_tcp(AF_INET6);
118 	test_tcp(AF_INET);
119 	test_udp(AF_INET6);
120 	test_udp(AF_INET);
121 
122 done:
123 	setget_sockopt__destroy(skel);
124 	close(cg_fd);
125 }
126