]> git.meshlink.io Git - meshlink-tiny/blob - test/netns_utils.c
Use a key/value store with configurable storage callbacks.
[meshlink-tiny] / test / netns_utils.c
1 #define _GNU_SOURCE 1
2
3 #ifdef NDEBUG
4 #undef NDEBUG
5 #endif
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12
13 #include "meshlink-tiny.h"
14 #include "netns_utils.h"
15 #include "utils.h"
16
17 #include "full.h"
18
19 static int ip = 1;
20
21 /// Create meshlink instances and network namespaces for a list of peers
22 static void create_peers(peer_config_t *peers, int npeers, const char *prefix) {
23         // We require root for network namespaces
24         if(getuid() != 0) {
25                 exit(77);
26         }
27
28         for(int i = 0; i < npeers; i++) {
29                 bool full = peers[i].full;
30
31                 assert(asprintf(&peers[i].netns_name, "%s%d", prefix, i) > 0);
32                 char *command = NULL;
33                 assert(asprintf(&command,
34                                 "/bin/ip netns delete %1$s 2>/dev/null || true;"
35                                 "/bin/ip netns add %1$s;"
36                                 "/bin/ip netns exec %1$s ip link set dev lo up;",
37                                 peers[i].netns_name));
38                 assert(command);
39                 assert(system(command) == 0);
40                 free(command);
41
42                 char *netns_path = NULL;
43                 assert(asprintf(&netns_path, "/run/netns/%s", peers[i].netns_name));
44                 assert(netns_path);
45                 peers[i].netns = open(netns_path, O_RDONLY);
46                 assert(peers[i].netns != -1);
47                 free(netns_path);
48
49                 char *conf_path = NULL;
50                 assert(asprintf(&conf_path, "%s_conf.%d", prefix, i + 1) > 0);
51                 assert(conf_path);
52                 assert(full ? full_meshlink_destroy(conf_path) : meshlink_destroy(conf_path));
53
54                 meshlink_open_params_t *params = full
55                                                  ? full_meshlink_open_params_init(conf_path, peers[i].name, prefix, peers[i].devclass)
56                                                  : meshlink_open_params_init(conf_path, peers[i].name, prefix, peers[i].devclass);
57                 assert(params);
58                 assert(full
59                        ? full_meshlink_open_params_set_netns(params, peers[i].netns)
60                        : meshlink_open_params_set_netns(params, peers[i].netns)
61                       );
62
63                 peers[i].mesh = full ? full_meshlink_open_ex(params) : meshlink_open_ex(params);
64                 assert(peers[i].mesh);
65                 free(params);
66                 free(conf_path);
67
68                 if(full) {
69                         full_meshlink_enable_discovery(peers[i].mesh, false);
70                 }
71         }
72 }
73
74 /// Set up a LAN topology where all peers can see each other directly
75 static void setup_lan_topology(peer_config_t *peers, int npeers) {
76         // Set up the LAN bridge
77         {
78                 char *command = NULL;
79                 assert(asprintf(&command,
80                                 "/bin/ip netns exec %1$s /bin/ip link add eth0 type bridge;"
81                                 "/bin/ip netns exec %1$s /bin/ip link set eth0 up;",
82                                 peers[0].netns_name));
83                 assert(command);
84                 assert(system(command) == 0);
85         }
86
87         // Add an interface to each peer that is connected to the bridge
88         for(int i = 1; i < npeers; i++) {
89                 char *command = NULL;
90                 assert(asprintf(&command,
91                                 "/bin/ip netns exec %1$s /bin/ip link add eth0 type veth peer eth%3$d netns %2$s;"
92                                 "/bin/ip netns exec %1$s /bin/ip link set dev eth0 up;"
93                                 "/bin/ip netns exec %2$s /bin/ip link set dev eth%3$d master eth0 up;",
94                                 peers[i].netns_name, peers[0].netns_name, i));
95                 assert(command);
96                 assert(system(command) == 0);
97                 free(command);
98         }
99
100         // Configure addresses
101         for(int i = 0; i < npeers; i++) {
102                 change_peer_ip(&peers[i]);
103         }
104 }
105
106 /// Set up an indirect topology where all peers can only access the relay
107 static void setup_indirect_topology(peer_config_t *peers, int npeers) {
108         // Add an interface to each peer that is connected to the relay
109         for(int i = 1; i < npeers; i++) {
110                 char *command = NULL;
111                 assert(asprintf(&command,
112                                 "/bin/ip netns exec %1$s /bin/ip link add eth0 type veth peer eth%3$d netns %2$s;"
113                                 "/bin/ip netns exec %1$s ip addr flush dev eth0;"
114                                 "/bin/ip netns exec %1$s ip addr add 192.168.%3$d.2/24 dev eth0;"
115                                 "/bin/ip netns exec %1$s /bin/ip link set dev eth0 up;"
116                                 "/bin/ip netns exec %2$s ip addr flush dev eth%3$d;"
117                                 "/bin/ip netns exec %2$s ip addr add 192.168.%3$d.1/24 dev eth%3$d;"
118                                 "/bin/ip netns exec %2$s /bin/ip link set dev eth%3$d up;",
119                                 peers[i].netns_name, peers[0].netns_name, i));
120                 assert(command);
121                 assert(system(command) == 0);
122                 free(command);
123         }
124 }
125
126 /// Give a peer a unique IP address
127 void change_peer_ip(peer_config_t *peer) {
128         char *command = NULL;
129         assert(asprintf(&command,
130                         "/bin/ip netns exec %1$s ip addr flush dev eth0;"
131                         "/bin/ip netns exec %1$s ip addr add 203.0.113.%2$d/24 dev eth0;",
132                         peer->netns_name, ip));
133         ip++;
134         assert(command);
135         assert(system(command) == 0);
136         free(command);
137 }
138
139 /// Let the first peer in a list invite all the subsequent peers
140 static void invite_peers(peer_config_t *peers, int npeers) {
141         assert(peers[0].full);
142         assert(full_meshlink_start(peers[0].mesh));
143
144         for(int i = 1; i < npeers; i++) {
145                 char *invitation = full_meshlink_invite_ex(peers[0].mesh, NULL, peers[i].name, MESHLINK_INVITE_LOCAL | MESHLINK_INVITE_NUMERIC);
146                 assert(invitation);
147                 printf("%s\n", invitation);
148                 assert(peers[i].full ? full_meshlink_join(peers[i].mesh, invitation) : meshlink_join(peers[i].mesh, invitation));
149                 free(invitation);
150         }
151
152         full_meshlink_stop(peers[0].mesh);
153 }
154
155 /// Close meshlink instances and clean up
156 static void close_peers(peer_config_t *peers, int npeers) {
157         for(int i = 0; i < npeers; i++) {
158                 peers[i].full ? full_meshlink_close(peers[i].mesh) : meshlink_close(peers[i].mesh);
159                 close(peers[i].netns);
160                 free(peers[i].netns_name);
161         }
162 }
163
164 /// Set up relay, peer and NUT that are directly connected
165 peer_config_t *setup_relay_peer_nut(const char *prefix) {
166         static peer_config_t peers[] = {
167                 {"relay", DEV_CLASS_BACKBONE, NULL, 0, true, NULL},
168                 {"peer", DEV_CLASS_STATIONARY, NULL, 0, false, NULL},
169                 {"nut", DEV_CLASS_STATIONARY, NULL, 0, false, NULL},
170         };
171
172         create_peers(peers, 3, prefix);
173         setup_lan_topology(peers, 3);
174         invite_peers(peers, 3);
175
176         return peers;
177 }
178
179 /// Set up relay, peer and NUT that are directly connected
180 peer_config_t *setup_relay_peer_nut_indirect(const char *prefix) {
181         static peer_config_t peers[] = {
182                 {"relay", DEV_CLASS_BACKBONE, NULL, 0, true, NULL},
183                 {"peer", DEV_CLASS_STATIONARY, NULL, 0, false, NULL},
184                 {"nut", DEV_CLASS_STATIONARY, NULL, 0, false, NULL},
185         };
186
187         create_peers(peers, 3, prefix);
188         setup_indirect_topology(peers, 3);
189         assert(full_meshlink_add_invitation_address(peers[0].mesh, "192.168.1.1", NULL));
190         assert(full_meshlink_add_invitation_address(peers[0].mesh, "192.168.2.1", NULL));
191         invite_peers(peers, 3);
192
193         return peers;
194 }
195
196 /// Make all nodes only be able to communicate via TCP
197 void set_peers_tcponly(peer_config_t *peers, int npeers) {
198         for(int i = 0; i < npeers; i++) {
199                 char *command = NULL;
200                 assert(asprintf(&command,
201                                 "/bin/ip netns exec %1$s iptables -A INPUT -p udp -j DROP;"
202                                 "/bin/ip netns exec %1$s iptables -A OUTPUT -p udp -j DROP;",
203                                 peers[i].netns_name));
204                 assert(command);
205                 assert(system(command) == 0);
206                 free(command);
207         }
208 }
209
210 void close_relay_peer_nut(peer_config_t *peers) {
211         close_peers(peers, 3);
212 }