This commit implements average RTT estimation based on PING-PONG between active TCP connections.
Average RTT can be used to update edge weight and propagate it to the network. tinc dump edges has been also extended to give the current RTT. New edge weight will change only if the config has EdgeUpdateInterval set to other value than 0. - Ignore local configuration for editors - Extended manpage with informations about EdgeUpdateInterval - Added clone_edge and fixed potential segfault when b->from not defined - Compute avg_rtt based on the time values we got back in PONG - Add avg_rtt on dump edge - Send current time on PING and return it on PONG - Changed last_ping_time to struct timeval - Extended edge_t with avg_rtt
This commit is contained in:
parent
9910f8f2d1
commit
0cd387fd90
14 changed files with 149 additions and 33 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -13,5 +13,6 @@ Makefile.in
|
|||
/missing
|
||||
INSTALL
|
||||
.deps
|
||||
.dir-locals.el
|
||||
stamp-h1
|
||||
/src/device.c
|
||||
|
|
|
@ -276,6 +276,12 @@ When this option is enabled, packets that cannot be sent directly to the destina
|
|||
but which would have to be forwarded by an intermediate node, are dropped instead.
|
||||
When combined with the IndirectData option,
|
||||
packets for nodes for which we do not have a meta connection with are also dropped.
|
||||
.It Va EdgeUpdateInterval Li = Ar seconds Pq 0
|
||||
The number of seconds between notification of edge changes.
|
||||
.Nm tinc
|
||||
will send updated edge informations to all active connections. When the value is 0
|
||||
.Nm tinc
|
||||
will not send any updates.
|
||||
.It Va Ed25519PrivateKeyFile Li = Ar filename Po Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /ed25519_key.priv Pc
|
||||
The file in which the private Ed25519 key of this tinc daemon resides.
|
||||
This is only used if
|
||||
|
|
|
@ -99,7 +99,7 @@ typedef struct connection_t {
|
|||
int tcplen; /* length of incoming TCPpacket */
|
||||
int allow_request; /* defined if there's only one request possible */
|
||||
|
||||
time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */
|
||||
struct timeval last_ping_time; /* last time we saw some activity from the other end or pinged them */
|
||||
|
||||
splay_tree_t *config_tree; /* Pointer to configuration tree belonging to him */
|
||||
} connection_t;
|
||||
|
|
37
src/edge.c
37
src/edge.c
|
@ -43,10 +43,12 @@ static int edge_weight_compare(const edge_t *a, const edge_t *b) {
|
|||
if(result)
|
||||
return result;
|
||||
|
||||
result = strcmp(a->from->name, b->from->name);
|
||||
if (a->from && b->from) {
|
||||
result = strcmp(a->from->name, b->from->name);
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
return strcmp(a->to->name, b->to->name);
|
||||
}
|
||||
|
@ -97,6 +99,26 @@ void edge_del(edge_t *e) {
|
|||
splay_delete(e->from->edge_tree, e);
|
||||
}
|
||||
|
||||
edge_t *clone_edge(edge_t *e) {
|
||||
edge_t *v;
|
||||
|
||||
v = new_edge();
|
||||
v->from = e->from;
|
||||
v->to = e->to;
|
||||
|
||||
memcpy(&v->address, &e->address, sizeof(sockaddr_t));
|
||||
memcpy(&v->local_address, &e->local_address, sizeof(sockaddr_t));
|
||||
|
||||
v->options = e->options;
|
||||
v->weight = e->weight;
|
||||
v->avg_rtt = e->avg_rtt;
|
||||
v->connection = e->connection;
|
||||
v->reverse = e->reverse;
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
edge_t *lookup_edge(node_t *from, node_t *to) {
|
||||
edge_t v;
|
||||
|
||||
|
@ -111,10 +133,11 @@ bool dump_edges(connection_t *c) {
|
|||
for splay_each(edge_t, e, n->edge_tree) {
|
||||
char *address = sockaddr2hostname(&e->address);
|
||||
char* local_address = sockaddr2hostname(&e->local_address);
|
||||
send_request(c, "%d %d %s %s %s %s %x %d",
|
||||
CONTROL, REQ_DUMP_EDGES,
|
||||
e->from->name, e->to->name, address,
|
||||
local_address, e->options, e->weight);
|
||||
send_request(c, "%d %d %s %s %s %s %x %d %d",
|
||||
CONTROL, REQ_DUMP_EDGES,
|
||||
e->from->name, e->to->name, address,
|
||||
local_address, e->options, e->weight,
|
||||
e->avg_rtt);
|
||||
free(address);
|
||||
free(local_address);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ typedef struct edge_t {
|
|||
|
||||
uint32_t options; /* options turned on for this edge */
|
||||
int weight; /* weight of this edge */
|
||||
int avg_rtt; /* average RTT */
|
||||
|
||||
struct connection_t *connection; /* connection associated with this edge, if available */
|
||||
struct edge_t *reverse; /* edge in the opposite direction, if available */
|
||||
|
@ -50,6 +51,7 @@ extern void free_edge_tree(splay_tree_t *);
|
|||
extern void edge_add(edge_t *);
|
||||
extern void edge_del(edge_t *);
|
||||
extern edge_t *lookup_edge(struct node_t *, struct node_t *);
|
||||
extern edge_t *clone_edge(edge_t *);
|
||||
extern bool dump_edges(struct connection_t *);
|
||||
|
||||
#endif /* __TINC_EDGE_H__ */
|
||||
|
|
12
src/net.c
12
src/net.c
|
@ -148,12 +148,12 @@ static void timeout_handler(void *data) {
|
|||
if(c->status.control)
|
||||
continue;
|
||||
|
||||
if(c->last_ping_time + pingtimeout <= now.tv_sec) {
|
||||
if(c->last_ping_time.tv_sec + pingtimeout <= now.tv_sec) {
|
||||
if(c->edge) {
|
||||
try_tx(c->node, false);
|
||||
if(c->status.pinged) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now.tv_sec - c->last_ping_time);
|
||||
} else if(c->last_ping_time + pinginterval <= now.tv_sec) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now.tv_sec - c->last_ping_time.tv_sec);
|
||||
} else if(c->last_ping_time.tv_sec + pinginterval <= now.tv_sec) {
|
||||
send_ping(c);
|
||||
continue;
|
||||
} else {
|
||||
|
@ -431,8 +431,10 @@ void retry(void) {
|
|||
|
||||
/* Check for outgoing connections that are in progress, and reset their ping timers */
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->outgoing && !c->node)
|
||||
c->last_ping_time = 0;
|
||||
if(c->outgoing && !c->node) {
|
||||
c->last_ping_time.tv_sec = 0;
|
||||
c->last_ping_time.tv_usec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Kick the ping timeout handler */
|
||||
|
|
|
@ -147,6 +147,7 @@ extern listen_socket_t listen_socket[MAXSOCKETS];
|
|||
extern int listen_sockets;
|
||||
extern io_t unix_socket;
|
||||
extern int keylifetime;
|
||||
extern int edgeupdateinterval;
|
||||
extern int udp_rcvbuf;
|
||||
extern int udp_sndbuf;
|
||||
extern int max_connection_burst;
|
||||
|
@ -209,6 +210,7 @@ extern bool read_rsa_public_key(struct connection_t *);
|
|||
extern void handle_device_data(void *, int);
|
||||
extern void handle_meta_connection_data(struct connection_t *);
|
||||
extern void regenerate_key(void);
|
||||
extern void update_edge_weight(void);
|
||||
extern void purge(void);
|
||||
extern void retry(void);
|
||||
extern int reload_configuration(void);
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#define MIN_PROBE_SIZE 18
|
||||
|
||||
int keylifetime = 0;
|
||||
int edgeupdateinterval = 0;
|
||||
#ifdef HAVE_LZO
|
||||
static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
|
||||
#endif
|
||||
|
|
|
@ -311,12 +311,18 @@ static bool read_rsa_private_key(void) {
|
|||
#endif
|
||||
|
||||
static timeout_t keyexpire_timeout;
|
||||
static timeout_t edgeupdate_timeout;
|
||||
|
||||
static void keyexpire_handler(void *data) {
|
||||
regenerate_key();
|
||||
timeout_set(data, &(struct timeval){keylifetime, rand() % 100000});
|
||||
}
|
||||
|
||||
static void edgeupdate_handler(void *data) {
|
||||
update_edge_weight();
|
||||
timeout_set(data, &(struct timeval){edgeupdateinterval, rand() % 100000});
|
||||
}
|
||||
|
||||
void regenerate_key(void) {
|
||||
logger(DEBUG_STATUS, LOG_INFO, "Expiring symmetric keys");
|
||||
send_key_changed();
|
||||
|
@ -324,6 +330,29 @@ void regenerate_key(void) {
|
|||
n->status.validkey_in = false;
|
||||
}
|
||||
|
||||
void update_edge_weight(void) {
|
||||
edge_t *t = NULL;
|
||||
logger(DEBUG_STATUS, LOG_INFO, "Update edge weight");
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if (c->status.control || !c->edge)
|
||||
continue;
|
||||
|
||||
if (c->edge->avg_rtt) {
|
||||
|
||||
t = clone_edge(c->edge);
|
||||
send_del_edge(c, c->edge);
|
||||
edge_del(c->edge);
|
||||
/* avg_rtt is in ms */
|
||||
t->weight = t->avg_rtt*10;
|
||||
c->edge = t;
|
||||
edge_add(t);
|
||||
send_add_edge(c, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Read Subnets from all host config files
|
||||
*/
|
||||
|
@ -624,6 +653,9 @@ bool setup_myself_reloadable(void) {
|
|||
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
|
||||
keylifetime = 3600;
|
||||
|
||||
if(!get_config_int(lookup_config(config_tree, "EdgeUpdateInterval"), &edgeupdateinterval))
|
||||
edgeupdateinterval = 0;
|
||||
|
||||
config_t *cfg = lookup_config(config_tree, "AutoConnect");
|
||||
if(cfg) {
|
||||
if(!get_config_bool(cfg, &autoconnect)) {
|
||||
|
@ -894,6 +926,9 @@ static bool setup_myself(void) {
|
|||
|
||||
timeout_add(&keyexpire_timeout, keyexpire_handler, &keyexpire_timeout, &(struct timeval){keylifetime, rand() % 100000});
|
||||
|
||||
if (edgeupdateinterval)
|
||||
timeout_add(&edgeupdate_timeout, edgeupdate_handler, &edgeupdate_timeout, &(struct timeval){edgeupdateinterval, rand() % 100000});
|
||||
|
||||
/* Check if we want to use message authentication codes... */
|
||||
|
||||
int maclength = 4;
|
||||
|
|
|
@ -319,7 +319,7 @@ void retry_outgoing(outgoing_t *outgoing) {
|
|||
void finish_connecting(connection_t *c) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
|
||||
|
||||
c->last_ping_time = now.tv_sec;
|
||||
c->last_ping_time = now;
|
||||
c->status.connecting = false;
|
||||
|
||||
send_id(c);
|
||||
|
@ -555,7 +555,7 @@ begin:
|
|||
#endif
|
||||
c->outmaclength = myself->connection->outmaclength;
|
||||
c->outcompression = myself->connection->outcompression;
|
||||
c->last_ping_time = now.tv_sec;
|
||||
c->last_ping_time = now;
|
||||
|
||||
connection_add(c);
|
||||
|
||||
|
@ -708,7 +708,7 @@ void handle_new_meta_connection(void *data, int flags) {
|
|||
c->address = sa;
|
||||
c->hostname = sockaddr2hostname(&sa);
|
||||
c->socket = fd;
|
||||
c->last_ping_time = now.tv_sec;
|
||||
c->last_ping_time = now;
|
||||
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);
|
||||
|
||||
|
@ -747,7 +747,7 @@ void handle_new_unix_connection(void *data, int flags) {
|
|||
c->address = sa;
|
||||
c->hostname = xstrdup("localhost port unix");
|
||||
c->socket = fd;
|
||||
c->last_ping_time = now.tv_sec;
|
||||
c->last_ping_time = now;
|
||||
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ extern bool send_error(struct connection_t *, int, const char *);
|
|||
extern bool send_termreq(struct connection_t *);
|
||||
extern bool send_ping(struct connection_t *);
|
||||
extern bool send_pong(struct connection_t *);
|
||||
bool send_pong_v2(connection_t *c, int, int);
|
||||
extern bool send_add_subnet(struct connection_t *, const struct subnet_t *);
|
||||
extern bool send_del_subnet(struct connection_t *, const struct subnet_t *);
|
||||
extern bool send_add_edge(struct connection_t *, const struct edge_t *);
|
||||
|
|
|
@ -295,7 +295,8 @@ bool id_h(connection_t *c, const char *request) {
|
|||
if(name[0] == '^' && !strcmp(name + 1, controlcookie)) {
|
||||
c->status.control = true;
|
||||
c->allow_request = CONTROL;
|
||||
c->last_ping_time = now.tv_sec + 3600;
|
||||
c->last_ping_time = now;
|
||||
c->last_ping_time.tv_sec += 3600;
|
||||
|
||||
free(c->name);
|
||||
c->name = xstrdup("<control>");
|
||||
|
|
|
@ -89,13 +89,26 @@ bool termreq_h(connection_t *c, const char *request) {
|
|||
|
||||
bool send_ping(connection_t *c) {
|
||||
c->status.pinged = true;
|
||||
c->last_ping_time = now.tv_sec;
|
||||
c->last_ping_time = now;
|
||||
|
||||
return send_request(c, "%d", PING);
|
||||
return send_request(c, "%d %d %d", PING, c->last_ping_time.tv_sec, c->last_ping_time.tv_usec);
|
||||
}
|
||||
|
||||
bool ping_h(connection_t *c, const char *request) {
|
||||
return send_pong(c);
|
||||
int tv_sec, tv_usec, ret;
|
||||
|
||||
ret = sscanf(request, "%*d %d %d", &tv_sec, &tv_usec);
|
||||
|
||||
if (ret == 2) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Got PING from %s (%s) %d", c->name, request, ret);
|
||||
return send_pong_v2(c, tv_sec, tv_usec);
|
||||
} else {
|
||||
return send_pong(c);
|
||||
}
|
||||
}
|
||||
|
||||
bool send_pong_v2(connection_t *c, int tv_sec, int tv_usec) {
|
||||
return send_request(c, "%d %d %d", PONG, tv_sec, tv_usec);
|
||||
}
|
||||
|
||||
bool send_pong(connection_t *c) {
|
||||
|
@ -103,8 +116,37 @@ bool send_pong(connection_t *c) {
|
|||
}
|
||||
|
||||
bool pong_h(connection_t *c, const char *request) {
|
||||
int current_rtt = 0;
|
||||
int tv_sec, tv_usec, ret;
|
||||
struct timeval _now;
|
||||
c->status.pinged = false;
|
||||
|
||||
ret = sscanf(request, "%*d %d %d", &tv_sec, &tv_usec);
|
||||
gettimeofday(&_now, NULL);
|
||||
|
||||
if (ret != 2) {
|
||||
/* We got PONG from older node */
|
||||
tv_sec = c->last_ping_time.tv_sec;
|
||||
tv_usec = c->last_ping_time.tv_usec;
|
||||
}
|
||||
|
||||
/* RTT should be in ms */
|
||||
current_rtt = (_now.tv_sec - tv_sec)*1000;
|
||||
/* Compute diff between usec */
|
||||
current_rtt += _now.tv_usec >= tv_usec ? _now.tv_usec - tv_usec : tv_usec - _now.tv_usec;
|
||||
|
||||
current_rtt = current_rtt/1000;
|
||||
|
||||
if (c->edge->avg_rtt == 0)
|
||||
c->edge->avg_rtt = current_rtt;
|
||||
else
|
||||
c->edge->avg_rtt = (current_rtt + c->edge->avg_rtt)/2;
|
||||
|
||||
|
||||
if (c->edge->reverse) {
|
||||
c->edge->reverse->avg_rtt = c->edge->avg_rtt;
|
||||
}
|
||||
|
||||
/* Succesful connection, reset timeout if this is an outgoing connection. */
|
||||
|
||||
if(c->outgoing) {
|
||||
|
|
|
@ -1021,7 +1021,7 @@ static int cmd_dump(int argc, char *argv[]) {
|
|||
char local_port[4096];
|
||||
char via[4096];
|
||||
char nexthop[4096];
|
||||
int cipher, digest, maclength, compression, distance, socket, weight;
|
||||
int cipher, digest, maclength, compression, distance, socket, weight, avg_rtt;
|
||||
short int pmtu, minmtu, maxmtu;
|
||||
unsigned int options, status_int;
|
||||
node_status_t status;
|
||||
|
@ -1059,8 +1059,8 @@ static int cmd_dump(int argc, char *argv[]) {
|
|||
} break;
|
||||
|
||||
case REQ_DUMP_EDGES: {
|
||||
int n = sscanf(line, "%*d %*d %s %s %s port %s %s port %s %x %d", from, to, host, port, local_host, local_port, &options, &weight);
|
||||
if(n != 8) {
|
||||
int n = sscanf(line, "%*d %*d %s %s %s port %s %s port %s %x %d %d", from, to, host, port, local_host, local_port, &options, &weight, &avg_rtt);
|
||||
if(n != 9) {
|
||||
fprintf(stderr, "Unable to parse edge dump from tincd.\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -1072,7 +1072,7 @@ static int cmd_dump(int argc, char *argv[]) {
|
|||
else if(do_graph == 2)
|
||||
printf(" %s -> %s [w = %f, weight = %f];\n", node1, node2, w, w);
|
||||
} else {
|
||||
printf("%s to %s at %s port %s local %s port %s options %x weight %d\n", from, to, host, port, local_host, local_port, options, weight);
|
||||
printf("%s to %s at %s port %s local %s port %s options %x weight %d avg_rtt %d\n", from, to, host, port, local_host, local_port, options, weight, avg_rtt);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue