diff options
| author | Frediano Ziglio <fziglio@redhat.com> | 2016-10-11 13:05:57 +0100 |
|---|---|---|
| committer | Frediano Ziglio <fziglio@redhat.com> | 2016-10-11 13:06:15 +0100 |
| commit | 5fe7fcb3d758b8cd1e73de153ef3dacdf25379aa (patch) | |
| tree | c5e30c9919c868a1897a9f6ba9c88ac1140e1cd5 | |
| parent | 7f3912b19cbc8a3865d5d24cde179af76d324a72 (diff) | |
Make test work even for remote case
Use network namespaces to test the remote case using
a single machine.
Server is run in a subprocess with a different namespace.
Client and server are connected with a veth interface.
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
| -rw-r--r-- | tests/bandwidth.c | 21 | ||||
| -rw-r--r-- | tests/common.c | 160 | ||||
| -rw-r--r-- | tests/common.h | 4 | ||||
| -rw-r--r-- | tests/delay.c | 21 | ||||
| -rw-r--r-- | tests/ping.c | 4 |
5 files changed, 186 insertions, 24 deletions
diff --git a/tests/bandwidth.c b/tests/bandwidth.c index a422de4..564ded3 100644 --- a/tests/bandwidth.c +++ b/tests/bandwidth.c @@ -12,6 +12,7 @@ static unsigned current_bw = 0; static int udp_socks[2] = { -1, -1 }; +static bool remote = false; typedef struct { uint8_t data[1024]; @@ -111,7 +112,10 @@ test_bandwidth(unsigned bw) unsigned expected = 1024 * 1024 * bw / 8 / 10 + 1 * (1024 + MIN_IP_UDP_HEADER); // launch program with given latency - launch_latency("10 %uMbit --framing-bytes 0", bw); + if (remote) + launch_latency_remote("10 %uMbit --framing-bytes 0", bw); + else + launch_latency("10 %uMbit --framing-bytes 0", bw); create_udp_pair(udp_socks); // one direction @@ -139,13 +143,22 @@ test_bandwidth(unsigned bw) kill_latency(); } -int main(void) +static void +all_tests(void) { - printf("Testing bandwidth limitation\n"); - test_bandwidth(2); test_bandwidth(4); test_bandwidth(8); test_bandwidth(16); +} + +int main(void) +{ + printf("Testing bandwidth limitation\n"); + + all_tests(); + remote = true; + all_tests(); + return 0; } diff --git a/tests/common.c b/tests/common.c index d103f1d..2155280 100644 --- a/tests/common.c +++ b/tests/common.c @@ -1,11 +1,36 @@ #include "common.h" #include <stdarg.h> #include <errno.h> +#include <err.h> #include <signal.h> +#include <sched.h> #include <sys/wait.h> #include <arpa/inet.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> static pid_t latency_pid = -1; +static pid_t server_pid = -1; +static bool cleanup_registered = false; + +static void +cleanup_atexit(void) +{ + if (latency_pid != -1) + kill(SIGKILL, latency_pid); + if (server_pid != -1) + kill(SIGKILL, server_pid); +} + +static void +register_cleanup(void) +{ + if (cleanup_registered) + return; + atexit(cleanup_atexit); + cleanup_registered = true; +} bool latency_running(void) @@ -16,7 +41,7 @@ latency_running(void) int sock = socket(AF_INET, SOCK_DGRAM, 0); assert(sock >= 0); setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &socktrue, sizeof(socktrue)); - setup_addr(&addr, "192.168.127.2", 0); + setup_addr(&addr, "192.168.127.0", 0); bool res; if (bind(sock, &addr.generic, sizeof(addr)) == 0) { res = true; @@ -28,9 +53,20 @@ latency_running(void) return res; } -void -launch_latency(const char *fmt, ...) +static int +get_process_netns(pid_t pid) +{ + char ns_path[128]; + sprintf(ns_path, "/proc/%u/ns/net", (unsigned) pid); + int ns = open(ns_path, O_RDONLY); + assert(ns >= 0); + return ns; +} + +static void +launch_latency_client(bool local, const char *fmt, va_list ap) { + register_cleanup(); assert(latency_pid == -1); while (latency_running()) { @@ -39,14 +75,14 @@ launch_latency(const char *fmt, ...) } char cmd[1024]; - va_list ap; - strcpy(cmd, "exec ../latency "); + if (local) + strcpy(cmd, "exec ../latency "); + else + strcpy(cmd, "exec ../latency --client 192.168.128.2 "); size_t cmd_len = strlen(cmd); - va_start(ap, fmt); vsnprintf(cmd + cmd_len, sizeof(cmd) - cmd_len, fmt, ap); - va_end(ap); printf("starting %s\n", cmd); latency_pid = fork(); @@ -66,31 +102,103 @@ launch_latency(const char *fmt, ...) usleep(50000); } +void +launch_latency(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + launch_latency_client(true, fmt, ap); + va_end(ap); +} + +void +launch_latency_remote(const char *fmt, ...) +{ + register_cleanup(); + assert(latency_pid == -1 && server_pid == -1); + + if (unshare(CLONE_NEWNET)) + err(1, "unshare"); + assert(system("ifconfig lo 127.0.0.1 netmask 255.255.255.0 up") == 0); + + int pipe_fds[2]; + + assert(pipe(pipe_fds) == 0); + + server_pid = fork(); + assert(server_pid != -1); + + char c; + if (server_pid == 0) { + char cmd[256]; + + close(pipe_fds[0]); + pipe_fds[0] = -1; + + if (unshare(CLONE_NEWNET)) + err(1, "unshare"); + assert(system("ifconfig lo 127.0.0.1 netmask 255.255.255.0 up") == 0); + sprintf(cmd, "ip link add server type veth peer name client netns %d", (int) getppid()); + assert(system(cmd) == 0); + assert(system("ifconfig server 192.168.128.2 netmask 255.255.255.0 up") == 0); + c = 'x'; + write(pipe_fds[1], &c, 1); + close(pipe_fds[1]); + execl("../latency", "latency", "--server", "--framing-bytes", "0", NULL); + exit(1); + } + + close(pipe_fds[1]); + pipe_fds[1] = -1; + assert(read(pipe_fds[0], &c, 1) == 1); + assert(c == 'x'); + assert(system("ifconfig client 192.168.128.3 netmask 255.255.255.0 up") == 0); + + va_list ap; + va_start(ap, fmt); + launch_latency_client(false, fmt, ap); + va_end(ap); +} + static void handle_alarm(int sig) { } -void -kill_latency(void) +static void +kill_pid(pid_t *p_pid) { - assert(latency_pid != -1); - kill(latency_pid, SIGTERM); + assert(*p_pid != -1); + kill(*p_pid, SIGTERM); // handle some timeout signal(SIGALRM, handle_alarm); alarm(1); int status; - pid_t pid = waitpid(latency_pid, &status, 0); + pid_t pid = waitpid(*p_pid, &status, 0); alarm(0); signal(SIGALRM, SIG_DFL); - assert(pid == latency_pid); + assert(pid == *p_pid); assert(WIFEXITED(status)); assert(WEXITSTATUS(status) == 0); - latency_pid = -1; + *p_pid = -1; +} + +void +kill_latency(void) +{ + kill_pid(&latency_pid); + if (server_pid != -1) { + kill_pid(&server_pid); + + int parent_ns = get_process_netns(getppid()); + assert(setns(parent_ns, 0) == 0); + close(parent_ns); + } } void @@ -123,20 +231,40 @@ create_udp_pair(int socks[2]) assert(getsockname(sock, &addr.generic, &addr_len) == 0); ports[0] = ntohs(addr.inet.sin_port); + const char *remote_listen_ip = "192.168.127.2"; + const char *remote_connect_ip = "192.168.127.3"; + + int save_ns = -1; + if (server_pid != -1) { + save_ns = get_process_netns(getpid()); + + int server_ns = get_process_netns(server_pid); + assert(setns(server_ns, 0) == 0); + close(server_ns); + + remote_listen_ip = "192.168.127.0"; + remote_connect_ip = "192.168.127.1"; + } + sock = socket(AF_INET, SOCK_DGRAM, 0); assert(sock >= 0); socks[1] = sock; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &socktrue, sizeof(socktrue)); - setup_addr(&addr, "192.168.127.2", 0); + setup_addr(&addr, remote_listen_ip, 0); assert(bind(sock, &addr.generic, sizeof(addr)) == 0); addr_len = sizeof(addr); assert(getsockname(sock, &addr.generic, &addr_len) == 0); ports[1] = ntohs(addr.inet.sin_port); + if (save_ns != -1) { + assert(setns(save_ns, 0) == 0); + close(save_ns); + } + // make a pair from the above ones setup_addr(&addr, "192.168.127.1", ports[1]); assert(connect(socks[0], &addr.generic, sizeof(addr)) == 0); - setup_addr(&addr, "192.168.127.3", ports[0]); + setup_addr(&addr, remote_connect_ip, ports[0]); assert(connect(socks[1], &addr.generic, sizeof(addr)) == 0); } diff --git a/tests/common.h b/tests/common.h index 9c72998..a6d11b3 100644 --- a/tests/common.h +++ b/tests/common.h @@ -1,4 +1,5 @@ #undef NDEBUG +#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <stdbool.h> @@ -15,6 +16,9 @@ bool latency_running(void); /** launch a program with given parameters */ void launch_latency(const char *fmt, ...); +/** launch a program with given parameters */ +void launch_latency_remote(const char *fmt, ...); + /** kill latency process */ void kill_latency(void); diff --git a/tests/delay.c b/tests/delay.c index aea5512..9202f57 100644 --- a/tests/delay.c +++ b/tests/delay.c @@ -6,6 +6,7 @@ static unsigned test_num = 0; static int udp_socks[2] = { -1, -1 }; static const char payload_id[8] = "DELAY\0\0"; +static bool remote = false; typedef struct { char id[8]; @@ -43,7 +44,10 @@ test_latency(unsigned latency) { ++test_num; // launch program with given latency - launch_latency("%u 100M", latency); + if (remote) + launch_latency_remote("%u 100M", latency); + else + launch_latency("%u 100M", latency); create_udp_pair(udp_socks); // send some payload and wait @@ -79,13 +83,22 @@ test_latency(unsigned latency) kill_latency(); } -int main(void) +static void +all_tests(void) { - printf("Testing delay introduced is correct\n"); - test_latency(10); test_latency(100); test_latency(200); test_latency(280); +} + +int main(void) +{ + printf("Testing delay introduced is correct\n"); + + all_tests(); + remote = true; + all_tests(); + return 0; } diff --git a/tests/ping.c b/tests/ping.c index 95831fc..ae7bb37 100644 --- a/tests/ping.c +++ b/tests/ping.c @@ -8,5 +8,9 @@ int main(void) launch_latency("10 100M"); assert(system("ping -c1 192.168.127.1") == 0); kill_latency(); + + launch_latency_remote("10 100M"); + assert(system("ping -c1 192.168.127.1") == 0); + kill_latency(); return 0; } |
