]> git.meshlink.io Git - meshlink/commitdiff
Add a metering test. feature/improved-counters test/metering-better-pmtu
authorGuus Sliepen <guus@meshlink.io>
Thu, 9 Sep 2021 18:11:16 +0000 (20:11 +0200)
committerGuus Sliepen <guus@meshlink.io>
Thu, 9 Sep 2021 18:11:16 +0000 (20:11 +0200)
This checks bandwidth usage for several minutes while doing PMTU probing,
being idle, and transferring data over a channel via a relay.

test/Makefile.am
test/metering.c [new file with mode: 0644]
test/netns_utils.c
test/netns_utils.h

index 65834bb63a006c4dbccb37079ad7b48fe7da55a7..f5f4cdc5d034202b8516accd159d6ca9fb0aace3 100644 (file)
@@ -20,6 +20,7 @@ TESTS = \
        get-all-nodes \
        import-export \
        invite-join \
+       metering \
        meta-connections \
        sign-verify \
        storage-policy \
@@ -64,6 +65,7 @@ check_PROGRAMS = \
        get-all-nodes \
        import-export \
        invite-join \
+       metering \
        meta-connections \
        sign-verify \
        storage-policy \
@@ -144,6 +146,9 @@ import_export_LDADD = $(top_builddir)/src/libmeshlink.la
 invite_join_SOURCES = invite-join.c utils.c utils.h
 invite_join_LDADD = $(top_builddir)/src/libmeshlink.la
 
+metering_SOURCES = metering.c netns_utils.c netns_utils.h utils.c utils.h
+metering_LDADD = $(top_builddir)/src/libmeshlink.la
+
 meta_connections_SOURCES = meta-connections.c netns_utils.c netns_utils.h utils.c utils.h
 meta_connections_LDADD = $(top_builddir)/src/libmeshlink.la
 
diff --git a/test/metering.c b/test/metering.c
new file mode 100644 (file)
index 0000000..e302ead
--- /dev/null
@@ -0,0 +1,141 @@
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "meshlink.h"
+#include "devtools.h"
+#include "netns_utils.h"
+#include "utils.h"
+
+static struct sync_flag peer_reachable;
+static struct sync_flag aio_done;
+static const size_t size = 10000000;
+static char *buffer;
+
+static void nut_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
+       (void)mesh;
+
+       if(reachable && !strcmp(node->name, "peer")) {
+               set_sync_flag(&peer_reachable, true);
+       }
+}
+
+static void aio_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len, void *priv) {
+       (void)mesh;
+       (void)channel;
+       (void)data;
+       (void)len;
+       (void)priv;
+
+       set_sync_flag(&aio_done, true);
+}
+
+static void peer_aio_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len, void *priv) {
+       (void)mesh;
+       (void)channel;
+       (void)data;
+       (void)len;
+       (void)priv;
+
+       meshlink_channel_close(mesh, channel);
+}
+
+static bool accept_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
+       (void)port;
+       (void)data;
+       (void)len;
+
+       assert(buffer);
+       assert(meshlink_channel_aio_receive(mesh, channel, buffer, size, peer_aio_cb, NULL));
+       return true;
+}
+
+static void print_counters(peer_config_t *peers, const char *description) {
+       printf("%s:\n", description);
+       printf("        %9s %9s %9s %9s %9s %9s\n",
+              "in data",
+              "forward",
+              "meta",
+              "out data",
+              "forward",
+              "meta");
+
+       for(int i = 0; i < 3; i++) {
+               meshlink_node_t *node = meshlink_get_node(peers[0].mesh, peers[i].name);
+               assert(node);
+               struct devtool_node_status status;
+               devtool_reset_node_counters(peers[0].mesh, node, &status);
+               printf(" %5s: %9" PRIu64 " %9" PRIu64 " %9" PRIu64 " %9" PRIu64 " %9" PRIu64 " %9" PRIu64 "\n",
+                      node->name,
+                      status.in_data,
+                      status.in_forward,
+                      status.in_meta,
+                      status.out_data,
+                      status.out_forward,
+                      status.out_meta);
+       }
+}
+
+
+int main(void) {
+       meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
+
+       init_sync_flag(&peer_reachable);
+       init_sync_flag(&aio_done);
+
+       // Set up relay, peer and NUT
+       peer_config_t *peers = setup_relay_peer_nut_indirect("metering");
+
+       meshlink_set_node_status_cb(peers[2].mesh, nut_status_cb);
+
+       for(int i = 0; i < 3; i++) {
+               assert(meshlink_start(peers[i].mesh));
+       }
+
+       // Measure traffic after 1 minute of PMTU probing
+       sleep(60);
+       print_counters(peers, "PMTU probing (1 min)");
+
+       // Measure traffic after 1 minute of idle
+       for(int i = 0; i < 10; i++) {
+               sleep(60);
+               print_counters(peers, "Idle (1 min)");
+       }
+
+       // Measure channel traffic between relay and peer
+       buffer = calloc(1, size);
+       assert(buffer);
+       meshlink_node_t *peer = meshlink_get_node(peers[0].mesh, peers[1].name);
+       assert(peer);
+       meshlink_set_channel_accept_cb(peers[1].mesh, accept_cb);
+       meshlink_channel_t *channel = meshlink_channel_open(peers[0].mesh, peer, 1, NULL, NULL, 0);
+       assert(channel);
+       assert(meshlink_channel_aio_send(peers[0].mesh, channel, buffer, size, aio_cb, NULL));
+       assert(wait_sync_flag(&aio_done, 15));
+       meshlink_channel_close(peers[0].mesh, channel);
+       sleep(1);
+       print_counters(peers, "relay->peer channel traffic");
+
+       // Measure channel traffic between NUT and peer
+       assert(wait_sync_flag(&peer_reachable, 5));
+       meshlink_node_t *nut = meshlink_get_node(peers[0].mesh, peers[2].name);
+       assert(nut);
+       peer = meshlink_get_node(peers[2].mesh, peers[1].name);
+       assert(peer);
+       channel = meshlink_channel_open(peers[2].mesh, peer, 1, NULL, NULL, 0);
+       assert(channel);
+       init_sync_flag(&aio_done);
+       assert(meshlink_channel_aio_send(peers[2].mesh, channel, buffer, size, aio_cb, NULL));
+       assert(wait_sync_flag(&aio_done, 15));
+       meshlink_channel_close(peers[2].mesh, channel);
+       sleep(1);
+       print_counters(peers, "NUT->peer channel traffic");
+
+       close_relay_peer_nut(peers);
+}
index d957d5b63386640e622821ef673ec45cb1b3e41b..70fa3130df7b68672e03505b023be5d249999931 100644 (file)
@@ -92,6 +92,26 @@ static void setup_lan_topology(peer_config_t *peers, int npeers) {
        }
 }
 
+/// Set up an indirect topology where all peers can only access the relay
+static void setup_indirect_topology(peer_config_t *peers, int npeers) {
+       // Add an interface to each peer that is connected to the relay
+       for(int i = 1; i < npeers; i++) {
+               char *command = NULL;
+               assert(asprintf(&command,
+                               "/bin/ip netns exec %1$s /bin/ip link add eth0 type veth peer eth%3$d netns %2$s;"
+                               "/bin/ip netns exec %1$s ip addr flush dev eth0;"
+                               "/bin/ip netns exec %1$s ip addr add 192.168.%3$d.2/24 dev eth0;"
+                               "/bin/ip netns exec %1$s /bin/ip link set dev eth0 up;"
+                               "/bin/ip netns exec %2$s ip addr flush dev eth%3$d;"
+                               "/bin/ip netns exec %2$s ip addr add 192.168.%3$d.1/24 dev eth%3$d;"
+                               "/bin/ip netns exec %2$s /bin/ip link set dev eth%3$d up;",
+                               peers[i].netns_name, peers[0].netns_name, i));
+               assert(command);
+               assert(system(command) == 0);
+               free(command);
+       }
+}
+
 /// Give a peer a unique IP address
 void change_peer_ip(peer_config_t *peer) {
        char *command = NULL;
@@ -112,6 +132,7 @@ static void invite_peers(peer_config_t *peers, int npeers) {
        for(int i = 1; i < npeers; i++) {
                char *invitation = meshlink_invite_ex(peers[0].mesh, NULL, peers[i].name, MESHLINK_INVITE_LOCAL | MESHLINK_INVITE_NUMERIC);
                assert(invitation);
+               printf("%s\n", invitation);
                assert(meshlink_join(peers[i].mesh, invitation));
                free(invitation);
        }
@@ -131,9 +152,9 @@ static void close_peers(peer_config_t *peers, int npeers) {
 /// Set up relay, peer and NUT that are directly connected
 peer_config_t *setup_relay_peer_nut(const char *prefix) {
        static peer_config_t peers[] = {
-               {"relay", DEV_CLASS_BACKBONE},
-               {"peer", DEV_CLASS_STATIONARY},
-               {"nut", DEV_CLASS_STATIONARY},
+               {"relay", DEV_CLASS_BACKBONE, NULL, 0, NULL},
+               {"peer", DEV_CLASS_STATIONARY, NULL, 0, NULL},
+               {"nut", DEV_CLASS_STATIONARY, NULL, 0, NULL},
        };
 
        create_peers(peers, 3, prefix);
@@ -143,6 +164,23 @@ peer_config_t *setup_relay_peer_nut(const char *prefix) {
        return peers;
 }
 
+/// Set up relay, peer and NUT that are directly connected
+peer_config_t *setup_relay_peer_nut_indirect(const char *prefix) {
+       static peer_config_t peers[] = {
+               {"relay", DEV_CLASS_BACKBONE, NULL, 0, NULL},
+               {"peer", DEV_CLASS_STATIONARY, NULL, 0, NULL},
+               {"nut", DEV_CLASS_STATIONARY, NULL, 0, NULL},
+       };
+
+       create_peers(peers, 3, prefix);
+       setup_indirect_topology(peers, 3);
+       assert(meshlink_add_invitation_address(peers[0].mesh, "192.168.1.1", NULL));
+       assert(meshlink_add_invitation_address(peers[0].mesh, "192.168.2.1", NULL));
+       invite_peers(peers, 3);
+
+       return peers;
+}
+
 void close_relay_peer_nut(peer_config_t *peers) {
        close_peers(peers, 3);
 }
index 7bbe51a279540146f44b1f4027d138e1245aa259..5f84f9c4bc2d2b6104dd3fa8942bab0eed852a3f 100644 (file)
@@ -12,6 +12,7 @@ typedef struct peer_config {
 
 extern void change_peer_ip(peer_config_t *peer);
 extern peer_config_t *setup_relay_peer_nut(const char *prefix);
+extern peer_config_t *setup_relay_peer_nut_indirect(const char *prefix);
 extern void close_relay_peer_nut(peer_config_t *peers);
 
 #endif