2 test_optimal_pmtu.c -- Execution of specific meshlink black box test cases
3 Copyright (C) 2019 Guus Sliepen <guus@meshlink.io>
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.
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.
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.
19 #include "network_namespace_framework.h"
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
29 static int ipv4_str_check_cidr(const char *ip_addr) {
31 sscanf(ip_addr, "%*d.%*d.%*d.%*d/%d", &cidr);
35 static char *ipv4_str_remove_cidr(const char *ipv4_addr) {
36 char *ptr = strdup(ipv4_addr);
39 if(ipv4_str_check_cidr(ptr)) {
40 char *end = strchr(ptr, '/');
47 namespace_t *find_namespace(netns_state_t *state, const char *namespace_name) {
50 for(i = 0; i < state->num_namespaces; i++) {
51 if(!strcmp((state->namespaces[i]).name, namespace_name)) {
52 return &(state->namespaces[i]);
59 static int netns_delete_namespace(namespace_t *namespace_handle) {
62 if(namespace_handle->type != BRIDGE) {
63 assert(sprintf(cmd, "ip netns del %s 2>/dev/null", namespace_handle->name) >= 0);
65 assert(sprintf(cmd, "ip link del %s 2>/dev/null", namespace_handle->name) >= 0);
71 /* Create new network namespace using namespace handle */
72 static void netns_create_namespace(netns_state_t *test_state, namespace_t *namespace_handle) {
76 // Add the network namespace
78 sprintf(cmd, "ip netns add %s", namespace_handle->name);
79 assert(system(cmd) == 0);
81 sprintf(cmd, "ip netns exec %s ip link set dev lo up", namespace_handle->name);
82 assert(system(cmd) == 0);
85 static void netns_create_bridge(netns_state_t *test_state, namespace_t *namespace_handle) {
89 sprintf(cmd, "ip link add name %s type bridge", namespace_handle->name);
90 assert(system(cmd) == 0);
92 sprintf(cmd, "ip link set %s up", namespace_handle->name);
93 assert(system(cmd) == 0);
96 interface_t *get_peer_interface_handle(netns_state_t *test_state, namespace_t *namespace, namespace_t *peer_namespace) {
98 interface_t *interfaces = namespace->interfaces;
99 int if_no = namespace->interfaces_no;
100 char *peer_name = peer_namespace->name;
102 for(i = 0; i < if_no; i++) {
103 if(!strcasecmp(interfaces[i].if_peer, peer_name)) {
104 return &interfaces[i];
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);
116 return get_peer_interface_handle(test_state, namespace, peer_ns);
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);
125 return iface->priv || peer_iface->priv;
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;
136 // Check if visited already
137 if(check_interfaces_visited(test_state, ns1, ns2)) {
141 assert(sprintf(eth_pairs[0], "%.9s_eth0", ns2->name) >= 0);
142 assert(sprintf(eth_pairs[1], "%.9s_peer0", ns1->name) >= 0);
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);
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);
154 for(i = 0; i < 2; i++) {
156 // Find interface handle that with it's peer interface
157 interface = get_peer_interface_handle(test_state, ns[i], ns[PEER_INDEX]);
160 if(ns[i]->type != BRIDGE) {
162 // Define interface name
165 if(interface->if_name) {
166 if_name = interface->if_name;
168 assert(sprintf(buff, "eth_%s", interface->if_peer) >= 0);
172 interface->if_name = strdup(if_name);
173 assert(interface->if_name);
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);
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);
185 // Mark interfaces as connected
186 interface->priv = set;
187 interface = get_peer_interface_handle(test_state, ns[PEER_INDEX], ns[i]);
189 interface->priv = set;
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;
199 for(i = 0; i < test_state->num_namespaces; i++) {
200 namespace = get_namespace_handle_by_index(test_state, i);
202 for(if_no = 0; if_no < namespace->interfaces_no; if_no++) {
203 if_handle = get_interface_handle_by_index(namespace, if_no);
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);
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);
223 void netns_enable_all_nats(netns_state_t *test_state) {
225 namespace_t *namespace, *peer_namespace;
226 interface_t *interface_handle;
230 for(i = 0; i < test_state->num_namespaces; i++) {
231 namespace = get_namespace_handle_by_index(test_state, i);
233 if(namespace->type == FULL_CONE) {
234 assert(namespace->nat_arg);
235 netns_fullcone_handle_t **nat_rules = namespace->nat_arg;
238 for(j = 0; nat_rules[j]; j++) {
239 assert(nat_rules[j]->snat_to_source && nat_rules[j]->dnat_to_destination);
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);
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);
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);
262 void netns_create_all_namespaces(netns_state_t *test_state) {
264 namespace_t *namespace, *peer_namespace;
265 interface_t *interfaces;
267 for(i = 0; i < test_state->num_namespaces; i++) {
268 namespace = get_namespace_handle_by_index(test_state, i);
270 // Delete the namespace if already exists
271 netns_delete_namespace(namespace);
275 if(namespace->type != BRIDGE) {
276 netns_create_namespace(test_state, namespace);
278 netns_create_bridge(test_state, namespace);
283 void netns_connect_all_namespaces(netns_state_t *test_state) {
285 namespace_t *namespace, *peer_namespace;
286 interface_t *interfaces;
287 interface_t *interface_handle;
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;
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);
301 // Reset all priv members of the interfaces
303 for(i = 0; i < test_state->num_namespaces; i++) {
304 namespace = get_namespace_handle_by_index(test_state, i);
305 assert(namespace->interfaces);
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;
315 void increment_ipv4_str(char *ip_addr, int ip_addr_size) {
316 uint32_t addr_int_n, addr_int_h;
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));
325 void increment_ipv4_cidr_str(char *ip) {
327 assert(sscanf(ip, "%*d.%*d.%*d.%*d/%d", &subnet) >= 0);
328 char *ptr = strchr(ip, '/');
330 increment_ipv4_str(ip, INET6_ADDRSTRLEN);
331 sprintf(ip, "%s/%d", ip, subnet);
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;
339 namespace_handle = find_namespace(test_state, namespace_name);
340 assert(namespace_handle);
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);
345 if(!strcmp(namespace_handle->name, interface_handle->fetch_ip_netns_name)) {
346 return interface_handle;
353 void netns_add_default_route_addr(netns_state_t *test_state) {
355 namespace_t *namespace_handle;
356 interface_t *interface_handle, *peer_interface_handle;
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);
362 if(namespace_handle->type != HOST) {
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);
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);
374 char *dup = strdup(interface_handle->if_default_route_ip);
376 interface_handle->if_default_route_ip = dup;
382 void netns_assign_ip_addresses(netns_state_t *test_state) {
384 namespace_t *namespace_handle;
385 interface_t *interface_handle, *peer_interface_handle;
389 char *addr = malloc(INET6_ADDRSTRLEN);
392 if(test_state->public_net_addr) {
393 assert(strncpy(addr, test_state->public_net_addr, INET6_ADDRSTRLEN));
395 assert(strncpy(addr, DEFAULT_PUB_NET_ADDR, INET6_ADDRSTRLEN));
398 test_state->public_net_addr = addr;
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);
404 if(namespace_handle->type == BRIDGE) {
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);
412 if(interface_handle->if_addr) {
416 // If fetch ip net namespace name is given get IP address from it, else get a public IP address
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);
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);
426 increment_ipv4_cidr_str(test_state->public_net_addr);
427 interface_handle->if_addr = strdup(test_state->public_net_addr);
429 if(namespace_handle->type == HOST) {
430 if(interface_handle->if_default_route_ip) {
431 char *dup = strdup(interface_handle->if_default_route_ip);
433 interface_handle->if_default_route_ip = dup;
435 interface_handle->if_default_route_ip = strdup(DEFAULT_GATEWAY_NET_ADDR);
442 netns_add_default_route_addr(test_state);
445 static void netns_namespace_init_pids(netns_state_t *test_state) {
447 namespace_t *namespace_handle;
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;
457 pid_t run_cmd_in_netns(netns_state_t *test_state, char *namespace_name, char *cmd_str) {
459 namespace_t *namespace_handle;
462 assert(namespace_name && cmd_str);
463 namespace_handle = find_namespace(test_state, namespace_name);
464 assert(namespace_handle);
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);
474 pid_ptr = realloc(namespace_handle->pids, (namespace_handle->pid_nos + 1) * sizeof(pid_t));
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;
483 static void *pthread_fun(void *arg) {
484 netns_thread_t *netns_arg = (netns_thread_t *)arg;
485 char namespace_path[100];
487 assert(sprintf(namespace_path, "/var/run/netns/%s", netns_arg->namespace_name) >= 0);
488 int fd = open(namespace_path, O_RDONLY);
490 assert(setns(fd, CLONE_NEWNET) != -1);
492 ret = (netns_arg->netns_thread)(netns_arg->arg);
493 pthread_detach(netns_arg->thread_handle);
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));
502 void netns_destroy_topology(netns_state_t *test_state) {
503 namespace_t *namespace_handle;
504 interface_t *interface_handle;
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);
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);
519 fprintf(stderr, "pid: %d, is still running\n", pid);
523 // Free interface name, interface address, interface default address etc.,
524 // which are dynamically allocated and set the values to NULL
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);
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;
539 assert(netns_delete_namespace(namespace_handle) == 0);
542 free(test_state->public_net_addr);
543 test_state->public_net_addr = NULL;
546 bool netns_create_topology(netns_state_t *test_state) {
548 // (Re)create name-spaces and bridges
549 netns_create_all_namespaces(test_state);
551 // Connect namespaces and bridges(if any) with their interfaces
552 netns_connect_all_namespaces(test_state);
554 // Assign IP addresses for the interfaces in namespaces
555 netns_assign_ip_addresses(test_state);
557 // Configure assigned IP addresses with the interfaces in netns
558 netns_configure_ip_address(test_state);
561 netns_enable_all_nats(test_state);
563 netns_namespace_init_pids(test_state);