diff --git a/README.md b/README.md index 122bb18f..d4f15202 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # n3n +[![Testing](https://github.com/n42n/n3n/actions/workflows/tests.yml/badge.svg)](https://github.com/n42n/n3n/actions/workflows/tests.yml) +[![Latest Release](https://img.shields.io/github/v/release/n42n/n3n)](https://github.com/n42n/n3n/releases/latest) + n3n is a lightweight Peer-to-Peer VPN that creates virtual networks. In order to start using n3n, two elements are required: @@ -19,8 +22,16 @@ n3n tries to establish a direct peer-to-peer connection via udp between the edge nodes when possible. When this is not possible (usually due to special NAT devices), the supernode is also used to relay the packets. +``` + [edge-A] ──────────────────── [edge-B] + \ direct p2p / + \ / + └──── [supernode] ────┘ + (discovery + relay) +``` + n3n was originally based on an older n2n project and hopes to keep protocol -compatiblilty with that. +compatibility with that. Note that some distributions have very old versions of n2n packaged that are incompatible with the protocol used by n3n. At the least, Debian has a n2n @@ -54,9 +65,11 @@ For Debian, Ubuntu or similar dpkg based systems: - Start the service: `sudo systemctl start n3n-edge@mynetwork` -- Check the connection: `sudo n3nctl -s mynetwork supernodes` +- Use `n3nctl` (the n3n management CLI) to inspect the running daemon: + + - Check the connection: `sudo n3nctl -s mynetwork supernodes` -- List other nodes found: `sudo n3nctl -s mynetwork edges` + - List other nodes found: `sudo n3nctl -s mynetwork edges` **IMPORTANT:** It is strongly advised to choose a custom community name (the `community.name` option) and a secret encryption key (the `community.key` @@ -82,6 +95,7 @@ You can contribute to n3n in various ways: - Improve the documentation - Provide pull requests with enhancements +For dev setup and internals, see the [Hacking guide](doc/Hacking.md). --- diff --git a/apps/n3n-edge.c b/apps/n3n-edge.c index d7f0803d..566257ee 100644 --- a/apps/n3n-edge.c +++ b/apps/n3n-edge.c @@ -340,38 +340,26 @@ static void cmd_test_config_roundtrip (int argc, char **argv, void *_conf) { static void cmd_test_benchmark (int argc, char **argv, void *_conf) { n2n_edge_conf_t *conf = (n2n_edge_conf_t *)_conf; - int level=0; - if(argc == 2) { - if(strcmp("pretty", argv[1])==0) { - level=0; - } else if(strcmp("raw", argv[1])==0) { - level=1; - } else { - printf( - "benchmark:\n" - "\n" - " usage: n3n-edge test benchmark [mode]\n" - "\n" - "The mode can be `raw` or `pretty` and defaults to pretty\n" - ); - exit(1); - } - } // TODO: // - provide a way to run a partial set of benchmarks - // - provide a way to output in normalised or raw numbers - benchmark_run_all(level, conf->benchmark_seconds); + benchmark_run_bench( + conf->test_output_format, + conf->test_benchmark_seconds, + argc-1, + ++argv + ); exit(0); } -static void cmd_test_builtin (int argc, char **argv, void *conf) { - int level=0; - if(argv[1]) { - level = atoi(argv[1]); - } - int errors = benchmark_check_all(level); +static void cmd_test_check (int argc, char **argv, void *_conf) { + n2n_edge_conf_t *conf = (n2n_edge_conf_t *)_conf; + int errors = benchmark_run_check( + conf->test_output_format, + argc-1, + ++argv + ); if(errors) { printf("ERROR\n"); } else { @@ -382,13 +370,23 @@ static void cmd_test_builtin (int argc, char **argv, void *conf) { static void cmd_test_fakebench (int argc, char **argv, void *_conf) { n2n_edge_conf_t *conf = (n2n_edge_conf_t *)_conf; - benchmark_run_all_ptrace_instr(conf->benchmark_seconds, argv[1]); + benchmark_run_ptrace( + conf->test_benchmark_seconds, + argc-1, + ++argv + ); + exit(0); +} + +static void cmd_test_list (int argc, char **argv, void *_conf) { + n2n_edge_conf_t *conf = (n2n_edge_conf_t *)_conf; + benchmark_list(conf->test_output_format); exit(0); } static void cmd_test_hashing (int argc, char **argv, void *conf) { - fprintf(stderr, "Deprecated: use `n3n-edge test builtin` instead\n"); - cmd_test_builtin(argc, argv, conf); + fprintf(stderr, "Deprecated: use `n3n-edge test check` instead\n"); + cmd_test_check(argc, argv, conf); } static void cmd_tools_keygen (int argc, char **argv, void *conf) { @@ -582,15 +580,17 @@ static struct n3n_subcmd_def cmd_tools[] = { static struct n3n_subcmd_def cmd_test[] = { { .name = "benchmark", - .help = "[pretty|raw] - run internal benchmarks", + .help = "[name..] - run built-in tests and benchmark results", .type = n3n_subcmd_type_fn, .fn = &cmd_test_benchmark, + .session_arg = true, }, { - .name = "builtin", - .help = "[level] - run built-in tests", + .name = "check", + .help = "[name..] - run built-in tests and check results", .type = n3n_subcmd_type_fn, - .fn = &cmd_test_builtin, + .fn = &cmd_test_check, + .session_arg = true, }, { .name = "config", @@ -603,11 +603,19 @@ static struct n3n_subcmd_def cmd_test[] = { .type = n3n_subcmd_type_fn, .fn = &cmd_test_hashing, }, + { + .name = "list", + .help = "Show the built-in tests", + .type = n3n_subcmd_type_fn, + .fn = &cmd_test_list, + .session_arg = true, + }, { .name = "fakebench", - .help = "[name] - count test instructions (when perf is unavailable)", + .help = "[name..] - run tests, counting instructions (when perf is unavailable)", .type = n3n_subcmd_type_fn, .fn = &cmd_test_fakebench, + .session_arg = true, }, { .name = NULL } }; @@ -682,7 +690,8 @@ static void n3n_config (int argc, char **argv, char *defname, n2n_edge_conf_t *c exit(1); } if(r == -2) { - printf( + traceEvent( + TRACE_INFO, "Warning: no config file found for session '%s'\n", cmd.sessionname ); diff --git a/doc/Building.md b/doc/Building.md index 5bd78df7..09325eab 100644 --- a/doc/Building.md +++ b/doc/Building.md @@ -174,7 +174,7 @@ In order to run n3n on Windows, you will need the following: The `edge.exe` program reads the `%USERPROFILE%\n3n\edge.conf` file if no session name option is provided. -The `supernode.exe` program reads the `%UERPROFILE%\n3n\supernode.conf` file if +The `supernode.exe` program reads the `%USERPROFILE%\n3n\supernode.conf` file if no session name option is provided. Example [edge.conf](edge.conf.sample) diff --git a/doc/Tools.md b/doc/Tools.md index 8ef9c738..0f38291e 100644 --- a/doc/Tools.md +++ b/doc/Tools.md @@ -71,7 +71,7 @@ compare test output and expected results to quickly show deviations, helpful when on bug hunt. Example: -- `tools/tests-transforms` +- `tools/tests-transform` ### `n3n-decode` diff --git a/include/n2n.h b/include/n2n.h index 145b3812..927edfab 100644 --- a/include/n2n.h +++ b/include/n2n.h @@ -126,6 +126,7 @@ struct n3n_runtime_data* edge_init (const n2n_edge_conf_t *conf, int *rv); void update_supernode_reg (struct n3n_runtime_data * eee, time_t nowTime); void readFromIPSocket (struct n3n_runtime_data * eee, int in_sock); void edge_term (struct n3n_runtime_data *eee); +size_t edge_encode_packet (struct n3n_runtime_data *eee, uint8_t *tap_pkt, size_t len, uint8_t *pktbuf, size_t pktbuf_size, n2n_mac_t out_destMac); void edge_send_packet2net (struct n3n_runtime_data *eee, uint8_t *tap_pkt, size_t len); int run_edge_loop (struct n3n_runtime_data *eee); int quick_edge_init (char *device_name, char *community_name, diff --git a/include/n2n_typedefs.h b/include/n2n_typedefs.h index 1751801b..360b340d 100644 --- a/include/n2n_typedefs.h +++ b/include/n2n_typedefs.h @@ -456,7 +456,9 @@ typedef struct n2n_edge_conf { devstr_t tuntap_dev_name; struct n2n_ip_subnet tuntap_v4; uint8_t tuntap_ip_mode; /**< Interface IP address allocated mode, eg. DHCP. */ - uint32_t benchmark_seconds; + + uint32_t test_benchmark_seconds; + int test_output_format; // Supernode specific config n2n_mac_t sn_mac_addr; diff --git a/include/n3n/benchmark.h b/include/n3n/benchmark.h index 483ac859..ce01a05d 100644 --- a/include/n3n/benchmark.h +++ b/include/n3n/benchmark.h @@ -22,10 +22,12 @@ enum n3n_test_data { test_data_tf, test_data_pdu_v3, test_data_pdu_eth, + test_data_tun2pdu, }; -#define BENCH_ITEM_CHECKONLY 0x1 // benchmark should be skipped -#define BENCH_ITEM_NOPTRACE 0x2 // fakebench takes too long, skip item +#define BENCH_SKIP_CHECK 0x1 // Default to skip check +#define BENCH_SKIP_BENCH 0x2 // Default to skip benchmark +#define BENCH_SKIP_PTRACE 0x4 // Default to skip fakebench struct bench_item { struct bench_item *next; @@ -33,7 +35,8 @@ struct bench_item { const char *name; // What is this testing const char *variant; // variant, eg name of optimisation int flags; - void *(*const setup)(void); // Any pre-run setup + const ssize_t ctx_size; // NR bytes to allocate for context + void *(*const setup)(void *const ctx); // Any pre-run setup const ssize_t(*const run)( void *const ctx, const void *data_in, @@ -62,8 +65,10 @@ struct bench_item { void n3n_benchmark_register (struct bench_item *); -void benchmark_run_all (const int level, const int seconds); -void benchmark_run_all_ptrace_instr (const int seconds, const char *filter_name); -int benchmark_check_all (int level); +void benchmark_run_bench (const int level, const int seconds, int filterc, char **filterv); +void benchmark_run_ptrace (const int seconds, int filterc, char **filterv); +int benchmark_run_check (int level, int filterc, char **filterv); + +void benchmark_list (const int level); #endif diff --git a/include/n3n/conffile.h b/include/n3n/conffile.h index 234e4859..891f7745 100644 --- a/include/n3n/conffile.h +++ b/include/n3n/conffile.h @@ -34,21 +34,30 @@ enum n3n_conf_type { n3n_conf_groupid, n3n_conf_macaddr, // TODO: conf has another macaddr string type n3n_conf_hostname_str, + n3n_conf_str2id, // TODO: refactor some other types to use this +}; + +struct n3n_conf_str2id_data { + const int id; + const char *name; }; struct n3n_conf_option { - char *name; // The name used to configure this option - int length; // Max length for string copy types - int offset; // offset within the conf structure of value - char *desc; // Short description - char *help; // lengthy description - enum n3n_conf_type type; // Which parser/validator to use + const char *name; // The name used to configure this option + union { + const int length; // Max length for string copy types + struct n3n_conf_str2id_data *str2id_data; + }; + const int offset; // offset within the conf structure of value + const char *desc; // Short description + const char *help; // lengthy description + const enum n3n_conf_type type; // Which parser/validator to use }; struct n3n_conf_section { struct n3n_conf_section *next; - char *name; // The name of this config section - char *help; // A description for this section + const char *name; // The name of this config section + const char *help; // A description for this section struct n3n_conf_option *options; }; diff --git a/scripts/benchmark2graphdata.py b/scripts/benchmark2graphdata.py index 96732e7e..63b6f4cb 100755 --- a/scripts/benchmark2graphdata.py +++ b/scripts/benchmark2graphdata.py @@ -42,6 +42,7 @@ def main(): "aes_decr,", "aes_encr,", "pdu2tun,", + "tun2pdu,", "NOP,", ] diff --git a/scripts/test_builtin_edge.sh b/scripts/test_builtin_edge.sh index 0fbd4fea..1e33e3f1 100755 --- a/scripts/test_builtin_edge.sh +++ b/scripts/test_builtin_edge.sh @@ -16,7 +16,7 @@ docmd() { return $S } -docmd "$BINDIR"/apps/n3n-edge test builtin +docmd "$BINDIR"/apps/n3n-edge test check docmd "$BINDIR"/apps/n3n-edge test config roundtrip diff --git a/src/benchmark.c b/src/benchmark.c index e918b10c..ce0feef8 100644 --- a/src/benchmark.c +++ b/src/benchmark.c @@ -16,6 +16,7 @@ #include #ifndef _WIN32 +#include // for mmap, MAP_SHARED, MAP_ANONYMOUS #include // for ptrace #include // for PTRACE_* #include // for wait, WIFSTOPPED @@ -509,6 +510,46 @@ static const uint8_t _test_data_pdu_eth[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, }; +/* Expected output for tun2pdu: the n3n v3 PDU produced by edge_send_packet2net + * when handed test_data_pdu_eth. Layout: + * common header (24 bytes): ver=3, ttl=2, flags=0x0003 (MSG_TYPE_PACKET, no + * socket), community="test"+zeros + * PACKET (14 bytes): srcMac=02:00:00:00:00:00 (device.mac_addr set in + * bench_tun2pdu_setup), dstMac=02:00:00:00:00:11 (eth dst from + * test_data_pdu_eth), compression=1 (NONE), transform=1 (NULL) + * payload (528 bytes): test_data_pdu_eth verbatim (NULL transform copies) + */ +static const uint8_t _test_data_tun2pdu[] = { + /* common header */ + 0x03,0x02,0x00,0x03, + 0x74,0x65,0x73,0x74,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + /* PACKET: srcMac, dstMac, compression, transform */ + 0x02,0x00,0x00,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x11, + 0x01,0x01, + /* payload: test_data_pdu_eth (528 bytes) */ + 0x02,0x00,0x00,0x00,0x00,0x11,0x02,0x00, + 0x00,0x00,0x00,0x22,0x0f,0x0f,0x55,0xaa, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, +}; + struct test_data { const int size; const void *data; @@ -559,17 +600,13 @@ const struct test_data benchmark_test_data[] = { .size = sizeof(_test_data_pdu_eth), .data = &_test_data_pdu_eth, }, + [test_data_tun2pdu] = { + .size = sizeof(_test_data_tun2pdu), + .data = &_test_data_tun2pdu, + }, }; /* A do-nothing function to time the benchmark framework */ -static void *bench_nop_setup (void) { - return NULL; -} - -static void bench_nop_teardown (void *ctx) { - return; -} - static const ssize_t bench_nop_run ( void *ctx, const void *data_in, @@ -582,9 +619,9 @@ static const ssize_t bench_nop_run ( static struct bench_item bench_nop = { .name = "NOP", - .setup = bench_nop_setup, + .flags = BENCH_SKIP_CHECK, + .ctx_size = 0, .run = bench_nop_run, - .teardown = bench_nop_teardown, .data_in = test_data_none, .data_out = test_data_none, }; @@ -608,6 +645,111 @@ int generic_check ( return 0; } +static void *item_setup (struct bench_item *item) { + void *ctx; + if(item->ctx_size) { + ctx = malloc(item->ctx_size); + if(!ctx) { + fprintf(stderr, "Malloc failure"); + exit(1); + } + } else { + ctx = NULL; + } + if(item->setup) { + ctx = item->setup(ctx); + } + + return ctx; +} + +static void item_teardown (struct bench_item *item, void *ctx) { + if(item->teardown) { + item->teardown(ctx); + } + if(item->ctx_size) { + free(ctx); + } +} + +static int item_fullname (struct bench_item *item, char *buf, ssize_t size, int level) { + return snprintf( + buf, + size, + "%s%s%s", + item->name, + (level || item->variant) ? ",":"", + item->variant ? item->variant : "" + ); +} + +#define ACTION_CHECK 1 +#define ACTION_BENCH 2 +#define ACTION_PTRACE 3 + +// Check if this item should be run or not +static bool item_allowrun (struct bench_item *item, int action, int filterc, char **filterv) { + bool _default = false; + + // Calculate what the default action would be + switch(action) { + case ACTION_CHECK: + if((item->flags & BENCH_SKIP_CHECK)) { + _default = false; + } else { + _default = true; + } + break; + + case ACTION_BENCH: + if(item->flags & BENCH_SKIP_BENCH) { + _default = false; + } else { + _default = true; + } + break; + + case ACTION_PTRACE: + if(item->flags & BENCH_SKIP_BENCH) { + _default = false; + } else if(item->flags & BENCH_SKIP_PTRACE) { + _default = false; + } else { + _default = true; + } + } + + bool result = false; + + if(filterc > 0) { + // Check all the filter strings + for(int i = 0; i < filterc; i++) { + if(!filterv[i]) { + continue; + } + if(strcmp("ALL", filterv[i])==0) { + result = true; + } + if(strcmp("DEFAULT", filterv[i])==0) { + result = _default; + } + if(strcmp(item->name, filterv[i])==0) { + result = true; + } + } + } else { + result = _default; + } + + return result; +} + +// These vars are shared between the harness and the traced pid when running a +// ptrace benchmark +struct pthread_shared { + int loops; + int sentinal; +}; static bool alarm_fired; @@ -618,13 +760,13 @@ static void handler (int nr) { #endif #ifdef _WIN32 -void benchmark_run_all_ptrace_instr (const int seconds, const char *filter) { +void benchmark_run_ptrace (const int seconds, int filterc, char **filterv) { fprintf(stderr,"no ptrace support on windows\n"); return; } #elif defined(DARWIN) -void benchmark_run_all_ptrace_instr (const int seconds, const char *filter) { +void benchmark_run_ptrace (const int seconds, int filterc, char **filterv) { fprintf(stderr,"Macos only partially implements ptrace support\n"); return; } @@ -634,12 +776,25 @@ static void run_one_item_ptrace (const int seconds, struct bench_item *item) { struct timeval tv1; struct timeval tv2; - void *ctx = item->setup(); + void *ctx = item_setup(item); const int input_size = benchmark_test_data[item->data_in].size; const void *input_data = benchmark_test_data[item->data_in].data; - int loops = 0; - alarm_fired = false; + struct pthread_shared *shm = mmap( + NULL, + sizeof(struct pthread_shared), + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, + -1, + 0 + ); + if(!shm) { + perror("mmap"); + exit(1); + } + + shm->loops = 0; + shm->sentinal = -1; struct sigaction sa = { .sa_handler = &handler, @@ -648,24 +803,36 @@ static void run_one_item_ptrace (const int seconds, struct bench_item *item) { gettimeofday(&tv1, NULL); - uint64_t sentinal = 0; pid_t pid = fork(); if(pid == 0) { - raise(SIGSTOP); + int wait_count = 10000; + // Spin on ether the parent is ready or we get bored of waiting + while(wait_count--) { + if(shm->sentinal==0) { + break; + } + } + + if(seconds > 0) { + alarm_fired = false; + alarm(seconds); + } else { + alarm_fired = true; + } ssize_t count_in; - sentinal = 1; - while(!alarm_fired) { + shm->sentinal = 1; + do { item->run( ctx, input_data, input_size, &count_in ); - loops++; - } - sentinal = 2; + shm->loops++; + } while(!alarm_fired); + shm->sentinal = 2; exit(0); } else { @@ -674,17 +841,12 @@ static void run_one_item_ptrace (const int seconds, struct bench_item *item) { exit(1); } + shm->sentinal = 0; int status; wait(&status); - alarm(seconds); while(WIFSTOPPED(status)) { - if(alarm_fired) { - ptrace(PTRACE_POKEDATA, pid, &alarm_fired, true); - loops = ptrace(PTRACE_PEEKDATA, pid, &loops, 0); - } - uint64_t _sentinal = ptrace(PTRACE_PEEKDATA, pid, &sentinal, 0); - if(_sentinal == 1) { + if(shm->sentinal == 1) { item->instr++; #if 0 // For debugging how accurate the measured cycle counts are, @@ -697,7 +859,29 @@ static void run_one_item_ptrace (const int seconds, struct bench_item *item) { #endif } - if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0)==-1) { + int sig = WSTOPSIG(status); + switch(sig) { + case SIGALRM: + // Pass these through + break; + case 0: + case SIGTRAP: + case SIGSTOP: + // Hide these from the child + sig = 0; + break; + default: + printf("child got unexpected signal %i\n", sig); +#ifdef __x86_64__ + struct user_regs_struct regs; + ptrace(PTRACE_GETREGS, pid, 0, ®s); + fhexdump(0, ®s, sizeof(regs), stdout); + printf("ip: 0x%08llx\n", regs.rip); +#endif + exit(1); + } + + if(ptrace(PTRACE_SINGLESTEP, pid, 0, sig)==-1) { perror("ptrace_singlestep"); exit(1); } @@ -707,47 +891,29 @@ static void run_one_item_ptrace (const int seconds, struct bench_item *item) { gettimeofday(&tv2, NULL); - item->teardown(ctx); + item_teardown(item, ctx); timersub(&tv2, &tv1, &tv1); - item->loops = loops; + item->loops = shm->loops; item->sec = tv1.tv_sec; item->usec = tv1.tv_usec; } // Run all tests (or just those with the matching name) once and count how // many instructions are -void benchmark_run_all_ptrace_instr (const int seconds, const char *filter) { +void benchmark_run_ptrace (const int seconds, int filterc, char **filterv) { struct bench_item *p; printf("name,variant,ptrace_seconds,ptrace_loops,ptrace_instr\n"); for(p = registered_items; p; p = p->next) { - if(p->flags & BENCH_ITEM_CHECKONLY) { + if(!item_allowrun(p, ACTION_PTRACE, filterc, filterv)) { continue; } - if(filter) { - // Allow filtering for only matching test names - if(strcmp(p->name, filter)!=0) { - continue; - } - } else { - // Check if this test should be skipped - if(p->flags & BENCH_ITEM_NOPTRACE) { - continue; - } - } char name[40]; - snprintf( - &name[0], - sizeof(name), - "%s,%s", - p->name, - p->variant ? p->variant : "" - ); - + item_fullname(p, &name[0], sizeof(name), 1); printf("%s,", name); fflush(stdout); @@ -760,7 +926,7 @@ void benchmark_run_all_ptrace_instr (const int seconds, const char *filter) { } #else -void benchmark_run_all_ptrace_instr (const int seconds, const char *filter) { +void benchmark_run_ptrace (const int seconds, int filterc, char **filterv) { fprintf(stderr,"TODO: add ptrace based fakebench for this platform\n"); return; } @@ -772,7 +938,7 @@ static void run_one_item (const int seconds, struct bench_item *item) { perf_setup(item); - void *ctx = item->setup(); + void *ctx = item_setup(item); const int input_size = benchmark_test_data[item->data_in].size; const void *input_data = benchmark_test_data[item->data_in].data; @@ -784,13 +950,18 @@ static void run_one_item (const int seconds, struct bench_item *item) { .sa_handler = &handler, }; sigaction(SIGALRM, &sa, NULL); - alarm(seconds); + + if(seconds > 0) { + alarm(seconds); + } else { + alarm_fired = true; + } #endif gettimeofday(&tv1, NULL); perf_measure_start(item); - while(!alarm_fired) { + do { ssize_t count_in; ssize_t count_out = item->run( @@ -809,14 +980,14 @@ static void run_one_item (const int seconds, struct bench_item *item) { alarm_fired = true; } #endif - } + } while(!alarm_fired); // TODO: per loop min/max/sumofsquares? perf_measure_collect(item); gettimeofday(&tv2, NULL); - item->teardown(ctx); + item_teardown(item, ctx); #ifdef _WIN32 // Just do a half-arsed job on windows, which matches their ability to @@ -832,7 +1003,7 @@ static void run_one_item (const int seconds, struct bench_item *item) { item->usec = tv1.tv_usec; } -void benchmark_run_all (const int level, const int seconds) { +void benchmark_run_bench (const int level, const int seconds, int filterc, char **filterv) { struct bench_item *p; if(level==0) { @@ -845,18 +1016,12 @@ void benchmark_run_all (const int level, const int seconds) { uint64_t cycles_total = 0; for(p = registered_items; p; p = p->next) { - if(p->flags && BENCH_ITEM_CHECKONLY) { + if(!item_allowrun(p, ACTION_BENCH, filterc, filterv)) { continue; } char name[40]; - snprintf( - &name[0], - sizeof(name), - "%s,%s", - p->name, - p->variant ? p->variant : "" - ); + item_fullname(p, &name[0], sizeof(name), level); if(level==0) { printf("%-20s", name); @@ -905,21 +1070,19 @@ void benchmark_run_all (const int level, const int seconds) { } } -int benchmark_check_all (int level) { +int benchmark_run_check (int level, int filterc, char **filterv) { int result = 0; for(struct bench_item *p = registered_items; p; p = p->next) { - if(p->data_out == test_data_none && !p->check) { + if(!item_allowrun(p, ACTION_CHECK, filterc, filterv)) { continue; } - fprintf(stderr, "%s", p->name); - if(p->variant) { - fprintf(stderr, ",%s", p->variant); - } - fprintf(stderr, ": "); + char name[40]; + item_fullname(p, &name[0], sizeof(name), level); + fprintf(stderr, "%s: ", name); - void *ctx = p->setup(); + void *ctx = item_setup(p); const int input_size = benchmark_test_data[p->data_in].size; const void *input_data = benchmark_test_data[p->data_in].data; @@ -962,8 +1125,8 @@ int benchmark_check_all (int level) { // Sanity check for bad data structures if(!checked) { - fprintf(stderr, "ERROR: neither check nor get_output available\n"); - exit(1); + fprintf(stderr, "WARNING: neither check nor get_output available\n"); + this_result += 1; } if(this_result) { @@ -974,12 +1137,55 @@ int benchmark_check_all (int level) { if(level) { printf("\n"); } - p->teardown(ctx); + item_teardown(p, ctx); } return result; } +void benchmark_list (const int level) { + if(level==0) { + // Pretty + printf("\n"); + printf("/------ C = include in default check list\n"); + printf("|/----- B = include in default benchmark list\n"); + printf("||/---- F = include in default fakebench list\n"); + printf("||| Name ctx_size in out\n"); + printf("+++-====================-========-==-===\n"); + } else { + // raw + printf("flags,name,variant,size,data_in,data_out\n"); + } + + for(struct bench_item *p = registered_items; p; p = p->next) { + char name[40]; + item_fullname(p, &name[0], sizeof(name), level); + + if(level==0) { + // Pretty + printf( + "%s%s%s %-20s %8i %2i %3i\n", + (p->flags & BENCH_SKIP_CHECK) ? "-":"C", + (p->flags & BENCH_SKIP_BENCH) ? "-":"B", + (p->flags & BENCH_SKIP_PTRACE) ? "-":"F", + name, + (int)p->ctx_size, + p->data_in, + p->data_out + ); + } else { + printf( + "0x%02x,%s,%i,%i,%i\n", + p->flags, + name, + (int)p->ctx_size, + p->data_in, + p->data_out + ); + } + } +} + void n3n_initfuncs_benchmark () { n3n_benchmark_register(&bench_nop); } diff --git a/src/benchmark_pdu.c b/src/benchmark_pdu.c index 01ceb1da..5670bf8d 100644 --- a/src/benchmark_pdu.c +++ b/src/benchmark_pdu.c @@ -28,8 +28,8 @@ struct bench_ctx { ssize_t outbuf_size; }; -static void *bench_setup (void) { - struct bench_ctx *ctx = calloc(1, sizeof(struct bench_ctx)); +static void *bench_setup (void *const _ctx) { + struct bench_ctx *ctx = (struct bench_ctx *)_ctx; edge_init_conf_defaults(&ctx->eee.conf,"edge"); strcpy(ctx->eee.conf.community_name, "test"); @@ -37,9 +37,15 @@ static void *bench_setup (void) { ctx->eee.last_sup = 1; ctx->eee.curr_sn = peer_info_malloc(null_mac); ctx->eee.curr_sn->sock.family = AF_INVALID; + ctx->eee.pending_peers = NULL; + ctx->eee.known_peers = NULL; + ctx->eee.network_traffic_filter = NULL; n2n_transop_null_init(&ctx->eee.conf, &ctx->eee.transop); + memset(ctx->eee.device.mac_addr, 0, N2N_MAC_SIZE); + ctx->eee.device.mac_addr[0] = 0x02; + #ifndef _WIN32 if(socketpair(AF_UNIX, SOCK_DGRAM, 0, ctx->sv) == -1) { perror("socketpair"); @@ -57,9 +63,9 @@ static void bench_teardown (void *_ctx) { struct bench_ctx *ctx = (struct bench_ctx *)_ctx; clear_peer_list(&ctx->eee.pending_peers); + clear_peer_list(&ctx->eee.known_peers); peer_info_free(ctx->eee.curr_sn); edge_term_conf(&ctx->eee.conf); - free(ctx); } #ifndef _WIN32 @@ -129,6 +135,7 @@ static const ssize_t bench_pdu2tun_run ( static struct bench_item bench_pdu2tun = { .name = "pdu2tun", + .ctx_size = sizeof(struct bench_ctx), .setup = bench_setup, .run = bench_pdu2tun_run, #ifndef _WIN32 @@ -141,6 +148,42 @@ static struct bench_item bench_pdu2tun = { .data_out = test_data_pdu_eth, }; +static const ssize_t bench_tun2pdu_run ( + void *_ctx, + const void *data_in, + const ssize_t data_in_size, + ssize_t *in +) { + struct bench_ctx *ctx = (struct bench_ctx *)_ctx; + n2n_mac_t destMac; + + ctx->outbuf_size = edge_encode_packet( + &ctx->eee, + (uint8_t *)data_in, data_in_size, + ctx->outbuf, sizeof(ctx->outbuf), + destMac + ); + + *in = data_in_size; + return ctx->outbuf_size; +} + +static struct bench_item bench_tun2pdu = { + .name = "tun2pdu", + .ctx_size = sizeof(struct bench_ctx), + .setup = bench_setup, + .run = bench_tun2pdu_run, +#ifndef _WIN32 + .get_output = bench_get_output, +#else + .check = bench_check_fake, +#endif + .teardown = bench_teardown, + .data_in = test_data_pdu_eth, + .data_out = test_data_tun2pdu, +}; + void n3n_initfuncs_benchmark_pdu () { n3n_benchmark_register(&bench_pdu2tun); + n3n_benchmark_register(&bench_tun2pdu); } diff --git a/src/conffile.c b/src/conffile.c index 6f50ea65..4f8d9df4 100644 --- a/src/conffile.c +++ b/src/conffile.c @@ -76,6 +76,28 @@ void n3n_deinitfuncs_config () { } } +const char *str2id_by_id (const struct n3n_conf_str2id_data data[], const int id) { + int i = 0; + while(data[i].name) { + if(data[i].id == id) { + return data[i].name; + } + i++; + } + return NULL; +} + +const int str2id_by_name (const struct n3n_conf_str2id_data data[], const char *name) { + int i = 0; + while(data[i].name) { + if(strcmp(data[i].name, name)==0) { + return data[i].id; + } + i++; + } + return -1; +} + static struct n3n_conf_option *lookup_section (char *section) { struct n3n_conf_section *p = registered_sections; while(p) { @@ -447,11 +469,19 @@ int n3n_config_set_option (void *conf, char *section, char *option, char *value) resolve_hostnames_str_add(listnr, value); return 0; } + case n3n_conf_str2id: { + int *val = (int *)valvoid; + *val = str2id_by_name(p->str2id_data, value); + if(*val == -1) { + return -1; + } + return 0; + } } return -1; } -static void dump_wordwrap (FILE *f, char *prefix, char *line, int width) { +static void dump_wordwrap (FILE *f, char *prefix, const char *line, int width) { char *line_copy = strdup(line); int column = 0; @@ -476,16 +506,16 @@ static void dump_wordwrap (FILE *f, char *prefix, char *line, int width) { // for the string - or may return a static string. A return of NULL means // that the option could not be rendered. // Buffer overflow is handled simplisticly by simply filling the buffer. -static const char * stringify_option (void *conf, struct n3n_conf_option *option, char *buf, size_t buflen) { +static const char * stringify_option (void *conf, struct n3n_conf_option option, char *buf, size_t buflen) { void *valvoid = NULL; // Entries that cannot be set via a pointer are marked with // a negative offset - if(option->offset >= 0) { - valvoid = (char *)conf + option->offset; + if(option.offset >= 0) { + valvoid = (char *)conf + option.offset; } - switch(option->type) { + switch(option.type) { case n3n_conf_strncpy: { char *val = (char *)valvoid; @@ -658,16 +688,20 @@ static const char * stringify_option (void *conf, struct n3n_conf_option *option // This is a multi-value item, so needs special handling to dump return NULL; } + case n3n_conf_str2id: { + int *val = (int *)valvoid; + return str2id_by_id(option.str2id_data, *val); + } } return NULL; } -static int option_storagesize (struct n3n_conf_option *option) { +static int option_storagesize (const struct n3n_conf_option option) { void *valvoid = NULL; - switch(option->type) { + switch(option.type) { case n3n_conf_strncpy: { - return option->length; + return option.length; } case n3n_conf_bool: { bool *val = (bool *)valvoid; @@ -736,6 +770,10 @@ static int option_storagesize (struct n3n_conf_option *option) { case n3n_conf_hostname_str: { return -1; } + case n3n_conf_str2id: { + int *val = (int *)valvoid; + return sizeof(*val); + } } return -1; } @@ -750,11 +788,8 @@ static int option_storagesize (struct n3n_conf_option *option) { * 4 = name, value, desc, schema and long help * */ -static void dump_option (FILE *f, void *conf, int level, struct n3n_conf_option *option) { - if(!option) { - return; - } - if(!option->name) { +static void dump_option (FILE *f, void *conf, int level, const struct n3n_conf_option option) { + if(!option.name) { return; } @@ -765,7 +800,7 @@ static void dump_option (FILE *f, void *conf, int level, struct n3n_conf_option } if(level >= 2) { // prefix with a short desc - fprintf(f, "# %s\n", option->desc); + fprintf(f, "# %s\n", option.desc); } #if 0 if(level >= 3) { @@ -775,25 +810,25 @@ static void dump_option (FILE *f, void *conf, int level, struct n3n_conf_option #endif if(level >= 4) { // also prefix with a long help - dump_wordwrap(f, "#", option->help, 78); + dump_wordwrap(f, "#", option.help, 78); } if(level >= 1) { // show both name and value - if(option->type == n3n_conf_hostname_str) { + if(option.type == n3n_conf_hostname_str) { // special case for this multi-value item // TODO: this breaks layering, but I cannot think of a simple // alternative - fprintf(f, "#%s=\n", option->name); - int listnr = option->offset; + fprintf(f, "#%s=\n", option.name); + int listnr = option.offset; int index = 0; char *p = (char *)resolve_hostnames_str_get(listnr, index); while(p) { fprintf( f, "%s=%s\n", - option->name, + option.name, p ); index++; @@ -812,23 +847,23 @@ static void dump_option (FILE *f, void *conf, int level, struct n3n_conf_option if(level >= 2) { // only show the invalids in levels with help texts - fprintf(f, "#%s=\n", option->name); + fprintf(f, "#%s=\n", option.name); } return; } - fprintf(f, "%s=%s\n", option->name, p); + fprintf(f, "%s=%s\n", option.name, p); return; } // level must be <= 0 // just print the variable name - fprintf(f, "%s=\n", option->name); + fprintf(f, "%s=\n", option.name); } void n3n_config_dump (void *conf, FILE *f, int level) { struct n3n_conf_section *section = registered_sections; - struct n3n_conf_option *option; + const struct n3n_conf_option *option; fprintf(f, "# Autogenerated config dump\n"); while(section) { @@ -843,9 +878,10 @@ void n3n_config_dump (void *conf, FILE *f, int level) { fprintf(f, "[%s]\n", section->name); option = section->options; - while(option->name) { - dump_option(f, conf, level, option); - option++; + int i = 0; + while(option[i].name) { + dump_option(f, conf, level, option[i]); + i++; } section = section->next; @@ -854,14 +890,15 @@ void n3n_config_dump (void *conf, FILE *f, int level) { void n3n_config_debug_addr (void *conf, FILE *f) { struct n3n_conf_section *section = registered_sections; - struct n3n_conf_option *option; + const struct n3n_conf_option *option; fprintf(f, "# Internal Address consistancy checks\n"); while(section) { option = section->options; - while(option->name) { - if(option->type == n3n_conf_hostname_str) { - option++; + int i = 0; + while(option[i].name) { + if(option[i].type == n3n_conf_hostname_str) { + i++; continue; } void *first = NULL; @@ -869,11 +906,11 @@ void n3n_config_debug_addr (void *conf, FILE *f) { // Entries that cannot be set via a pointer are marked with // a negative offset - if(option->offset >= 0) { - first = (char *)conf + option->offset; + if(option[i].offset >= 0) { + first = (char *)conf + option[i].offset; } - int size = option_storagesize(option); + int size = option_storagesize(option[i]); if(size > 0) { last = first + (size-1); } @@ -885,10 +922,10 @@ void n3n_config_debug_addr (void *conf, FILE *f) { last, size, section->name, - option->name, - option->type + option[i].name, + option[i].type ); - option++; + i++; } section = section->next; diff --git a/src/conffile_defs.c b/src/conffile_defs.c index 68e7858e..15f2c0fc 100644 --- a/src/conffile_defs.c +++ b/src/conffile_defs.c @@ -273,7 +273,7 @@ static struct n3n_conf_option section_logging[] = { .offset = -1, .desc = "Set the logging verbosity", .help = "This is a number between 0 and 4, defaulting to 2 for " - "normal amounts of logging." + "normal amounts of logging. (0 is most logging, 4 is least)" }, {.name = NULL}, }; @@ -399,16 +399,43 @@ static struct n3n_conf_option section_supernode[] = { {.name = NULL}, }; +static struct n3n_conf_str2id_data test_output_format_data[] = { + { + .id = 0, + .name = "pretty", + }, + { + .id = 1, + .name = "raw", + }, + {}, +}; + static struct n3n_conf_option section_test[] = { { .name = "benchmark_seconds", .type = n3n_conf_uint32, - .offset = offsetof(n2n_edge_conf_t, benchmark_seconds), + .offset = offsetof(n2n_edge_conf_t, test_benchmark_seconds), .desc = "Duration of each benchmark test", .help = "This allows the amount of time spent on running the built-in " "benchmark tests to be adjusted. Larger numbers will " "produce more accurate results, but will obviously take more " - "time to complete. (Integer numbers of seconds only)", + "time to complete. (Integer numbers of seconds only). " + "A value of zero causes one loop to run", + }, + { + .name = "output_format", + .type = n3n_conf_str2id, + .str2id_data = test_output_format_data, + .offset = offsetof(n2n_edge_conf_t, test_output_format), + .desc = "What format to show results of tests in", + .help = "The built-in tests can output their results in a number of " + "different formats. The default is to output a 'pretty' " + "result - this is intended to be simplified and easily " + "readable. The alternative is 'raw', which outputs the " + "unprocessed data, suitable for additional reporting or " + "debugging." + "FIXME - the integer number should be a string lookup.", }, {.name = NULL}, }; diff --git a/src/curve25519.c b/src/curve25519.c index 539493ee..a6dd87b4 100644 --- a/src/curve25519.c +++ b/src/curve25519.c @@ -367,14 +367,6 @@ static const uint8_t test_data_k[] = { 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, }; -static void *bench_curve25519_setup (void) { - return NULL; -} - -static void bench_curve25519_teardown (void *ctx) { - return; -} - static const ssize_t bench_curve25519_run ( void *ctx, const void *data_in, @@ -389,10 +381,9 @@ static const ssize_t bench_curve25519_run ( static struct bench_item bench_curve25519 = { .name = "curve25519", - .flags = BENCH_ITEM_NOPTRACE, - .setup = bench_curve25519_setup, + .flags = BENCH_SKIP_CHECK | BENCH_SKIP_PTRACE, + .ctx_size = 0, .run = bench_curve25519_run, - .teardown = bench_curve25519_teardown, .data_in = test_data_none, }; diff --git a/src/edge_utils.c b/src/edge_utils.c index a67ced95..550f52d3 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -967,6 +967,10 @@ static void check_peer_registration_needed (struct n3n_runtime_data *eee, struct peer_info *scan; + if(!eee->known_peers) { + return; + } + HASH_FIND_PEER(eee->known_peers, mac, scan); /* If we were not able to find it by MAC, we try to find it by socket. */ @@ -1493,8 +1497,9 @@ void send_register_super (struct n3n_runtime_data *eee) { n2n_REGISTER_SUPER_t reg; n3n_sock_str_t sockbuf; - // FIXME: fix encode_* functions to not need memsets - memset(&cmn, 0, sizeof(cmn)); + /* reg.key_time is not set by this caller; zero it so encode_REGISTER_SUPER + * does not emit garbage for that field */ + // TODO: refactor code to avoid needing memet memset(®, 0, sizeof(reg)); cmn.ttl = N2N_DEFAULT_TTL; @@ -1552,10 +1557,6 @@ static void send_unregister_super (struct n3n_runtime_data *eee) { return; } - // FIXME: fix encode_* functions to not need memsets - memset(&cmn, 0, sizeof(cmn)); - memset(&unreg, 0, sizeof(unreg)); - cmn.ttl = N2N_DEFAULT_TTL; cmn.pc = MSG_TYPE_UNREGISTER_SUPER; cmn.flags = 0; @@ -1650,8 +1651,9 @@ static void send_register (struct n3n_runtime_data * eee, return; } - // FIXME: fix encode_* functions to not need memsets - memset(&cmn, 0, sizeof(cmn)); + /* reg.auth is not set by this caller; zero it so encode_REGISTER does not + * emit garbage for that field */ + // TODO: refactor code to avoid needing memet memset(®, 0, sizeof(reg)); cmn.ttl = N2N_DEFAULT_TTL; cmn.pc = MSG_TYPE_REGISTER; @@ -1702,15 +1704,10 @@ static void send_register_ack (struct n3n_runtime_data * eee, return; } - // FIXME: fix encode_* functions to not need memsets - memset(&cmn, 0, sizeof(cmn)); cmn.ttl = N2N_DEFAULT_TTL; cmn.pc = MSG_TYPE_REGISTER_ACK; cmn.flags = 0; memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); - - // FIXME: fix encode_* functions to not need memsets - memset(&ack, 0, sizeof(ack)); ack.cookie = reg->cookie; memcpy(ack.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); memcpy(ack.dstMac, reg->srcMac, N2N_MAC_SIZE); @@ -2242,17 +2239,23 @@ static int send_packet (struct n3n_runtime_data * eee, /* ************************************** */ /** A layer-2 packet was received at the tunnel and needs to be sent via UDP. */ -void edge_send_packet2net (struct n3n_runtime_data * eee, - uint8_t *tap_pkt, size_t len) { +/** Encode an ethernet frame into an n3n PDU. + * + * Returns the number of bytes written to pktbuf, or 0 if the packet was + * discarded by policy (e.g. routing rules). out_destMac receives the n3n + * destination MAC that should be used to route the PDU. + */ +size_t edge_encode_packet (struct n3n_runtime_data *eee, + uint8_t *tap_pkt, size_t len, + uint8_t *pktbuf, size_t pktbuf_size, + n2n_mac_t out_destMac) { ipstr_t ip_buf; - n2n_mac_t destMac; n2n_common_t cmn; n2n_PACKET_t pkt; uint8_t *enc_src = tap_pkt; size_t enc_len = len; uint8_t compression_buf[N2N_PKT_BUF_SIZE]; - uint8_t pktbuf[N2N_PKT_BUF_SIZE]; size_t idx = 0; n2n_transform_t tx_transop_idx = eee->transop.transform_id; ether_hdr_t eh; @@ -2260,7 +2263,7 @@ void edge_send_packet2net (struct n3n_runtime_data * eee, /* tap_pkt is not aligned so we have to copy to aligned memory */ memcpy(&eh, tap_pkt, sizeof(ether_hdr_t)); - /* Discard IP packets that are not originated by this hosts */ + /* Discard IP packets that are not originated by this host */ if(!(eee->conf.allow_routing)) { if(ntohs(eh.type) == 0x0800) { /* This is an IP packet from the local source address - not forwarded. */ @@ -2271,7 +2274,7 @@ void edge_send_packet2net (struct n3n_runtime_data * eee, /* This is a packet that needs to be routed */ traceEvent(TRACE_INFO, "discarding routed packet destined to [%s]", intoa(ntohl(*src), ip_buf, sizeof(ip_buf))); - return; + return 0; } else { /* This packet is originated by us */ /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */ @@ -2283,29 +2286,25 @@ void edge_send_packet2net (struct n3n_runtime_data * eee, /* Once processed, send to destination in PACKET */ - memcpy(destMac, tap_pkt, N2N_MAC_SIZE); /* dest MAC is first in ethernet header */ + memcpy(out_destMac, eh.dhost, N2N_MAC_SIZE); #ifdef HAVE_BRIDGING_SUPPORT /* find the destMac behind which edge, and change dest to this edge */ - if((eee->conf.allow_routing) && (!is_multi_broadcast(destMac))) { + if((eee->conf.allow_routing) && (!is_multi_broadcast(out_destMac))) { struct host_info *host = NULL; - HASH_FIND(hh, eee->known_hosts, destMac, sizeof(n2n_mac_t), host); + HASH_FIND(hh, eee->known_hosts, out_destMac, sizeof(n2n_mac_t), host); if(host) { - memcpy(destMac, host->edge_addr, N2N_MAC_SIZE); + memcpy(out_destMac, host->edge_addr, N2N_MAC_SIZE); } } #endif - // FIXME: fix encode_* functions to not need memsets - memset(&cmn, 0, sizeof(cmn)); cmn.ttl = N2N_DEFAULT_TTL; cmn.pc = MSG_TYPE_PACKET; cmn.flags = 0; /* no options, not from supernode, no socket */ memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); - // FIXME: fix encode_* functions to not need memsets - memset(&pkt, 0, sizeof(pkt)); memcpy(pkt.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); - memcpy(pkt.dstMac, destMac, N2N_MAC_SIZE); + memcpy(pkt.dstMac, out_destMac, N2N_MAC_SIZE); pkt.transform = tx_transop_idx; @@ -2359,7 +2358,7 @@ void edge_send_packet2net (struct n3n_runtime_data * eee, uint16_t headerIdx = idx; idx += eee->transop.fwd(&eee->transop, - pktbuf + idx, N2N_PKT_BUF_SIZE - idx, + pktbuf + idx, pktbuf_size - idx, enc_src, enc_len, pkt.dstMac); traceEvent(TRACE_DEBUG, "encode PACKET of %u bytes, %u bytes data, %u bytes overhead, transform %u", @@ -2382,7 +2381,19 @@ void edge_send_packet2net (struct n3n_runtime_data * eee, eee->transop.tx_cnt++; /* stats */ - send_packet(eee, destMac, pktbuf, idx); /* to peer or supernode */ + return idx; +} + +void edge_send_packet2net (struct n3n_runtime_data * eee, + uint8_t *tap_pkt, size_t len) { + + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + n2n_mac_t destMac; + + size_t idx = edge_encode_packet(eee, tap_pkt, len, pktbuf, sizeof(pktbuf), destMac); + if(idx) { + send_packet(eee, destMac, pktbuf, idx); /* to peer or supernode */ + } } /* ************************************** */ @@ -2766,8 +2777,6 @@ void process_pdu (struct n3n_runtime_data *eee, return; } - // FIXME: fix decode_* functions to not need memsets - memset(&ra, 0, sizeof(ra)); decode_REGISTER_SUPER_ACK(&ra, &cmn, udp_buf, &rem, &idx, tmpbuf); if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { @@ -2888,8 +2897,6 @@ void process_pdu (struct n3n_runtime_data *eee, return; } - // FIXME: fix decode_* functions to not need memsets - memset(&nak, 0, sizeof(nak)); decode_REGISTER_SUPER_NAK(&nak, &cmn, udp_buf, &rem, &idx); if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { @@ -3625,7 +3632,8 @@ void edge_init_conf_defaults (n2n_edge_conf_t *conf, char *sessionname) { conf->metric = 0; conf->mtu = DEFAULT_MTU; - conf->benchmark_seconds = 1; + conf->test_benchmark_seconds = 1; + conf->test_output_format = 0; #ifndef _WIN32 struct passwd *pw = NULL; diff --git a/src/hexdump.c b/src/hexdump.c index ea1ad8dd..cc7496d4 100644 --- a/src/hexdump.c +++ b/src/hexdump.c @@ -18,6 +18,7 @@ */ +#include // for PRIx64 #include // for fhexdump #include // for uint8_t #include // for fprintf, FILE @@ -29,7 +30,7 @@ void fhexdump (uint64_t display_addr, const void *in, int size, FILE *stream) { while(size>0) { int i; - fprintf(stream, "%03lx: ", display_addr); + fprintf(stream, "%03" PRIx64 ": ", display_addr); for(i = 0; i < 16; i++) { if(i < size) { diff --git a/src/pearson.c b/src/pearson.c index cd91fd33..f3d6a6cd 100644 --- a/src/pearson.c +++ b/src/pearson.c @@ -230,15 +230,6 @@ static const uint16_t expected_pearson_hash_16 = 0x8be; static const uint32_t expected_pearson_hash_32 = 0x2ea108be; static const uint64_t expected_pearson_hash_64 = 0xb2d98fa82ea108be; -static void *bench_pearson_setup (void) { - // largest result size plus one for the length - return malloc(32 + 1); -} - -static void bench_pearson_teardown (void *ctx) { - return free(ctx); -} - static const ssize_t bench_16_run ( void *ctx, const void *data_in, @@ -381,51 +372,51 @@ static const void *const bench_get_output (void *const ctx) { static struct bench_item bench_16 = { .name = "pearson_hash_16", - .flags = BENCH_ITEM_CHECKONLY, - .setup = bench_pearson_setup, + .flags = BENCH_SKIP_BENCH, + // largest result size plus one for the length + .ctx_size = 32 + 1, .run = bench_16_run, .check = bench_16_check, - .teardown = bench_pearson_teardown, .data_in = test_data_32x16, }; static struct bench_item bench_32 = { .name = "pearson_hash_32", - .flags = BENCH_ITEM_CHECKONLY, - .setup = bench_pearson_setup, + .flags = BENCH_SKIP_BENCH, + // largest result size plus one for the length + .ctx_size = 32 + 1, .run = bench_32_run, .check = bench_32_check, - .teardown = bench_pearson_teardown, .data_in = test_data_32x16, }; static struct bench_item bench_64 = { .name = "pearson_hash_64", - .setup = bench_pearson_setup, + // largest result size plus one for the length + .ctx_size = 32 + 1, .run = bench_64_run, .check = bench_64_check, - .teardown = bench_pearson_teardown, .data_in = test_data_32x16, }; static struct bench_item bench_128 = { .name = "pearson_hash_128", - .flags = BENCH_ITEM_CHECKONLY, - .setup = bench_pearson_setup, + .flags = BENCH_SKIP_BENCH, + // largest result size plus one for the length + .ctx_size = 32 + 1, .run = bench_128_run, .get_output = bench_get_output, - .teardown = bench_pearson_teardown, .data_in = test_data_32x16, .data_out = test_data_pearson_128, }; static struct bench_item bench_256 = { .name = "pearson_hash_256", - .flags = BENCH_ITEM_CHECKONLY, - .setup = bench_pearson_setup, + .flags = BENCH_SKIP_BENCH, + // largest result size plus one for the length + .ctx_size = 32 + 1, .run = bench_256_run, .get_output = bench_get_output, - .teardown = bench_pearson_teardown, .data_in = test_data_32x16, .data_out = test_data_pearson_256, }; diff --git a/src/peer_info.c b/src/peer_info.c index 6693db23..58aae093 100644 --- a/src/peer_info.c +++ b/src/peer_info.c @@ -231,6 +231,10 @@ int find_and_remove_peer (struct peer_info **head, const n2n_mac_t mac) { struct peer_info *peer; + if(!*head) { + return 0; + } + HASH_FIND_PEER(*head, mac, peer); if(peer) { HASH_DEL(*head, peer); diff --git a/src/sn_utils.c b/src/sn_utils.c index e972ff83..cfb99a39 100644 --- a/src/sn_utils.c +++ b/src/sn_utils.c @@ -1565,9 +1565,6 @@ static int re_register_and_purge_supernodes (struct n3n_runtime_data *sss, struc n2n_REGISTER_SUPER_t reg; n3n_sock_str_t sockbuf; - memset(&cmn, 0, sizeof(cmn)); - memset(®, 0, sizeof(reg)); - cmn.ttl = N2N_DEFAULT_TTL; cmn.pc = MSG_TYPE_REGISTER_SUPER; cmn.flags = N2N_FLAGS_FROM_SUPERNODE; @@ -2056,8 +2053,13 @@ static int process_pdu (struct n3n_runtime_data * sss, int ret_value; sn_user_t *user = NULL; + /* + * ack.dev_addr is only set when the edge needs an IP assigned + * (lines below); zero the whole struct so the encoded dev_addr + * is zero rather than garbage when that branch is not taken + */ + // TODO: refactor code to avoid needing memset memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); - memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); /* Edge/supernode requesting registration with us. */ sss->last_sn_reg=now; @@ -2356,8 +2358,6 @@ static int process_pdu (struct n3n_runtime_data * sss, int auth; - memset(&unreg, 0, sizeof(n2n_UNREGISTER_SUPER_t)); - if(!comm) { traceEvent(TRACE_DEBUG, "dropped UNREGISTER_SUPER with unknown community %s", cmn.community); return -1; @@ -2413,8 +2413,6 @@ static int process_pdu (struct n3n_runtime_data * sss, n2n_REGISTER_SUPER_ACK_payload_t *payload; n3n_sock_t payload_sock; - memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); - if(!comm) { traceEvent(TRACE_DEBUG, "REGISTER_SUPER_ACK with unknown community %s", cmn.community); return -1; diff --git a/src/transform_aes.c b/src/transform_aes.c index 198b3646..bc8c3c07 100644 --- a/src/transform_aes.c +++ b/src/transform_aes.c @@ -263,8 +263,8 @@ struct bench_ctx { ssize_t outbuf_size; }; -static void *bench_setup (void) { - struct bench_ctx *ctx = calloc(1, sizeof(struct bench_ctx)); +static void *bench_setup (void *const _ctx) { + struct bench_ctx *ctx = (struct bench_ctx *)_ctx; const char *key = "just_a_test_key_for_benchmarks"; const ssize_t key_len = sizeof(key); @@ -283,7 +283,6 @@ static void *bench_setup (void) { static void bench_teardown (void *_ctx) { struct bench_ctx *ctx = (struct bench_ctx *)_ctx; aes_deinit(ctx->priv.ctx); - free(ctx); } static const ssize_t bench_encr_run ( @@ -423,6 +422,7 @@ static const void *const bench_get_output (void *const _ctx) { static struct bench_item bench_encr = { .name = "aes_encr", + .ctx_size = sizeof(struct bench_ctx), .setup = bench_setup, .run = bench_encr_run, .get_output = bench_get_output, @@ -433,6 +433,7 @@ static struct bench_item bench_encr = { static struct bench_item bench_decr = { .name = "aes_decr", + .ctx_size = sizeof(struct bench_ctx), .setup = bench_setup, .run = bench_decr_run, .get_output = bench_get_output, diff --git a/src/transform_cc20.c b/src/transform_cc20.c index ef13a8c7..fec18725 100644 --- a/src/transform_cc20.c +++ b/src/transform_cc20.c @@ -184,8 +184,8 @@ struct bench_ctx { ssize_t outbuf_size; }; -static void *bench_setup (void) { - struct bench_ctx *ctx = calloc(1, sizeof(struct bench_ctx)); +static void *bench_setup (void *const _ctx) { + struct bench_ctx *ctx = (struct bench_ctx *)_ctx; const char *key = "just_a_test_key_for_benchmarks"; const ssize_t key_len = sizeof(key); @@ -204,7 +204,6 @@ static void *bench_setup (void) { static void bench_teardown (void *_ctx) { struct bench_ctx *ctx = (struct bench_ctx *)_ctx; cc20_deinit(ctx->priv.ctx); - free(ctx); } static const ssize_t bench_encr_run ( @@ -267,6 +266,7 @@ static const void *const bench_get_output (void *const _ctx) { static struct bench_item bench_encr = { .name = "cc20_encr", + .ctx_size = sizeof(struct bench_ctx), .setup = bench_setup, .run = bench_encr_run, .get_output = bench_get_output, @@ -277,6 +277,7 @@ static struct bench_item bench_encr = { static struct bench_item bench_decr = { .name = "cc20_decr", + .ctx_size = sizeof(struct bench_ctx), .setup = bench_setup, .run = bench_decr_run, .get_output = bench_get_output, diff --git a/src/transform_lzo.c b/src/transform_lzo.c index be307607..922d26c0 100644 --- a/src/transform_lzo.c +++ b/src/transform_lzo.c @@ -147,14 +147,6 @@ struct bench_ctx { lzo_uint outbuf_size; }; -static void *bench_lzo_setup (void) { - return calloc(1, sizeof(struct bench_ctx)); -} - -static void bench_lzo_teardown (void *ctx) { - free(ctx); -} - static const ssize_t bench_lzo_comp_run ( void *_ctx, const void *data_in, @@ -217,20 +209,18 @@ static struct n3n_transform transform = { static struct bench_item bench_lzo_comp = { .name = "lzo_comp", - .setup = bench_lzo_setup, + .ctx_size = sizeof(struct bench_ctx), .run = bench_lzo_comp_run, .get_output = bench_lzo_get_output, - .teardown = bench_lzo_teardown, .data_in = test_data_32x16, .data_out = test_data_lzo, }; static struct bench_item bench_lzo_uncomp = { .name = "lzo_uncomp", - .setup = bench_lzo_setup, + .ctx_size = sizeof(struct bench_ctx), .run = bench_lzo_uncomp_run, .get_output = bench_lzo_get_output, - .teardown = bench_lzo_teardown, .data_in = test_data_lzo, .data_out = test_data_32x16, }; diff --git a/src/transform_speck.c b/src/transform_speck.c index 5a0267cd..221576be 100644 --- a/src/transform_speck.c +++ b/src/transform_speck.c @@ -188,8 +188,8 @@ struct bench_ctx { ssize_t outbuf_size; }; -static void *bench_setup (void) { - struct bench_ctx *ctx = calloc(1, sizeof(struct bench_ctx)); +static void *bench_setup (void *const _ctx) { + struct bench_ctx *ctx = (struct bench_ctx *)_ctx; const char *key = "just_a_test_key_for_benchmarks"; const ssize_t key_len = sizeof(key); @@ -208,7 +208,6 @@ static void *bench_setup (void) { static void bench_teardown (void *_ctx) { struct bench_ctx *ctx = (struct bench_ctx *)_ctx; speck_deinit(ctx->priv.ctx); - free(ctx); } static const ssize_t bench_encr_run ( @@ -271,6 +270,7 @@ static const void *const bench_get_output (void *const _ctx) { static struct bench_item bench_encr = { .name = "speck_encr", + .ctx_size = sizeof(struct bench_ctx), .setup = bench_setup, .run = bench_encr_run, .get_output = bench_get_output, @@ -281,6 +281,7 @@ static struct bench_item bench_encr = { static struct bench_item bench_decr = { .name = "speck_decr", + .ctx_size = sizeof(struct bench_ctx), .setup = bench_setup, .run = bench_decr_run, .get_output = bench_get_output, diff --git a/src/transform_tf.c b/src/transform_tf.c index ced6b09c..9e0c4c4c 100644 --- a/src/transform_tf.c +++ b/src/transform_tf.c @@ -249,8 +249,8 @@ struct bench_ctx { ssize_t outbuf_size; }; -static void *bench_setup (void) { - struct bench_ctx *ctx = calloc(1, sizeof(struct bench_ctx)); +static void *bench_setup (void *const _ctx) { + struct bench_ctx *ctx = (struct bench_ctx *)_ctx; const char *key = "just_a_test_key_for_benchmarks"; const ssize_t key_len = sizeof(key); @@ -269,7 +269,6 @@ static void *bench_setup (void) { static void bench_teardown (void *_ctx) { struct bench_ctx *ctx = (struct bench_ctx *)_ctx; tf_deinit(ctx->priv.ctx); - free(ctx); } static const ssize_t bench_encr_run ( @@ -408,6 +407,7 @@ static const void *const bench_get_output (void *const _ctx) { static struct bench_item bench_encr = { .name = "tf_encr", + .ctx_size = sizeof(struct bench_ctx), .setup = bench_setup, .run = bench_encr_run, .get_output = bench_get_output, @@ -418,6 +418,7 @@ static struct bench_item bench_encr = { static struct bench_item bench_decr = { .name = "tf_decr", + .ctx_size = sizeof(struct bench_ctx), .setup = bench_setup, .run = bench_decr_run, .get_output = bench_get_output, diff --git a/tests/test_builtin_edge.sh.expected b/tests/test_builtin_edge.sh.expected index 2148e60b..07901fde 100644 --- a/tests/test_builtin_edge.sh.expected +++ b/tests/test_builtin_edge.sh.expected @@ -1,4 +1,4 @@ -### test: ./apps/n3n-edge test builtin +### test: ./apps/n3n-edge test check OK ### test: ./apps/n3n-edge test config roundtrip @@ -47,6 +47,7 @@ spoofing_protection=false [test] benchmark_seconds=0 +output_format=pretty [tuntap] address=0.0.0.0/0