Dump through control socket
Note this removes SIGUSR1, SIGUSR2, and the graph dumping config option. It seems cleaner to do everything through the control socket.
This commit is contained in:
parent
50ad3f2a89
commit
6eaefb4dbc
18 changed files with 113 additions and 125 deletions
|
@ -147,18 +147,6 @@ instead of
|
|||
.Va Device .
|
||||
The info pages of the tinc package contain more information
|
||||
about configuring the virtual network device.
|
||||
.It Va GraphDumpFile Li = Ar filename Bq experimental
|
||||
If this option is present,
|
||||
.Nm tinc
|
||||
will dump the current network graph to the file
|
||||
.Ar filename
|
||||
every minute, unless there were no changes to the graph.
|
||||
The file is in a format that can be read by graphviz tools.
|
||||
If
|
||||
.Ar filename
|
||||
starts with a pipe symbol |,
|
||||
then the rest of the filename is interpreted as a shell command
|
||||
that is executed, the graph is then sent to stdin.
|
||||
.It Va Hostnames Li = yes | no Pq no
|
||||
This option selects whether IP addresses (both real and on the VPN) should
|
||||
be resolved. Since DNS lookups are blocking, it might affect tinc's
|
||||
|
|
|
@ -885,16 +885,6 @@ Under Windows, use @var{Interface} instead of @var{Device}.
|
|||
Note that you can only use one device per daemon.
|
||||
See also @ref{Device files}.
|
||||
|
||||
@cindex GraphDumpFile
|
||||
@item GraphDumpFile = <@var{filename}> [experimental]
|
||||
If this option is present,
|
||||
tinc will dump the current network graph to the file @var{filename}
|
||||
every minute, unless there were no changes to the graph.
|
||||
The file is in a format that can be read by graphviz tools.
|
||||
If @var{filename} starts with a pipe symbol |,
|
||||
then the rest of the filename is interpreted as a shell command
|
||||
that is executed, the graph is then sent to stdin.
|
||||
|
||||
@cindex Hostnames
|
||||
@item Hostnames = <yes|no> (no)
|
||||
This option selects whether IP addresses (both real and on the VPN)
|
||||
|
@ -1579,12 +1569,6 @@ New outgoing connections specified in @file{tinc.conf} will be made.
|
|||
Temporarily increases debug level to 5.
|
||||
Send this signal again to revert to the original level.
|
||||
|
||||
@item USR1
|
||||
Dumps the connection list to syslog.
|
||||
|
||||
@item USR2
|
||||
Dumps virtual network device statistics, all known nodes, edges and subnets to syslog.
|
||||
|
||||
@item WINCH
|
||||
Purges all information remembered about unreachable nodes.
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ Dump a graph of the VPN in
|
|||
format.
|
||||
.El
|
||||
.Sh BUGS
|
||||
The "start", "restart", "reload", and "dump" commands are not yet implemented.
|
||||
The "start", "restart", and "reload" commands are not yet implemented.
|
||||
.Pp
|
||||
If you find any bugs, report them to tinc@tinc-vpn.org.
|
||||
.Sh SEE ALSO
|
||||
|
|
|
@ -98,10 +98,6 @@ will be made.
|
|||
.It INT
|
||||
Temporarily increases debug level to 5.
|
||||
Send this signal again to revert to the original level.
|
||||
.It USR1
|
||||
Dumps the connection list to syslog.
|
||||
.It USR2
|
||||
Dumps virtual network device statistics, all known nodes, edges and subnets to syslog.
|
||||
.It WINCH
|
||||
Purges all information remembered about unreachable nodes.
|
||||
.El
|
||||
|
|
|
@ -106,21 +106,22 @@ void connection_del(connection_t *c) {
|
|||
splay_delete(connection_tree, c);
|
||||
}
|
||||
|
||||
void dump_connections(void) {
|
||||
int dump_connections(struct evbuffer *out) {
|
||||
splay_node_t *node;
|
||||
connection_t *c;
|
||||
|
||||
cp();
|
||||
|
||||
logger(LOG_DEBUG, _("Connections:"));
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
logger(LOG_DEBUG, _(" %s at %s options %lx socket %d status %04x"),
|
||||
c->name, c->hostname, c->options, c->socket, c->status.value);
|
||||
if(evbuffer_add_printf(out,
|
||||
_(" %s at %s options %lx socket %d status %04x\n"),
|
||||
c->name, c->hostname, c->options, c->socket,
|
||||
c->status.value) == -1)
|
||||
return errno;
|
||||
}
|
||||
|
||||
logger(LOG_DEBUG, _("End of connections."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool read_connection_config(connection_t *c) {
|
||||
|
|
|
@ -109,7 +109,7 @@ extern connection_t *new_connection(void) __attribute__ ((__malloc__));
|
|||
extern void free_connection(connection_t *);
|
||||
extern void connection_add(connection_t *);
|
||||
extern void connection_del(connection_t *);
|
||||
extern void dump_connections(void);
|
||||
extern int dump_connections(struct evbuffer *);
|
||||
extern bool read_connection_config(connection_t *);
|
||||
|
||||
#endif /* __TINC_CONNECTION_H__ */
|
||||
|
|
|
@ -62,11 +62,41 @@ static void handle_control_data(struct bufferevent *event, void *data) {
|
|||
}
|
||||
|
||||
if(req.type == REQ_STOP) {
|
||||
logger(LOG_NOTICE, _("Got stop command"));
|
||||
logger(LOG_NOTICE, _("Got '%s' command"), "stop");
|
||||
event_loopexit(NULL);
|
||||
goto respond;
|
||||
}
|
||||
|
||||
if(req.type == REQ_DUMP_NODES) {
|
||||
logger(LOG_NOTICE, _("Got '%s' command"), "dump nodes");
|
||||
res.res_errno = dump_nodes(res_data);
|
||||
goto respond;
|
||||
}
|
||||
|
||||
if(req.type == REQ_DUMP_EDGES) {
|
||||
logger(LOG_NOTICE, _("Got '%s' command"), "dump edges");
|
||||
res.res_errno = dump_edges(res_data);
|
||||
goto respond;
|
||||
}
|
||||
|
||||
if(req.type == REQ_DUMP_SUBNETS) {
|
||||
logger(LOG_NOTICE, _("Got '%s' command"), "dump subnets");
|
||||
res.res_errno = dump_subnets(res_data);
|
||||
goto respond;
|
||||
}
|
||||
|
||||
if(req.type == REQ_DUMP_CONNECTIONS) {
|
||||
logger(LOG_NOTICE, _("Got '%s' command"), "dump connections");
|
||||
res.res_errno = dump_connections(res_data);
|
||||
goto respond;
|
||||
}
|
||||
|
||||
if(req.type == REQ_DUMP_GRAPH) {
|
||||
logger(LOG_NOTICE, _("Got '%s' command"), "dump graph");
|
||||
res.res_errno = dump_graph(res_data);
|
||||
goto respond;
|
||||
}
|
||||
|
||||
logger(LOG_DEBUG, _("Malformed control command received"));
|
||||
res.res_errno = EINVAL;
|
||||
|
||||
|
|
|
@ -26,6 +26,11 @@ enum request_type {
|
|||
REQ_STOP,
|
||||
REQ_RELOAD,
|
||||
REQ_RESTART,
|
||||
REQ_DUMP_NODES,
|
||||
REQ_DUMP_EDGES,
|
||||
REQ_DUMP_SUBNETS,
|
||||
REQ_DUMP_CONNECTIONS,
|
||||
REQ_DUMP_GRAPH,
|
||||
};
|
||||
|
||||
#define TINC_CTL_VERSION_CURRENT 0
|
||||
|
|
15
src/edge.c
15
src/edge.c
|
@ -125,7 +125,7 @@ edge_t *lookup_edge(node_t *from, node_t *to) {
|
|||
return splay_search(from->edge_tree, &v);
|
||||
}
|
||||
|
||||
void dump_edges(void) {
|
||||
int dump_edges(struct evbuffer *out) {
|
||||
splay_node_t *node, *node2;
|
||||
node_t *n;
|
||||
edge_t *e;
|
||||
|
@ -133,18 +133,21 @@ void dump_edges(void) {
|
|||
|
||||
cp();
|
||||
|
||||
logger(LOG_DEBUG, _("Edges:"));
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
|
||||
e = node2->data;
|
||||
address = sockaddr2hostname(&e->address);
|
||||
logger(LOG_DEBUG, _(" %s to %s at %s options %lx weight %d"),
|
||||
e->from->name, e->to->name, address, e->options, e->weight);
|
||||
if(evbuffer_add_printf(out,
|
||||
_(" %s to %s at %s options %lx weight %d\n"),
|
||||
e->from->name, e->to->name, address,
|
||||
e->options, e->weight) == -1) {
|
||||
free(address);
|
||||
return errno;
|
||||
}
|
||||
free(address);
|
||||
}
|
||||
}
|
||||
|
||||
logger(LOG_DEBUG, _("End of edges."));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,6 @@ 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 void dump_edges(void);
|
||||
extern int dump_edges(struct evbuffer *);
|
||||
|
||||
#endif /* __TINC_EDGE_H__ */
|
||||
|
|
55
src/graph.c
55
src/graph.c
|
@ -313,66 +313,37 @@ void sssp_bfs(void) {
|
|||
dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true
|
||||
*/
|
||||
|
||||
static void dump_graph(int fd, short events, void *data) {
|
||||
int dump_graph(struct evbuffer *out) {
|
||||
splay_node_t *node;
|
||||
node_t *n;
|
||||
edge_t *e;
|
||||
char *filename = NULL, *tmpname = NULL;
|
||||
FILE *file;
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename))
|
||||
return;
|
||||
|
||||
ifdebug(PROTOCOL) logger(LOG_NOTICE, "Dumping graph");
|
||||
|
||||
if(filename[0] == '|') {
|
||||
file = popen(filename + 1, "w");
|
||||
} else {
|
||||
asprintf(&tmpname, "%s.new", filename);
|
||||
file = fopen(tmpname, "w");
|
||||
}
|
||||
|
||||
if(!file) {
|
||||
logger(LOG_ERR, "Unable to open graph dump file %s: %s", filename, strerror(errno));
|
||||
free(tmpname);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(file, "digraph {\n");
|
||||
if(evbuffer_add_printf(out, "digraph {\n") == -1)
|
||||
return errno;
|
||||
|
||||
/* dump all nodes first */
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
fprintf(file, " %s [label = \"%s\"];\n", n->name, n->name);
|
||||
if(evbuffer_add_printf(out, " %s [label = \"%s\"];\n",
|
||||
n->name, n->name) == -1)
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* now dump all edges */
|
||||
for(node = edge_weight_tree->head; node; node = node->next) {
|
||||
e = node->data;
|
||||
fprintf(file, " %s -> %s;\n", e->from->name, e->to->name);
|
||||
if(evbuffer_add_printf(out, " %s -> %s;\n",
|
||||
e->from->name, e->to->name) == -1)
|
||||
return errno;
|
||||
}
|
||||
|
||||
fprintf(file, "}\n");
|
||||
|
||||
if(filename[0] == '|') {
|
||||
pclose(file);
|
||||
} else {
|
||||
fclose(file);
|
||||
#ifdef HAVE_MINGW
|
||||
unlink(filename);
|
||||
#endif
|
||||
rename(tmpname, filename);
|
||||
free(tmpname);
|
||||
}
|
||||
if(evbuffer_add_printf(out, "}\n") == -1)
|
||||
return errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void graph(void) {
|
||||
static struct event ev;
|
||||
|
||||
sssp_bfs();
|
||||
mst_kruskal();
|
||||
|
||||
if(!timeout_initialized(&ev))
|
||||
timeout_set(&ev, dump_graph, NULL);
|
||||
event_add(&ev, &(struct timeval){5, 0});
|
||||
}
|
||||
|
|
|
@ -26,6 +26,6 @@
|
|||
extern void graph(void);
|
||||
extern void mst_kruskal(void);
|
||||
extern void sssp_bfs(void);
|
||||
extern void dump_graph(void);
|
||||
extern int dump_graph(struct evbuffer *);
|
||||
|
||||
#endif /* __TINC_GRAPH_H__ */
|
||||
|
|
21
src/net.c
21
src/net.c
|
@ -252,19 +252,6 @@ static void sigint_handler(int signal, short events, void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
static void sigusr1_handler(int signal, short events, void *data) {
|
||||
logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
|
||||
dump_connections();
|
||||
}
|
||||
|
||||
static void sigusr2_handler(int signal, short events, void *data) {
|
||||
logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
|
||||
dump_device_stats();
|
||||
dump_nodes();
|
||||
dump_edges();
|
||||
dump_subnets();
|
||||
}
|
||||
|
||||
static void sigwinch_handler(int signal, short events, void *data) {
|
||||
logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
|
||||
purge();
|
||||
|
@ -346,8 +333,6 @@ int main_loop(void) {
|
|||
struct event sigint_event;
|
||||
struct event sigterm_event;
|
||||
struct event sigquit_event;
|
||||
struct event sigusr1_event;
|
||||
struct event sigusr2_event;
|
||||
struct event sigwinch_event;
|
||||
struct event sigalrm_event;
|
||||
|
||||
|
@ -363,10 +348,6 @@ int main_loop(void) {
|
|||
signal_add(&sigterm_event, NULL);
|
||||
signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL);
|
||||
signal_add(&sigquit_event, NULL);
|
||||
signal_set(&sigusr1_event, SIGUSR1, sigusr1_handler, NULL);
|
||||
signal_add(&sigusr1_event, NULL);
|
||||
signal_set(&sigusr2_event, SIGUSR2, sigusr2_handler, NULL);
|
||||
signal_add(&sigusr2_event, NULL);
|
||||
signal_set(&sigwinch_event, SIGWINCH, sigwinch_handler, NULL);
|
||||
signal_add(&sigwinch_event, NULL);
|
||||
signal_set(&sigalrm_event, SIGALRM, sigalrm_handler, NULL);
|
||||
|
@ -381,8 +362,6 @@ int main_loop(void) {
|
|||
signal_del(&sigint_event);
|
||||
signal_del(&sigterm_event);
|
||||
signal_del(&sigquit_event);
|
||||
signal_del(&sigusr1_event);
|
||||
signal_del(&sigusr2_event);
|
||||
signal_del(&sigwinch_event);
|
||||
signal_del(&sigalrm_event);
|
||||
event_del(&timeout_event);
|
||||
|
|
11
src/node.c
11
src/node.c
|
@ -160,22 +160,21 @@ node_t *lookup_node_udp(const sockaddr_t *sa) {
|
|||
return splay_search(node_udp_tree, &n);
|
||||
}
|
||||
|
||||
void dump_nodes(void) {
|
||||
int dump_nodes(struct evbuffer *out) {
|
||||
splay_node_t *node;
|
||||
node_t *n;
|
||||
|
||||
cp();
|
||||
|
||||
logger(LOG_DEBUG, _("Nodes:"));
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
logger(LOG_DEBUG, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)"),
|
||||
if(evbuffer_add_printf(out, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)\n"),
|
||||
n->name, n->hostname, n->cipher ? n->cipher->nid : 0,
|
||||
n->digest ? n->digest->type : 0, n->maclength, n->compression,
|
||||
n->options, *(uint32_t *)&n->status, n->nexthop ? n->nexthop->name : "-",
|
||||
n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu);
|
||||
n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu) == -1)
|
||||
return errno;
|
||||
}
|
||||
|
||||
logger(LOG_DEBUG, _("End of nodes."));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -94,6 +94,6 @@ extern void node_add(node_t *);
|
|||
extern void node_del(node_t *);
|
||||
extern node_t *lookup_node(char *);
|
||||
extern node_t *lookup_node_udp(const sockaddr_t *);
|
||||
extern void dump_nodes(void);
|
||||
extern int dump_nodes(struct evbuffer *);
|
||||
|
||||
#endif /* __TINC_NODE_H__ */
|
||||
|
|
10
src/subnet.c
10
src/subnet.c
|
@ -438,7 +438,7 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
|||
}
|
||||
}
|
||||
|
||||
void dump_subnets(void)
|
||||
int dump_subnets(struct evbuffer *out)
|
||||
{
|
||||
char netstr[MAXNETSTR];
|
||||
subnet_t *subnet;
|
||||
|
@ -446,14 +446,14 @@ void dump_subnets(void)
|
|||
|
||||
cp();
|
||||
|
||||
logger(LOG_DEBUG, _("Subnet list:"));
|
||||
|
||||
for(node = subnet_tree->head; node; node = node->next) {
|
||||
subnet = node->data;
|
||||
if(!net2str(netstr, sizeof netstr, subnet))
|
||||
continue;
|
||||
logger(LOG_DEBUG, _(" %s owner %s"), netstr, subnet->owner->name);
|
||||
if(evbuffer_add_printf(out, _(" %s owner %s\n"),
|
||||
netstr, subnet->owner->name) == -1)
|
||||
return errno;
|
||||
}
|
||||
|
||||
logger(LOG_DEBUG, _("End of subnet list."));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -81,6 +81,6 @@ extern subnet_t *lookup_subnet(const struct node_t *, const subnet_t *);
|
|||
extern subnet_t *lookup_subnet_mac(const mac_t *);
|
||||
extern subnet_t *lookup_subnet_ipv4(const ipv4_t *);
|
||||
extern subnet_t *lookup_subnet_ipv6(const ipv6_t *);
|
||||
extern void dump_subnets(void);
|
||||
extern int dump_subnets(struct evbuffer *);
|
||||
|
||||
#endif /* __TINC_SUBNET_H__ */
|
||||
|
|
|
@ -546,6 +546,38 @@ int main(int argc, char *argv[], char *envp[]) {
|
|||
return send_ctl_request_cooked(fd, REQ_RESTART, NULL, 0) != -1;
|
||||
}
|
||||
|
||||
if(!strcasecmp(argv[optind], "dump")) {
|
||||
if (argc < optind + 2) {
|
||||
fprintf(stderr, _("Not enough arguments.\n"));
|
||||
usage(true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!strcasecmp(argv[optind+1], "nodes")) {
|
||||
return send_ctl_request_cooked(fd, REQ_DUMP_NODES, NULL, 0) != -1;
|
||||
}
|
||||
|
||||
if(!strcasecmp(argv[optind+1], "edges")) {
|
||||
return send_ctl_request_cooked(fd, REQ_DUMP_EDGES, NULL, 0) != -1;
|
||||
}
|
||||
|
||||
if(!strcasecmp(argv[optind+1], "subnets")) {
|
||||
return send_ctl_request_cooked(fd, REQ_DUMP_SUBNETS, NULL, 0) != -1;
|
||||
}
|
||||
|
||||
if(!strcasecmp(argv[optind+1], "connections")) {
|
||||
return send_ctl_request_cooked(fd, REQ_DUMP_CONNECTIONS, NULL, 0) != -1;
|
||||
}
|
||||
|
||||
if(!strcasecmp(argv[optind+1], "graph")) {
|
||||
return send_ctl_request_cooked(fd, REQ_DUMP_GRAPH, NULL, 0) != -1;
|
||||
}
|
||||
|
||||
fprintf(stderr, _("Unknown dump type '%s'.\n"), argv[optind+1]);
|
||||
usage(true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, _("Unknown command `%s'.\n"), argv[optind]);
|
||||
usage(true);
|
||||
|
||||
|
|
Loading…
Reference in a new issue