Browse Source

added optional rtt based supernode selection: federation (#580)

pull/582/head
Logan oos Even 4 years ago
committed by GitHub
parent
commit
8761ae849b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      doc/Building.md
  2. 4
      doc/Federation.md
  3. 43
      src/sn_selection.c

10
doc/Building.md

@ -137,3 +137,13 @@ which then will include ZSTD if found on the system. It will be available via `-
`./configure --with-zstd --with-openssl CFLAGS="-O3 -march=native"` `./configure --with-zstd --with-openssl CFLAGS="-O3 -march=native"`
Again, and this needs to be reiterated sufficiently often, please do no forget to `make clean` after (re-)configuration and before building (again) using `make`. Again, and this needs to be reiterated sufficiently often, please do no forget to `make clean` after (re-)configuration and before building (again) using `make`.
## Federation – Supernode Selection by Round Trip Time
If used with multiple supernodes, by default, an edge choses the least loaded supernode to connect to. This selection strategy is part of the [federation](Federation.md) feature and aims at a fair workload distribution among the supernodes. To serve special scenarios, an edge can be compiled to always connect to the supernode with the lowest round trip time, i.e. the "closest" with the lowest ping. However, this could result in not so fair workload distribution among supernodes. This option can be configured by defining the macro `SN_SELECTION_RTT` and affects edge's behaviour only:
`./configure CFLAGS="-DSN_SELECTION_RTT"`
which of course can be combined with the compiler optimizations mentioned above…
Note that the activation of this strategy requires a sufficiently accurate local day-of-time clock. It probably will fail on smaller systems using `uclibc` (instead of `glibc`) whose day-of-time clock is said to not provide sub-second accuracy.

4
doc/Federation.md

@ -1,4 +1,4 @@
# Supernode Federation # Supernode Federation
## Idea ## Idea
To enhance resilience in terms of backup and fail-over, also for load-balancing, multiple supernodes can easily interconnect and form a special community, called **federation**. To enhance resilience in terms of backup and fail-over, also for load-balancing, multiple supernodes can easily interconnect and form a special community, called **federation**.
@ -33,3 +33,5 @@ Once edges have saved those informations, it is up to them choosing the supernod
An edge connects to the supernode with the lowest work-load and it is re-considered from time to time, with each re-registration. We used a stickyness factor to avoid too much jumping between supernodes. An edge connects to the supernode with the lowest work-load and it is re-considered from time to time, with each re-registration. We used a stickyness factor to avoid too much jumping between supernodes.
Thanks to this last feature, n2n is now able to handle security attacks (e.g., DoS against supernodes) and it can redistribute the entire load of the network in a fair manner between all the supernodes. Thanks to this last feature, n2n is now able to handle security attacks (e.g., DoS against supernodes) and it can redistribute the entire load of the network in a fair manner between all the supernodes.
To serve scenarios in which an edge is supposed to select the supernode by round trip time, i.e. choosing the "closest" one, a [compile-time option](Building.md) is offered. Note, that workload distribution among supernodes is not so fair then.

43
src/sn_selection.c

@ -1,5 +1,5 @@
/** /**
* (C) 2007-20 - ntop.org and contributors * (C) 2007-21 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -16,13 +16,13 @@
* *
*/ */
#include "n2n.h" #include "n2n.h"
static SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_common_read (n2n_edge_t *eee); static SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_common_read (n2n_edge_t *eee);
static int sn_selection_criterion_sort (peer_info_t *a, peer_info_t *b); static int sn_selection_criterion_sort (peer_info_t *a, peer_info_t *b);
/* ****************************************************************************** */
/* Initialize selection_criterion field in peer_info structure*/ /* Initialize selection_criterion field in peer_info structure*/
int sn_selection_criterion_init (peer_info_t *peer) { int sn_selection_criterion_init (peer_info_t *peer) {
@ -34,6 +34,7 @@ int sn_selection_criterion_init (peer_info_t *peer) {
return 0; /* OK */ return 0; /* OK */
} }
/* Set selection_criterion field to default value according to selected strategy. */ /* Set selection_criterion field to default value according to selected strategy. */
int sn_selection_criterion_default (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion) { int sn_selection_criterion_default (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion) {
@ -42,6 +43,7 @@ int sn_selection_criterion_default (SN_SELECTION_CRITERION_DATA_TYPE *selection_
return 0; /* OK */ return 0; /* OK */
} }
/* Take data from PEER_INFO payload and transform them into a selection_criterion. /* Take data from PEER_INFO payload and transform them into a selection_criterion.
* This function is highly dependant of the chosen selection criterion. * This function is highly dependant of the chosen selection criterion.
*/ */
@ -51,6 +53,8 @@ int sn_selection_criterion_calculate (n2n_edge_t *eee, peer_info_t *peer, SN_SEL
int sum = 0; int sum = 0;
common_data = sn_selection_criterion_common_read(eee); common_data = sn_selection_criterion_common_read(eee);
#ifndef SN_SELECTION_RTT
peer->selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)(be32toh(*data) + common_data); peer->selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)(be32toh(*data) + common_data);
/* Mitigation of the real supernode load in order to see less oscillations. /* Mitigation of the real supernode load in order to see less oscillations.
@ -61,13 +65,18 @@ int sn_selection_criterion_calculate (n2n_edge_t *eee, peer_info_t *peer, SN_SEL
sum = HASH_COUNT(eee->known_peers) + HASH_COUNT(eee->pending_peers); sum = HASH_COUNT(eee->known_peers) + HASH_COUNT(eee->pending_peers);
peer->selection_criterion = peer->selection_criterion * sum / (sum + 1); peer->selection_criterion = peer->selection_criterion * sum / (sum + 1);
} }
#else
peer->selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)(time_stamp() >> 22) - common_data;
#endif
return 0; /* OK */ return 0; /* OK */
} }
/* Set sn_selection_criterion_common_data field to default value. */ /* Set sn_selection_criterion_common_data field to default value. */
int sn_selection_criterion_common_data_default (n2n_edge_t *eee) { int sn_selection_criterion_common_data_default (n2n_edge_t *eee) {
#ifndef SN_SELECTION_RTT
SN_SELECTION_CRITERION_DATA_TYPE tmp = 0; SN_SELECTION_CRITERION_DATA_TYPE tmp = 0;
tmp = HASH_COUNT(eee->pending_peers); tmp = HASH_COUNT(eee->pending_peers);
@ -75,16 +84,21 @@ int sn_selection_criterion_common_data_default (n2n_edge_t *eee) {
tmp *= 2; tmp *= 2;
} }
eee->sn_selection_criterion_common_data = tmp / HASH_COUNT(eee->conf.supernodes); eee->sn_selection_criterion_common_data = tmp / HASH_COUNT(eee->conf.supernodes);
#else
eee->sn_selection_criterion_common_data = (SN_SELECTION_CRITERION_DATA_TYPE)(time_stamp() >> 22);
#endif
return 0; /* OK */ return 0; /* OK */
} }
/* Return the value of sn_selection_criterion_common_data field. */ /* Return the value of sn_selection_criterion_common_data field. */
static SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_common_read (n2n_edge_t *eee) { static SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_common_read (n2n_edge_t *eee) {
return eee->sn_selection_criterion_common_data; return eee->sn_selection_criterion_common_data;
} }
/* Function that compare two selection_criterion fields and sorts them in ascending order. */ /* 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) { static int sn_selection_criterion_sort (peer_info_t *a, peer_info_t *b) {
@ -92,6 +106,7 @@ static int sn_selection_criterion_sort (peer_info_t *a, peer_info_t *b) {
return (a->selection_criterion - b->selection_criterion); return (a->selection_criterion - b->selection_criterion);
} }
/* Function that sorts peer_list using sn_selection_criterion_sort. */ /* Function that sorts peer_list using sn_selection_criterion_sort. */
int sn_selection_sort (peer_info_t **peer_list) { int sn_selection_sort (peer_info_t **peer_list) {
@ -100,15 +115,20 @@ int sn_selection_sort (peer_info_t **peer_list) {
return 0; /* OK */ return 0; /* OK */
} }
/* Function that gathers requested data on a supernode. */
/* Function that gathers requested data on a supernode.
* it remains unaffected by SN_SELECT_RTT macro because it refers to edge behaviour only
*/
SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_gather_data (n2n_sn_t *sss) { SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_gather_data (n2n_sn_t *sss) {
SN_SELECTION_CRITERION_DATA_TYPE data = 0, tmp = 0; SN_SELECTION_CRITERION_DATA_TYPE data = 0, tmp = 0;
struct sn_community *comm, *tmp_comm; struct sn_community *comm, *tmp_comm;
HASH_ITER(hh, sss->communities, comm, tmp_comm) { HASH_ITER(hh, sss->communities, comm, tmp_comm) {
tmp = HASH_COUNT(comm->edges) + 1; /* number of nodes in the community + the community itself. */ // number of nodes in the community + the community itself
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { /*double-count encrypted communities (and their nodes): they exert more load on supernode. */ tmp = HASH_COUNT(comm->edges) + 1;
if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
// double-count encrypted communities (and their nodes): they exert more load on supernode
tmp *= 2; tmp *= 2;
} }
data += tmp; data += tmp;
@ -117,6 +137,7 @@ SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_gather_data (n2n_sn_t *s
return htobe32(data); return htobe32(data);
} }
/* Convert selection_criterion field in a string for management port output. */ /* Convert selection_criterion field in a string for management port output. */
extern char * sn_selection_criterion_str (selection_criterion_str_t out, peer_info_t *peer) { extern char * sn_selection_criterion_str (selection_criterion_str_t out, peer_info_t *peer) {
@ -124,7 +145,17 @@ extern char * sn_selection_criterion_str (selection_criterion_str_t out, peer_in
return NULL; return NULL;
} }
memset(out, 0, SN_SELECTION_CRITERION_BUF_SIZE); memset(out, 0, SN_SELECTION_CRITERION_BUF_SIZE);
snprintf(out, SN_SELECTION_CRITERION_BUF_SIZE - 1, "ld = %d", (short int)(peer->selection_criterion));
#ifndef SN_SELECTION_RTT
snprintf(out, SN_SELECTION_CRITERION_BUF_SIZE - 1,
(int16_t)(peer->selection_criterion) != -1 ? "ld = %7d" :
"ld = _______", peer->selection_criterion);
#else
snprintf(out, SN_SELECTION_CRITERION_BUF_SIZE - 1,
(int16_t)(peer->selection_criterion) != -1 ? "rtt %5d ms" :
"rtt _____ ms", peer->selection_criterion);
#endif
return out; return out;
} }

Loading…
Cancel
Save