]> git.meshlink.io Git - meshlink/blob - test/blackbox/common/network_namespace_framework.c
2cac3b2e054b7385d7ac85a5c445cd303c9cd7c5
[meshlink] / test / blackbox / common / network_namespace_framework.c
1 /*
2     test_optimal_pmtu.c -- Execution of specific meshlink black box test cases
3     Copyright (C) 2019  Guus Sliepen <guus@meshlink.io>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 #include "network_namespace_framework.h"
20
21 #define DEFAULT_PUB_NET_ADDR "203.0.113.0/24"
22 #define DEFAULT_GATEWAY_NET_ADDR "203.0.113.254"
23 #define NS_PEER0  " ns_peer0 "
24 #define NS_ETH0   " ns_eth0 "
25 #define PEER_INDEX i ? 0 : 1
26 #define get_namespace_handle_by_index(state_ptr, index) index < state_ptr->num_namespaces ? &(state_ptr->namespaces[index]) : NULL
27 #define get_interface_handle_by_index(namespace, index) index < namespace->interfaces_no  ? &((namespace->interfaces)[index]) : NULL
28
29 static int ipv4_str_check_cidr(const char *ip_addr) {
30         int cidr = 0;
31         sscanf(ip_addr, "%*d.%*d.%*d.%*d/%d", &cidr);
32         return cidr;
33 }
34
35 static char *ipv4_str_remove_cidr(const char *ipv4_addr) {
36         char *ptr = strdup(ipv4_addr);
37         assert(ptr);
38
39         if(ipv4_str_check_cidr(ptr)) {
40                 char *end = strchr(ptr, '/');
41                 *end = '\0';
42         }
43
44         return ptr;
45 }
46
47 namespace_t *find_namespace(netns_state_t *state, const char *namespace_name) {
48         int i;
49
50         for(i = 0; i < state->num_namespaces; i++) {
51                 if(!strcmp((state->namespaces[i]).name, namespace_name)) {
52                         return &(state->namespaces[i]);
53                 }
54         }
55
56         return NULL;
57 }
58
59 static int netns_delete_namespace(namespace_t *namespace_handle) {
60         char cmd[200];
61
62         if(namespace_handle->type != BRIDGE) {
63                 assert(sprintf(cmd, "ip netns del %s 2>/dev/null", namespace_handle->name) >= 0);
64         } else {
65                 assert(sprintf(cmd, "ip link del %s 2>/dev/null", namespace_handle->name) >= 0);
66         }
67
68         return system(cmd);
69 }
70
71 /* Create new network namespace using namespace handle */
72 static void netns_create_namespace(netns_state_t *test_state, namespace_t *namespace_handle) {
73         char cmd[200];
74         int cmd_ret;
75
76         // Add the network namespace
77
78         sprintf(cmd, "ip netns add %s", namespace_handle->name);
79         assert(system(cmd) == 0);
80
81         sprintf(cmd, "ip netns exec %s ip link set dev lo up", namespace_handle->name);
82         assert(system(cmd) == 0);
83 }
84
85 static void netns_create_bridge(netns_state_t *test_state, namespace_t *namespace_handle) {
86         char cmd[200];
87         int cmd_ret;
88
89         sprintf(cmd, "ip link add name %s type bridge", namespace_handle->name);
90         assert(system(cmd) == 0);
91
92         sprintf(cmd, "ip link set %s up", namespace_handle->name);
93         assert(system(cmd) == 0);
94 }
95
96 interface_t *get_peer_interface_handle(netns_state_t *test_state, namespace_t *namespace, namespace_t *peer_namespace) {
97         int i;
98         interface_t *interfaces = namespace->interfaces;
99         int if_no = namespace->interfaces_no;
100         char *peer_name = peer_namespace->name;
101
102         for(i = 0; i < if_no; i++) {
103                 if(!strcasecmp(interfaces[i].if_peer, peer_name)) {
104                         return &interfaces[i];
105                 }
106         }
107
108         return NULL;
109 }
110
111 interface_t *get_interface_handle_by_name(netns_state_t *test_state, namespace_t *namespace, const char *peer_name) {
112         namespace_t *peer_ns;
113         peer_ns = find_namespace(test_state, peer_name);
114         assert(peer_ns);
115
116         return get_peer_interface_handle(test_state, namespace, peer_ns);
117 }
118
119 bool check_interfaces_visited(netns_state_t *test_state, namespace_t *ns1, namespace_t *ns2) {
120         interface_t *iface, *peer_iface;
121         iface = get_peer_interface_handle(test_state, ns1, ns2);
122         peer_iface = get_peer_interface_handle(test_state, ns2, ns1);
123         assert(iface && peer_iface);
124
125         return iface->priv || peer_iface->priv;
126 }
127
128 void netns_connect_namespaces(netns_state_t *test_state, namespace_t *ns1, namespace_t *ns2) {
129         char buff[20], cmd[200], ns_eth0[20], ns_peer0[20];
130         int cmd_ret, if_no, i;
131         char eth_pairs[2][20];
132         namespace_t *ns[2] = { ns1, ns2 };
133         interface_t *interface;
134         char *set = "set";
135
136         // Check if visited already
137         if(check_interfaces_visited(test_state, ns1, ns2)) {
138                 return;
139         }
140
141         assert(sprintf(eth_pairs[0], "%.9s_eth0", ns2->name) >= 0);
142         assert(sprintf(eth_pairs[1], "%.9s_peer0", ns1->name) >= 0);
143
144         // Delete veth pair if already exists
145         for(i = 0; i < 2; i++) {
146                 assert(sprintf(cmd, "ip link del %s 2>/dev/null", eth_pairs[i]) >= 0);
147                 cmd_ret = system(cmd);
148         }
149
150         // Create veth pair
151         assert(sprintf(cmd, "ip link add %s type veth peer name %s", eth_pairs[0], eth_pairs[1]) >= 0);
152         assert(system(cmd) == 0);
153
154         for(i = 0; i < 2; i++) {
155
156                 // Find interface handle that with it's peer interface
157                 interface =  get_peer_interface_handle(test_state, ns[i], ns[PEER_INDEX]);
158                 assert(interface);
159
160                 if(ns[i]->type != BRIDGE) {
161
162                         // Define interface name
163                         char *if_name;
164
165                         if(interface->if_name) {
166                                 if_name = interface->if_name;
167                         } else {
168                                 assert(sprintf(buff, "eth_%s", interface->if_peer) >= 0);
169                                 if_name = buff;
170                         }
171
172                         interface->if_name = strdup(if_name);
173                         assert(interface->if_name);
174
175                         // Connect one end of the the veth pair to the namespace's interface
176                         assert(sprintf(cmd, "ip link set %s netns %s name %s", eth_pairs[i], ns[i]->name, interface->if_name) >= 0);
177                         assert(system(cmd) == 0);
178                 } else {
179
180                         // Connect one end of the the veth pair to the bridge
181                         assert(sprintf(cmd, "ip link set %s master %s up\n", eth_pairs[i], ns[i]->name) >= 0);
182                         assert(system(cmd) == 0);
183                 }
184
185                 // Mark interfaces as connected
186                 interface->priv = set;
187                 interface = get_peer_interface_handle(test_state, ns[PEER_INDEX], ns[i]);
188                 assert(interface);
189                 interface->priv = set;
190         }
191 }
192
193 void netns_configure_ip_address(netns_state_t *test_state) {
194         int i, if_no, cmd_ret;
195         namespace_t *namespace;
196         interface_t *if_handle;
197         char cmd[200];
198
199         for(i = 0; i < test_state->num_namespaces; i++) {
200                 namespace = get_namespace_handle_by_index(test_state, i);
201
202                 for(if_no = 0; if_no < namespace->interfaces_no; if_no++) {
203                         if_handle = get_interface_handle_by_index(namespace, if_no);
204                         assert(if_handle);
205
206                         if(if_handle->if_addr && namespace->type != BRIDGE) {
207                                 assert(sprintf(cmd, "ip netns exec %s ip addr add %s dev %s", namespace->name, if_handle->if_addr, if_handle->if_name) >= 0);
208                                 assert(system(cmd) == 0);
209                                 assert(sprintf(cmd, "ip netns exec %s ip link set dev %s up", namespace->name, if_handle->if_name) >= 0);
210                                 assert(system(cmd) == 0);
211
212                                 if(if_handle->if_default_route_ip) {
213                                         char *route_ip = ipv4_str_remove_cidr(if_handle->if_default_route_ip);
214                                         assert(sprintf(cmd, "ip netns exec %s ip route add default via %s", namespace->name, route_ip) >= 0);
215                                         assert(system(cmd) == 0);
216                                         free(route_ip);
217                                 }
218                         }
219                 }
220         }
221 }
222
223 void netns_enable_all_nats(netns_state_t *test_state) {
224         int i, j;
225         namespace_t *namespace, *peer_namespace;
226         interface_t *interface_handle;
227         char cmd[200];
228         char *ip_addr;
229
230         for(i = 0; i < test_state->num_namespaces; i++) {
231                 namespace = get_namespace_handle_by_index(test_state, i);
232
233                 if(namespace->type == FULL_CONE) {
234                         assert(namespace->nat_arg);
235                         netns_fullcone_handle_t **nat_rules = namespace->nat_arg;
236                         char *eth0;
237
238                         for(j = 0; nat_rules[j]; j++) {
239                                 assert(nat_rules[j]->snat_to_source && nat_rules[j]->dnat_to_destination);
240
241                                 interface_handle = get_interface_handle_by_name(test_state, namespace, nat_rules[j]->snat_to_source);
242                                 assert(interface_handle);
243                                 eth0 = interface_handle->if_name;
244                                 ip_addr = ipv4_str_remove_cidr(interface_handle->if_addr);
245                                 assert(sprintf(cmd, "ip netns exec %s iptables -t nat -A POSTROUTING -o %s -j SNAT --to-source %s", namespace->name, eth0, ip_addr) >= 0);
246                                 assert(system(cmd) == 0);
247                                 free(ip_addr);
248
249                                 peer_namespace = find_namespace(test_state, nat_rules[j]->dnat_to_destination);
250                                 interface_handle = get_interface_handle_by_name(test_state, peer_namespace, namespace->name);
251                                 assert(interface_handle);
252
253                                 ip_addr = ipv4_str_remove_cidr(interface_handle->if_addr);
254                                 assert(sprintf(cmd, "ip netns exec %s iptables -t nat -A PREROUTING  -i %s -j DNAT --to-destination %s", namespace->name, eth0, ip_addr) >= 0);
255                                 assert(system(cmd) == 0);
256                                 free(ip_addr);
257                         }
258                 }
259         }
260 }
261
262 void netns_create_all_namespaces(netns_state_t *test_state) {
263         int i, j;
264         namespace_t *namespace, *peer_namespace;
265         interface_t *interfaces;
266
267         for(i = 0; i < test_state->num_namespaces; i++) {
268                 namespace = get_namespace_handle_by_index(test_state, i);
269
270                 // Delete the namespace if already exists
271                 netns_delete_namespace(namespace);
272
273                 // Create namespace
274
275                 if(namespace->type != BRIDGE) {
276                         netns_create_namespace(test_state, namespace);
277                 } else {
278                         netns_create_bridge(test_state, namespace);
279                 }
280         }
281 }
282
283 void netns_connect_all_namespaces(netns_state_t *test_state) {
284         int i, j;
285         namespace_t *namespace, *peer_namespace;
286         interface_t *interfaces;
287         interface_t *interface_handle;
288
289         for(i = 0; i < test_state->num_namespaces; i++) {
290                 namespace = get_namespace_handle_by_index(test_state, i);
291                 assert(namespace->interfaces);
292                 interfaces = namespace->interfaces;
293
294                 for(j = 0; j < namespace->interfaces_no; j++) {
295                         peer_namespace = find_namespace(test_state, interfaces[j].if_peer);
296                         assert(peer_namespace);
297                         netns_connect_namespaces(test_state, namespace, peer_namespace);
298                 }
299         }
300
301         // Reset all priv members of the interfaces
302
303         for(i = 0; i < test_state->num_namespaces; i++) {
304                 namespace = get_namespace_handle_by_index(test_state, i);
305                 assert(namespace->interfaces);
306
307                 for(j = 0; j < namespace->interfaces_no; j++) {
308                         interface_handle = get_interface_handle_by_index(namespace, j);
309                         assert(interface_handle);
310                         interface_handle->priv = NULL;
311                 }
312         }
313 }
314
315 void increment_ipv4_str(char *ip_addr, int ip_addr_size) {
316         uint32_t addr_int_n, addr_int_h;
317
318         assert(inet_pton(AF_INET, ip_addr, &addr_int_n) > 0);
319         addr_int_h = ntohl(addr_int_n);
320         addr_int_h = addr_int_h + 1;
321         addr_int_n = htonl(addr_int_h);
322         assert(inet_ntop(AF_INET, &addr_int_n, ip_addr, ip_addr_size));
323 }
324
325 void increment_ipv4_cidr_str(char *ip) {
326         int subnet;
327         assert(sscanf(ip, "%*d.%*d.%*d.%*d/%d", &subnet) >= 0);
328         char *ptr = strchr(ip, '/');
329         *ptr = '\0';
330         increment_ipv4_str(ip, INET6_ADDRSTRLEN);
331         sprintf(ip, "%s/%d", ip, subnet);
332 }
333
334 interface_t *netns_get_priv_addr(netns_state_t *test_state, const char *namespace_name) {
335         namespace_t *namespace_handle;
336         interface_t *interface_handle;
337         int if_no;
338
339         namespace_handle = find_namespace(test_state, namespace_name);
340         assert(namespace_handle);
341
342         for(if_no = 0; if_no < namespace_handle->interfaces_no; if_no++) {
343                 interface_handle = get_interface_handle_by_index(namespace_handle, if_no);
344
345                 if(!strcmp(namespace_handle->name, interface_handle->fetch_ip_netns_name)) {
346                         return interface_handle;
347                 }
348         }
349
350         return NULL;
351 }
352
353 void netns_add_default_route_addr(netns_state_t *test_state) {
354         int ns, if_no;
355         namespace_t *namespace_handle;
356         interface_t *interface_handle, *peer_interface_handle;
357
358         for(ns = 0; ns < test_state->num_namespaces; ns++) {
359                 namespace_handle = get_namespace_handle_by_index(test_state, ns);
360                 assert(namespace_handle);
361
362                 if(namespace_handle->type != HOST) {
363                         continue;
364                 }
365
366                 for(if_no = 0; if_no < namespace_handle->interfaces_no; if_no++) {
367                         interface_handle = get_interface_handle_by_index(namespace_handle, if_no);
368
369                         if(interface_handle->if_default_route_ip == NULL) {
370                                 peer_interface_handle = netns_get_priv_addr(test_state, interface_handle->fetch_ip_netns_name);
371                                 assert(peer_interface_handle);
372                                 interface_handle->if_default_route_ip  = ipv4_str_remove_cidr(peer_interface_handle->if_addr);
373                         } else {
374                                 char *dup = strdup(interface_handle->if_default_route_ip);
375                                 assert(dup);
376                                 interface_handle->if_default_route_ip = dup;
377                         }
378                 }
379         }
380 }
381
382 void netns_assign_ip_addresses(netns_state_t *test_state) {
383         int ns, j;
384         namespace_t *namespace_handle;
385         interface_t *interface_handle, *peer_interface_handle;
386         int sub_net;
387
388
389         char *addr = malloc(INET6_ADDRSTRLEN);
390         assert(addr);
391
392         if(test_state->public_net_addr) {
393                 assert(strncpy(addr, test_state->public_net_addr, INET6_ADDRSTRLEN));
394         } else {
395                 assert(strncpy(addr, DEFAULT_PUB_NET_ADDR, INET6_ADDRSTRLEN));
396         }
397
398         test_state->public_net_addr = addr;
399
400         for(ns = 0; ns < test_state->num_namespaces; ns++) {
401                 namespace_handle = get_namespace_handle_by_index(test_state, ns);
402                 assert(namespace_handle);
403
404                 if(namespace_handle->type == BRIDGE) {
405                         continue;
406                 }
407
408                 for(j = 0; j < namespace_handle->interfaces_no; j++) {
409                         interface_handle = get_interface_handle_by_index(namespace_handle, j);
410                         assert(interface_handle);
411
412                         if(interface_handle->if_addr) {
413                                 continue;
414                         }
415
416                         // If fetch ip net namespace name is given get IP address from it, else get a public IP address
417
418                         if(interface_handle->fetch_ip_netns_name) {
419                                 namespace_t *gw_netns_handle = find_namespace(test_state, interface_handle->fetch_ip_netns_name);
420                                 assert(gw_netns_handle);
421                                 assert(gw_netns_handle->static_config_net_addr);
422
423                                 increment_ipv4_cidr_str(gw_netns_handle->static_config_net_addr);
424                                 interface_handle->if_addr = strdup(gw_netns_handle->static_config_net_addr);
425                         } else {
426                                 increment_ipv4_cidr_str(test_state->public_net_addr);
427                                 interface_handle->if_addr = strdup(test_state->public_net_addr);
428
429                                 if(namespace_handle->type == HOST) {
430                                         if(interface_handle->if_default_route_ip) {
431                                                 char *dup = strdup(interface_handle->if_default_route_ip);
432                                                 assert(dup);
433                                                 interface_handle->if_default_route_ip = dup;
434                                         } else {
435                                                 interface_handle->if_default_route_ip = strdup(DEFAULT_GATEWAY_NET_ADDR);
436                                         }
437                                 }
438                         }
439                 }
440         }
441
442         netns_add_default_route_addr(test_state);
443 }
444
445 static void netns_namespace_init_pids(netns_state_t *test_state) {
446         int if_no;
447         namespace_t *namespace_handle;
448
449         for(if_no = 0; if_no < test_state->num_namespaces; if_no++) {
450                 namespace_handle = get_namespace_handle_by_index(test_state, if_no);
451                 assert(namespace_handle);
452                 namespace_handle->pid_nos = 0;
453                 namespace_handle->pids = NULL;
454         }
455 }
456
457 pid_t run_cmd_in_netns(netns_state_t *test_state, char *namespace_name, char *cmd_str) {
458         pid_t pid;
459         namespace_t *namespace_handle;
460         char cmd[1000];
461
462         assert(namespace_name && cmd_str);
463         namespace_handle = find_namespace(test_state, namespace_name);
464         assert(namespace_handle);
465
466         if((pid = fork()) == 0) {
467                 assert(daemon(1, 0) != -1);
468                 assert(sprintf(cmd, "ip netns exec %s %s", namespace_name, cmd_str) >= 0);
469                 assert(system(cmd) == 0);
470                 exit(0);
471         }
472
473         pid_t *pid_ptr;
474         pid_ptr = realloc(namespace_handle->pids, (namespace_handle->pid_nos + 1) * sizeof(pid_t));
475         assert(pid_ptr);
476         namespace_handle->pids = pid_ptr;
477         (namespace_handle->pids)[namespace_handle->pid_nos] = pid;
478         namespace_handle->pid_nos = namespace_handle->pid_nos + 1;
479
480         return pid;
481 }
482
483 static void *pthread_fun(void *arg) {
484         netns_thread_t *netns_arg = (netns_thread_t *)arg;
485         char namespace_path[100];
486         void *ret;
487         assert(sprintf(namespace_path, "/var/run/netns/%s", netns_arg->namespace_name) >= 0);
488         int fd = open(namespace_path, O_RDONLY);
489         assert(fd != -1);
490         assert(setns(fd, CLONE_NEWNET) != -1);
491
492         ret = (netns_arg->netns_thread)(netns_arg->arg);
493         pthread_detach(netns_arg->thread_handle);
494         pthread_exit(ret);
495 }
496
497 void run_node_in_namespace_thread(netns_thread_t *netns_arg) {
498         assert(netns_arg->namespace_name && netns_arg->netns_thread);
499         assert(!pthread_create(&(netns_arg->thread_handle), NULL, pthread_fun, netns_arg));
500 }
501
502 void netns_destroy_topology(netns_state_t *test_state) {
503         namespace_t *namespace_handle;
504         interface_t *interface_handle;
505         int if_no, j, i;
506         pid_t pid, pid_ret;
507
508         for(if_no = 0; if_no < test_state->num_namespaces; if_no++) {
509                 namespace_handle = get_namespace_handle_by_index(test_state, if_no);
510                 assert(namespace_handle->interfaces);
511
512                 for(i = 0; i < namespace_handle->pid_nos; i++) {
513                         pid = (namespace_handle->pids)[i];
514                         assert(kill(pid, SIGINT) != -1);
515                         pid_ret = waitpid(pid, NULL, WNOHANG);
516                         assert(pid_ret != -1);
517
518                         if(pid_ret == 0) {
519                                 fprintf(stderr, "pid: %d, is still running\n", pid);
520                         }
521                 }
522
523                 // Free interface name, interface address, interface default address etc.,
524                 // which are dynamically allocated and set the values to NULL
525
526                 for(j = 0; j < namespace_handle->interfaces_no; j++) {
527                         interface_handle = get_interface_handle_by_index(namespace_handle, j);
528                         assert(interface_handle);
529
530                         free(interface_handle->if_name);
531                         interface_handle->if_name = NULL;
532                         free(interface_handle->if_addr);
533                         interface_handle->if_addr = NULL;
534                         free(interface_handle->if_default_route_ip);
535                         interface_handle->if_default_route_ip = NULL;
536                 }
537
538                 // Delete namespace
539                 assert(netns_delete_namespace(namespace_handle) == 0);
540         }
541
542         free(test_state->public_net_addr);
543         test_state->public_net_addr = NULL;
544 }
545
546 bool netns_create_topology(netns_state_t *test_state) {
547
548         // (Re)create name-spaces and bridges
549         netns_create_all_namespaces(test_state);
550
551         // Connect namespaces and bridges(if any) with their interfaces
552         netns_connect_all_namespaces(test_state);
553
554         // Assign IP addresses for the interfaces in namespaces
555         netns_assign_ip_addresses(test_state);
556
557         // Configure assigned IP addresses with the interfaces in netns
558         netns_configure_ip_address(test_state);
559
560         // Enable all NATs
561         netns_enable_all_nats(test_state);
562
563         netns_namespace_init_pids(test_state);
564
565         return true;
566 }