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