diff --git a/edge.8 b/edge.8 index 7a81444..529fd6f 100644 --- a/edge.8 +++ b/edge.8 @@ -105,6 +105,10 @@ compress outgoing data packets, -z1 = lzo1x, disabled by default \fB\-\-select-rtt\fR select supernode by round trip time if several to choose from (federation), defaults to load-based selection strategy if not provided. +.TP +\fB\-\-select-mac\fR +select supernode by MAC address if several to choose from (federation), +lowest MAC address first. .SH TAP DEVICE AND OVERLAY NETWORK CONFIGURATION .TP \fB\-a \fR[\fImode\fR]<\fIip\fR>[\fI/n\fR] diff --git a/include/n2n_typedefs.h b/include/n2n_typedefs.h index 2715731..3ba65f2 100644 --- a/include/n2n_typedefs.h +++ b/include/n2n_typedefs.h @@ -288,7 +288,7 @@ typedef char n2n_version_t[N2N_VERSION_STRING_SIZE]; #define SN_SELECTION_STRATEGY_LOAD 1 #define SN_SELECTION_STRATEGY_RTT 2 -#define SN_SELECTION_STRATEGY_MAC 3 /* REVISIT: not implemented yet */ +#define SN_SELECTION_STRATEGY_MAC 3 typedef struct n2n_ip_subnet { diff --git a/src/edge.c b/src/edge.c index 01e2096..6ccdd28 100644 --- a/src/edge.c +++ b/src/edge.c @@ -232,6 +232,7 @@ static void help (int level) { "\n [-r] enable packet forwarding through n2n community" "\n [-E] accept multicast MAC addresses" "\n [--select-rtt] select supernode by round trip time" + "\n [--select-mac] select supernode by MAC address" #ifndef WIN32 "\n [-f] do not fork but run in foreground" #endif @@ -290,7 +291,8 @@ static void help (int level) { "-z2 = zstd, " #endif "disabled by default\n"); - printf("--select-rtt | supernode selection based on round trip time (default:\n" + printf("--select-rtt | supernode selection based on round trip time\n" + "--select-mac | supernode selection based on MAC address (default:\n" " | by load)\n"); printf ("\n"); @@ -737,7 +739,14 @@ static int setOption (int optkey, char *optargument, n2n_tuntap_priv_config_t *e break; } - case ']': /* password for management port */ { + case ']': /* mac-address-based supernode selection strategy */ { + // overwrites the default load-based strategy + conf->sn_selection_strategy = SN_SELECTION_STRATEGY_MAC; + + break; + } + + case '{': /* password for management port */ { conf->mgmt_password_hash = pearson_hash_64((uint8_t*)optargument, strlen(optargument)); break; @@ -797,7 +806,8 @@ static const struct option long_options[] = { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, '@' }, /* internal special character '@' to identify long help case */ { "select-rtt", no_argument, NULL, '[' }, /* '[' rtt selection strategy */ - { "management-password", required_argument, NULL, ']' }, /* ']' management port password */ + { "select-mac", no_argument, NULL, ']' }, /* ']' mac selection strategy */ + { "management-password", required_argument, NULL, '{' }, /* '{' management port password */ { NULL, 0, NULL, 0 } }; diff --git a/src/sn_selection.c b/src/sn_selection.c index 98b3ec1..13c0ff1 100644 --- a/src/sn_selection.c +++ b/src/sn_selection.c @@ -88,7 +88,17 @@ int sn_selection_criterion_calculate (n2n_edge_t *eee, peer_info_t *peer, SN_SEL } case SN_SELECTION_STRATEGY_RTT: { - peer->selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)(time_stamp() >> 22) - common_data; + peer->selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)((uint32_t)time_stamp() >> 22) - common_data; + break; + } + + case SN_SELECTION_STRATEGY_MAC: { + peer->selection_criterion = 0; + memcpy(&peer->selection_criterion, /* leftbound, don't mess with pointer arithmetics */ + peer->mac_addr, + N2N_MAC_SIZE); + peer->selection_criterion = be64toh(peer->selection_criterion); + peer->selection_criterion >>= (sizeof(peer->selection_criterion) - N2N_MAC_SIZE) * 8; /* rightbound */ break; } @@ -120,7 +130,12 @@ int sn_selection_criterion_common_data_default (n2n_edge_t *eee) { } case SN_SELECTION_STRATEGY_RTT: { - eee->sn_selection_criterion_common_data = (SN_SELECTION_CRITERION_DATA_TYPE)(time_stamp() >> 22); + eee->sn_selection_criterion_common_data = (SN_SELECTION_CRITERION_DATA_TYPE)((uint32_t)time_stamp() >> 22); + break; + } + + case SN_SELECTION_STRATEGY_MAC: { + eee->sn_selection_criterion_common_data = 0; break; } @@ -145,8 +160,15 @@ static SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_common_read (n2n_ /* Function that compare two selection_criterion fields and sorts them in ascending order. */ static int sn_selection_criterion_sort (peer_info_t *a, peer_info_t *b) { + int ret = 0; + // comparison function for sorting supernodes in ascending order of their selection_criterion. - return (a->selection_criterion - b->selection_criterion); + if(a->selection_criterion > b->selection_criterion) + ret = 1; + else if(a->selection_criterion < b->selection_criterion) + ret = -2; + + return ret; } @@ -177,7 +199,7 @@ SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_gather_data (n2n_sn_t *s data += tmp; } - return htobe32(data); + return htobe64(data); } @@ -195,7 +217,7 @@ extern char * sn_selection_criterion_str (n2n_edge_t *eee, selection_criterion_s // keep off the super-big values (used for "bad" or "good" or "undetermined" supernodes, // easier to sort to the end of the list). // Alternatively, typecast to (int16_t) and check for greater or equal zero - if(peer->selection_criterion < (UINT32_MAX >> 2)) { + if(peer->selection_criterion < (UINT64_MAX >> 2)) { switch(eee->conf.sn_selection_strategy) { @@ -209,6 +231,11 @@ extern char * sn_selection_criterion_str (n2n_edge_t *eee, selection_criterion_s break; } + case SN_SELECTION_STRATEGY_MAC: { + chars = snprintf(out, SN_SELECTION_CRITERION_BUF_SIZE, "%s", (int64_t)peer->selection_criterion > 0 ? "active" : ""); + break; + } + default: { // this should never happen traceEvent(TRACE_ERROR, "selection_criterion unknown selection strategy configuration");