- More s/vertex/edge/g
- Implementation of Kruskal's minimum spanning tree algorithm.
This commit is contained in:
parent
94497336ef
commit
66067cc9c1
9 changed files with 206 additions and 59 deletions
|
@ -1,15 +1,15 @@
|
|||
## Produce this file with automake to get Makefile.in
|
||||
# $Id: Makefile.am,v 1.4.4.15 2001/10/28 08:41:19 guus Exp $
|
||||
# $Id: Makefile.am,v 1.4.4.16 2001/10/28 10:16:18 guus Exp $
|
||||
|
||||
sbin_PROGRAMS = tincd
|
||||
|
||||
tincd_SOURCES = conf.c connection.c device.c meta.c net.c netutl.c node.c process.c \
|
||||
protocol.c route.c subnet.c tincd.c edge.c
|
||||
tincd_SOURCES = conf.c connection.c device.c edge.c graph.c meta.c net.c netutl.c node.c process.c \
|
||||
protocol.c route.c subnet.c tincd.c
|
||||
|
||||
INCLUDES = @INCLUDES@ -I$(top_builddir) -I$(top_srcdir)/lib -I$(top_srcdir)/intl
|
||||
|
||||
noinst_HEADERS = conf.h connection.h device.h meta.h net.h netutl.h node.h process.h \
|
||||
protocol.h route.h subnet.h edge.h
|
||||
noinst_HEADERS = conf.h connection.h device.h edge.h meta.h net.h netutl.h node.h process.h \
|
||||
protocol.h route.h subnet.h
|
||||
|
||||
LIBS = @LIBS@ @INTLLIBS@
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id: connection.h,v 1.1.2.18 2001/10/28 08:41:19 guus Exp $
|
||||
$Id: connection.h,v 1.1.2.19 2001/10/28 10:16:18 guus Exp $
|
||||
*/
|
||||
|
||||
#ifndef __TINC_CONNECTION_H__
|
||||
|
@ -56,7 +56,8 @@ typedef struct connection_status_t {
|
|||
int timeout:1; /* 1 if gotten timeout */
|
||||
int encryptout:1; /* 1 if we can encrypt outgoing traffic */
|
||||
int decryptin:1; /* 1 if we have to decrypt incoming traffic */
|
||||
int unused:18;
|
||||
int mst:1; /* 1 if this connection is part of a minimum spanning tree */
|
||||
int unused:17;
|
||||
} connection_status_t;
|
||||
|
||||
typedef struct connection_t {
|
||||
|
|
69
src/edge.c
69
src/edge.c
|
@ -17,7 +17,7 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id: edge.c,v 1.1.2.1 2001/10/28 08:41:19 guus Exp $
|
||||
$Id: edge.c,v 1.1.2.2 2001/10/28 10:16:18 guus Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
@ -39,7 +39,8 @@
|
|||
#include "xalloc.h"
|
||||
#include "system.h"
|
||||
|
||||
avl_tree_t *edge_tree; /* Tree with all known vertices (replaces active_tree) */
|
||||
avl_tree_t *edge_tree; /* Tree with all known edges (replaces active_tree) */
|
||||
avl_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */
|
||||
|
||||
int edge_compare(edge_t *a, edge_t *b)
|
||||
{
|
||||
|
@ -64,14 +65,44 @@ int edge_compare(edge_t *a, edge_t *b)
|
|||
|
||||
*/
|
||||
|
||||
void init_vertices(void)
|
||||
int edge_weight_compare(edge_t *a, edge_t *b)
|
||||
{
|
||||
int result;
|
||||
char *name_a1, *name_a2, *name_b1, *name_b2;
|
||||
|
||||
|
||||
result = a->weight - b->weight;
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
if(strcmp(a->from->name, a->to->name) < 0)
|
||||
name_a1 = a->from->name, name_a2 = a->to->name;
|
||||
else
|
||||
name_a1 = a->to->name, name_a2 = a->from->name;
|
||||
|
||||
if(strcmp(b->from->name, b->to->name) < 0)
|
||||
name_b1 = b->from->name, name_b2 = b->to->name;
|
||||
else
|
||||
name_b1 = b->to->name, name_b2 = b->from->name;
|
||||
|
||||
result = strcmp(name_a1, name_b1);
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
else
|
||||
return strcmp(name_a2, name_b2);
|
||||
}
|
||||
|
||||
void init_edges(void)
|
||||
{
|
||||
cp
|
||||
edge_tree = avl_alloc_tree((avl_compare_t)edge_compare, NULL);
|
||||
edge_weight_tree = avl_alloc_tree((avl_compare_t)edge_weight_compare, NULL);
|
||||
cp
|
||||
}
|
||||
|
||||
void exit_vertices(void)
|
||||
void exit_edges(void)
|
||||
{
|
||||
cp
|
||||
avl_delete_tree(edge_tree);
|
||||
|
@ -83,29 +114,31 @@ cp
|
|||
edge_t *new_edge(void)
|
||||
{
|
||||
cp
|
||||
edge_t *v = (edge_t *)xmalloc_and_zero(sizeof(*v));
|
||||
edge_t *e = (edge_t *)xmalloc_and_zero(sizeof(*e));
|
||||
cp
|
||||
return v;
|
||||
return e;
|
||||
}
|
||||
|
||||
void free_edge(edge_t *v)
|
||||
void free_edge(edge_t *e)
|
||||
{
|
||||
cp
|
||||
free(v);
|
||||
free(e);
|
||||
cp
|
||||
}
|
||||
|
||||
void edge_add(edge_t *v)
|
||||
void edge_add(edge_t *e)
|
||||
{
|
||||
cp
|
||||
avl_insert(edge_tree, v);
|
||||
avl_insert(edge_tree, e);
|
||||
avl_insert(edge_weight_tree, e);
|
||||
cp
|
||||
}
|
||||
|
||||
void edge_del(edge_t *v)
|
||||
void edge_del(edge_t *e)
|
||||
{
|
||||
cp
|
||||
avl_delete(edge_tree, v);
|
||||
avl_delete(edge_tree, e);
|
||||
avl_delete(edge_weight_tree, e);
|
||||
cp
|
||||
}
|
||||
|
||||
|
@ -127,20 +160,20 @@ cp
|
|||
return avl_search(edge_tree, &v);
|
||||
}
|
||||
|
||||
void dump_vertices(void)
|
||||
void dump_edges(void)
|
||||
{
|
||||
avl_node_t *node;
|
||||
edge_t *v;
|
||||
edge_t *e;
|
||||
cp
|
||||
syslog(LOG_DEBUG, _("Vertices:"));
|
||||
syslog(LOG_DEBUG, _("Edges:"));
|
||||
|
||||
for(node = edge_tree->head; node; node = node->next)
|
||||
{
|
||||
v = (edge_t *)node->data;
|
||||
e = (edge_t *)node->data;
|
||||
syslog(LOG_DEBUG, _(" %s - %s options %ld"),
|
||||
v->from->name, v->to->name, v->options);
|
||||
e->from->name, e->to->name, e->options);
|
||||
}
|
||||
|
||||
syslog(LOG_DEBUG, _("End of vertices."));
|
||||
syslog(LOG_DEBUG, _("End of edges."));
|
||||
cp
|
||||
}
|
||||
|
|
15
src/edge.h
15
src/edge.h
|
@ -17,7 +17,7 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id: edge.h,v 1.1.2.1 2001/10/28 08:41:19 guus Exp $
|
||||
$Id: edge.h,v 1.1.2.2 2001/10/28 10:16:18 guus Exp $
|
||||
*/
|
||||
|
||||
#ifndef __TINC_EDGE_H__
|
||||
|
@ -42,21 +42,22 @@ typedef struct edge_t {
|
|||
struct node_t *from;
|
||||
struct node_t *to;
|
||||
|
||||
long int options; /* options turned on for this connection */
|
||||
int metric; /* weight of this edge */
|
||||
long int options; /* options turned on for this edge */
|
||||
int weight; /* weight of this edge */
|
||||
|
||||
struct connection_t *connection; /* connection associated with this edge, if available */
|
||||
} edge_t;
|
||||
|
||||
extern avl_tree_t *edge_tree; /* Tree with all known vertices (replaces active_tree) */
|
||||
extern avl_tree_t *edge_tree; /* Tree with all known edges (replaces active_tree) */
|
||||
extern avl_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */
|
||||
|
||||
extern void init_vertices(void);
|
||||
extern void exit_vertices(void);
|
||||
extern void init_edges(void);
|
||||
extern void exit_edges(void);
|
||||
extern edge_t *new_edge(void);
|
||||
extern void free_edge(edge_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_vertices(void);
|
||||
extern void dump_edges(void);
|
||||
|
||||
#endif /* __TINC_EDGE_H__ */
|
||||
|
|
111
src/graph.c
Normal file
111
src/graph.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
graph.c -- graph algorithms
|
||||
Copyright (C) 2001 Guus Sliepen <guus@sliepen.warande.net>,
|
||||
2001 Ivo Timmermans <itimmermans@bigfoot.com>
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id: graph.c,v 1.1.2.1 2001/10/28 10:16:18 guus Exp $
|
||||
*/
|
||||
|
||||
/* We need to generate two trees from the graph:
|
||||
|
||||
1. A minimum spanning tree for broadcasts,
|
||||
2. A single-source shortest path tree for unicasts.
|
||||
|
||||
Actually, the first one alone would suffice but would make unicast packets
|
||||
take longer routes than necessary.
|
||||
|
||||
For the MST algorithm we can choose from Prim's or Kruskal's. I personally
|
||||
favour Kruskal's, because we make an extra AVL tree of edges sorted on
|
||||
weights (metric). That tree only has to be updated when an edge is added or
|
||||
removed, and during the MST algorithm we just have go linearly through that
|
||||
tree, adding safe edges until #edges = #nodes - 1.
|
||||
|
||||
For the SSSP algorithm Dijkstra's seems to be a nice choice.
|
||||
*/
|
||||
|
||||
#include <syslog.h>
|
||||
#include "config.h"
|
||||
|
||||
#include "node.h"
|
||||
#include "edge.h"
|
||||
#include "connection.h"
|
||||
|
||||
#include "system.h"
|
||||
|
||||
/* Implementation of Kruskal's algorithm.
|
||||
Running time: O(V)
|
||||
Please note that sorting on weight is already done by add_vertex().
|
||||
*/
|
||||
|
||||
void kruskal(void)
|
||||
{
|
||||
avl_node_t *node;
|
||||
edge_t *e;
|
||||
node_t *n;
|
||||
connection_t *c;
|
||||
int nodes;
|
||||
int safe_edges = 0;
|
||||
|
||||
syslog(LOG_DEBUG, _("Running Kruskal's algorithm:"));
|
||||
|
||||
/* Clear MST status on nodes */
|
||||
|
||||
for(node = node_tree->head; node; node = node->next)
|
||||
{
|
||||
n = (node_t *)node->data;
|
||||
n->status.mst = 0;
|
||||
node++;
|
||||
}
|
||||
|
||||
/* Clear MST status on connections */
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next)
|
||||
{
|
||||
c = (edge_t *)node->data;
|
||||
c->status.mst = 0;
|
||||
}
|
||||
|
||||
/* Add safe edges */
|
||||
|
||||
for(node = edge_weight_tree->head; node; node = node->next)
|
||||
{
|
||||
// Algorithm should work without this:
|
||||
// if(safe_edges = nodes - 1)
|
||||
// break;
|
||||
|
||||
e = (edge_t *)node->data;
|
||||
|
||||
if(e->from->status.mst && e->to->status.mst)
|
||||
continue;
|
||||
|
||||
e->from->status.mst = 1;
|
||||
e->to->status.mst = 1;
|
||||
if(e->connection)
|
||||
e->connection->status.mst = 1;
|
||||
|
||||
safe_edges++;
|
||||
|
||||
syslog(LOG_DEBUG, _("Adding safe edge %s - %s weight %d"), e->from->name, e->to->name, e->weight);
|
||||
}
|
||||
|
||||
syslog(LOG_DEBUG, _("Done."));
|
||||
|
||||
if(safe_edges != nodes - 1)
|
||||
{
|
||||
syslog(LOG_ERR, _("Implementation of Kruskal's algorithm is screwed: %d nodes, found %d safe edges"), nodes, safe_edges);
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id: net.c,v 1.35.4.140 2001/10/28 08:41:19 guus Exp $
|
||||
$Id: net.c,v 1.35.4.141 2001/10/28 10:16:18 guus Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
@ -776,7 +776,7 @@ cp
|
|||
init_connections();
|
||||
init_subnets();
|
||||
init_nodes();
|
||||
init_vertices();
|
||||
init_edges();
|
||||
|
||||
if(get_config_int(lookup_config(config_tree, "PingTimeout"), &timeout))
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id: node.h,v 1.1.2.5 2001/10/27 12:13:17 guus Exp $
|
||||
$Id: node.h,v 1.1.2.6 2001/10/28 10:16:18 guus Exp $
|
||||
*/
|
||||
|
||||
#ifndef __TINC_NODE_H__
|
||||
|
@ -32,7 +32,8 @@ typedef struct node_status_t {
|
|||
int active:1; /* 1 if active.. */
|
||||
int validkey:1; /* 1 if we currently have a valid key for him */
|
||||
int waitingforkey:1; /* 1 if we already sent out a request */
|
||||
int unused:29;
|
||||
int mst:1; /* 1 if this node has been visited by the MST algorithm */
|
||||
int unused:28;
|
||||
} node_status_t;
|
||||
|
||||
typedef struct node_t {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id: process.c,v 1.1.2.28 2001/10/27 15:19:13 guus Exp $
|
||||
$Id: process.c,v 1.1.2.29 2001/10/28 10:16:18 guus Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
@ -380,7 +380,7 @@ sigusr2_handler(int a, siginfo_t *info, void *b)
|
|||
{
|
||||
dump_device_stats();
|
||||
dump_nodes();
|
||||
dump_vertices();
|
||||
dump_edges();
|
||||
dump_subnets();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id: protocol.c,v 1.28.4.110 2001/10/28 08:41:19 guus Exp $
|
||||
$Id: protocol.c,v 1.28.4.111 2001/10/28 10:16:18 guus Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
@ -600,7 +600,7 @@ cp
|
|||
|
||||
c->edge->from = myself;
|
||||
c->edge->to = n;
|
||||
c->edge->metric = 1;
|
||||
c->edge->weight = 1;
|
||||
c->edge->connection = c;
|
||||
|
||||
edge_add(c->edge);
|
||||
|
@ -934,19 +934,19 @@ cp
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Vertices */
|
||||
/* Edges */
|
||||
|
||||
int send_add_edge(connection_t *c, edge_t *v)
|
||||
int send_add_edge(connection_t *c, edge_t *e)
|
||||
{
|
||||
cp
|
||||
return send_request(c, "%d %s %s %lx", ADD_NODE,
|
||||
v->from->name, v->to->name, v->options);
|
||||
e->from->name, e->to->name, e->options);
|
||||
}
|
||||
|
||||
int add_edge_h(connection_t *c)
|
||||
{
|
||||
connection_t *other;
|
||||
edge_t *v;
|
||||
edge_t *e;
|
||||
node_t *from, *to;
|
||||
char from_name[MAX_STRING_SIZE];
|
||||
char to_name[MAX_STRING_SIZE];
|
||||
|
@ -993,19 +993,19 @@ cp
|
|||
|
||||
/* Check if node already exists */
|
||||
|
||||
v = lookup_edge(from, to);
|
||||
e = lookup_edge(from, to);
|
||||
|
||||
if(v)
|
||||
if(e)
|
||||
{
|
||||
/* Check if it matches */
|
||||
}
|
||||
else
|
||||
{
|
||||
v = new_edge();
|
||||
v->from = from;
|
||||
v->to = to;
|
||||
v->options = options;
|
||||
edge_add(v);
|
||||
e = new_edge();
|
||||
e->from = from;
|
||||
e->to = to;
|
||||
e->options = options;
|
||||
edge_add(e);
|
||||
}
|
||||
|
||||
/* Tell the rest about the new edge */
|
||||
|
@ -1014,23 +1014,23 @@ cp
|
|||
{
|
||||
other = (connection_t *)node->data;
|
||||
if(other->status.active && other != c)
|
||||
send_add_edge(other, v);
|
||||
send_add_edge(other, e);
|
||||
}
|
||||
|
||||
cp
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_del_edge(connection_t *c, edge_t *v)
|
||||
int send_del_edge(connection_t *c, edge_t *e)
|
||||
{
|
||||
cp
|
||||
return send_request(c, "%d %s %s %lx", DEL_EDGE,
|
||||
v->from->name, v->to->name, v->options);
|
||||
e->from->name, e->to->name, e->options);
|
||||
}
|
||||
|
||||
int del_edge_h(connection_t *c)
|
||||
{
|
||||
edge_t *v;
|
||||
edge_t *e;
|
||||
char from_name[MAX_STRING_SIZE];
|
||||
char to_name[MAX_STRING_SIZE];
|
||||
node_t *from, *to;
|
||||
|
@ -1079,9 +1079,9 @@ cp
|
|||
|
||||
/* Check if edge exists */
|
||||
|
||||
v = lookup_edge(from, to);
|
||||
e = lookup_edge(from, to);
|
||||
|
||||
if(v)
|
||||
if(e)
|
||||
{
|
||||
/* Check if it matches */
|
||||
}
|
||||
|
@ -1097,12 +1097,12 @@ cp
|
|||
{
|
||||
other = (connection_t *)node->data;
|
||||
if(other->status.active && other != c)
|
||||
send_del_edge(other, v);
|
||||
send_del_edge(other, e);
|
||||
}
|
||||
|
||||
/* Delete the edge */
|
||||
|
||||
edge_del(v);
|
||||
edge_del(e);
|
||||
cp
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue