Commit 210b379a authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Merge branch 'babelz'

parents c1f87660 da82470c
......@@ -125,7 +125,7 @@ main(int argc, char **argv)
protocol_port = 6697;
while(1) {
opt = getopt(argc, argv, "m:p:h:H:i:k:A:PsuS:d:g:lwt:T:c:C:DL:I:");
opt = getopt(argc, argv, "m:p:h:H:i:k:A:PsuS:d:g:lwz:t:T:c:C:DL:I:");
if(opt < 0)
break;
......@@ -202,6 +202,18 @@ main(int argc, char **argv)
case 'w':
all_wireless = 1;
break;
case 'z':
{
char *comma = strchr(optarg, ',');
diversity_kind = atoi(optarg);
if(comma == NULL)
diversity_factor = 128;
else
diversity_factor = atoi(comma + 1);
if(diversity_factor <= 0 || diversity_factor > 256)
goto usage;
}
break;
case 't':
export_table = atoi(optarg);
if(export_table < 0 || export_table > 0xFFFF)
......@@ -777,7 +789,7 @@ main(int argc, char **argv)
"Syntax: %s "
"[-m multicast_address] [-p port] [-S state-file]\n"
" "
"[-h hello] [-H wired_hello] [-i idle_hello]\n"
"[-h hello] [-H wired_hello] [-i idle_hello] [-z kind[,factor]]\n"
" "
"[-k metric] [-A metric] [-s] [-P] [-l] [-w] [-u] [-g port]\n"
" "
......@@ -922,12 +934,13 @@ dump_tables(FILE *out)
fprintf(out, "My id %s seqno %d\n", format_eui64(myid), myseqno);
FOR_ALL_NEIGHBOURS(neigh) {
fprintf(out, "Neighbour %s dev %s reach %04x rxcost %d txcost %d%s.\n",
fprintf(out, "Neighbour %s dev %s reach %04x rxcost %d txcost %d chan %d%s.\n",
format_address(neigh->address),
neigh->network->ifname,
neigh->reach,
neighbour_rxcost(neigh),
neigh->txcost,
neigh->network->channel,
net_up(neigh->network) ? "" : " (down)");
}
for(i = 0; i < numxroutes; i++) {
......@@ -939,12 +952,33 @@ dump_tables(FILE *out)
const unsigned char *nexthop =
memcmp(routes[i].nexthop, routes[i].neigh->address, 16) == 0 ?
NULL : routes[i].nexthop;
fprintf(out, "%s metric %d refmetric %d id %s seqno %d age %d "
char channels[100];
if(routes[i].channels[0] == 0)
channels[0] = '\0';
else {
int k, j = 0;
snprintf(channels, 100, " chan (");
j = strlen(channels);
for(k = 0; k < DIVERSITY_HOPS; k++) {
if(routes[i].channels[k] == 0)
break;
if(k > 0)
channels[j++] = ',';
snprintf(channels + j, 100 - j, "%d", routes[i].channels[k]);
j = strlen(channels);
}
snprintf(channels + j, 100 - j, ")");
if(k == 0)
channels[0] = '\0';
}
fprintf(out, "%s metric %d refmetric %d id %s seqno %d%s age %d "
"via %s neigh %s%s%s%s\n",
format_prefix(routes[i].src->prefix, routes[i].src->plen),
route_metric(&routes[i]), routes[i].refmetric,
format_eui64(routes[i].src->id),
(int)routes[i].seqno,
channels,
(int)(now.tv_sec - routes[i].time),
routes[i].neigh->network->ifname,
format_address(routes[i].neigh->address),
......
......@@ -51,6 +51,24 @@ at which scheduled hello packets are sent on idle interfaces. This
functionality is experimental, don't use it unless you know what you are
doing.
.TP
.BI \-z " kind" " \fR[\fB," factor "\fR]"
Enable diversity-sensitive routing. The value
.B kind
defines the diversity algorithm used, and can be one of
.B 0
(no diversity),
.B 1
(per-interface diversity with no memory),
.B 2
(per-channel diversity with no memory),
or
.B 3
(per-channel diversity with memory).
The value
.B factor
specifies by how much the cost of non-interfering routes is multiplied,
in units of 1/256; the default is 128 (i.e. division by 2).
.TP
.BI \-k " priority"
Specify the priority value used when installing routes into the kernel.
The default is 0.
......@@ -167,6 +185,23 @@ for computing metrics of routes going through this interface depends on
whether link quality estimation is being done. The default is 96 for wired
interfaces, and 256 for wireless ones.
.TP
.BI channel " channel"
Sets the channel for this interface. The value
.I channel
can be either an integer, or one of the strings
.B interfering
or
.BR noninterfering .
The default is to autodetect the channel number for wireless interfaces,
and
.B noninterfering
for wired interfaces.
.TP
.BR faraway " {" true | false }
This specifies whether the network is "far away", in the sense that
networks behind it don't interfere with networks in front of it. By
default, networks are not far away.
.TP
.BI hello\-interval " interval"
This defines the interval between hello packets sent on this interface.
The default is specified with the
......
......@@ -429,6 +429,12 @@ parse_nconf(gnc_t gnc, void *closure)
if(c < -1)
goto error;
nconf->wired = v;
} else if(strcmp(token, "faraway") == 0) {
int v;
c = getbool(c, &v, gnc, closure);
if(c < -1)
goto error;
nconf->faraway = v;
} else if(strcmp(token, "link-quality") == 0) {
int v;
c = getbool(c, &v, gnc, closure);
......@@ -441,6 +447,28 @@ parse_nconf(gnc_t gnc, void *closure)
if(c < -1)
goto error;
nconf->split_horizon = v;
} else if(strcmp(token, "channel") == 0) {
char *t, *end;
c = getword(c, &t, gnc, closure);
if(c < -1)
goto error;
if(strcmp(t, "noninterfering") == 0)
nconf->channel = NET_CHANNEL_NONINTERFERING;
else if(strcmp(t, "interfering") == 0)
nconf->channel = NET_CHANNEL_INTERFERING;
else {
nconf->channel = strtol(t, &end, 0);
if(*end != '\0')
goto error;
}
free(t);
if((nconf->channel < 1 || nconf->channel > 254) &&
nconf->channel != NET_CHANNEL_NONINTERFERING)
goto error;
} else {
goto error;
}
......
......@@ -52,6 +52,7 @@ int kernel_interface_ipv4(const char *ifname, int ifindex,
unsigned char *addr_r);
int kernel_interface_mtu(const char *ifname, int ifindex);
int kernel_interface_wireless(const char *ifname, int ifindex);
int kernel_interface_channel(const char *ifname, int ifindex);
int kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric,
const unsigned char *newgate, int newifindex,
......
......@@ -742,6 +742,81 @@ kernel_interface_wireless(const char *ifname, int ifindex)
return rc;
}
/* Sorry for that, but I haven't managed to get <linux/wireless.h>
to include cleanly. */
#define SIOCGIWFREQ 0x8B05
struct iw_freq {
int m;
short e;
unsigned char i;
unsigned char flags;
};
struct iwreq_subset {
union {
char ifrn_name[IFNAMSIZ];
} ifr_ifrn;
union {
struct iw_freq freq;
} u;
};
static int
freq_to_chan(struct iw_freq *freq)
{
int m = freq->m, e = freq->e;
/* If exponent is 0, assume the channel is encoded directly in m. */
if(e == 0 && m > 0 && m < 254)
return m;
if(e <= 6) {
int mega, step, c, i;
/* This encodes 1 MHz */
mega = 1000000;
for(i = 0; i < e; i++)
mega /= 10;
/* Channels 1 through 13 are 5 MHz apart, with channel 1 at 2412. */
step = 5 * mega;
c = 1 + (m - 2412 * mega + step / 2) / step;
if(c >= 1 && c <= 13)
return c;
/* Channel 14 is at 2484 MHz */
if(c >= 14 && m < 2484 * mega + step / 2)
return 14;
/* 802.11a channel 36 is at 5180 MHz */
c = 36 + (m - 5180 * mega + step / 2) / step;
if(c >= 34 && c <= 165)
return c;
}
errno = ENOENT;
return -1;
}
int
kernel_interface_channel(const char *ifname, int ifindex)
{
struct iwreq_subset iwreq;
int rc;
memset(&iwreq, 0, sizeof(iwreq));
strncpy(iwreq.ifr_ifrn.ifrn_name, ifname, IFNAMSIZ);
rc = ioctl(dgram_socket, SIOCGIWFREQ, &iwreq);
if(rc >= 0)
return freq_to_chan(&iwreq.u.freq);
else
return -1;
}
int
kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric,
......
......@@ -297,6 +297,13 @@ kernel_interface_wireless(const char *ifname, int ifindex)
return 0;
}
int
kernel_interface_channel(const char *ifname, int ifindex)
{
errno = ENOSYS;
return -1;
}
int
kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric,
......
This diff is collapsed.
......@@ -23,6 +23,7 @@ THE SOFTWARE.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/ioctl.h>
......@@ -183,6 +184,32 @@ check_network_ipv4(struct network *net)
return 0;
}
int
check_network_channel(struct network *net)
{
int channel = NET_CONF(net, channel);
if(channel == NET_CHANNEL_UNKNOWN) {
if((net->flags & NET_WIRED)) {
channel = NET_CHANNEL_NONINTERFERING;
} else {
channel = kernel_interface_channel(net->ifname, net->ifindex);
if(channel < 0)
fprintf(stderr,
"Couldn't determine channel of interface %s: %s.\n",
net->ifname, strerror(errno));
if(channel <= 0)
channel = NET_CHANNEL_INTERFERING;
}
}
if(net->channel != channel) {
net->channel = channel;
return 1;
}
return 0;
}
int
network_up(struct network *net, int up)
{
......@@ -292,6 +319,9 @@ network_up(struct network *net, int up)
net->flags |= NET_LQ;
}
if(NET_CONF(net, faraway) == CONFIG_YES)
net->flags |= NET_FARAWAY;
net->activity_time = now.tv_sec;
update_hello_interval(net);
/* Since the interface was marked as active above, the
......@@ -364,13 +394,15 @@ network_up(struct network *net, int up)
net->numll = 0;
}
check_network_channel(net);
update_network_metric(net);
rc = check_network_ipv4(net);
debugf("Upped network %s (%s, cost=%d%s).\n",
debugf("Upped network %s (%s, cost=%d, channel=%d%s).\n",
net->ifname,
(net->flags & NET_WIRED) ? "wired" : "wireless",
net->cost,
net->channel,
net->ipv4 ? ", IPv4" : "");
if(up && rc > 0)
......@@ -419,6 +451,7 @@ check_networks(void)
network_up(net, rc > 0);
}
check_network_channel(net);
rc = check_network_ipv4(net);
if(rc > 0) {
send_request(net, NULL, 0);
......
......@@ -35,6 +35,8 @@ struct network_conf {
char wired;
char split_horizon;
char lq;
char faraway;
int channel;
struct network_conf *next;
};
......@@ -46,6 +48,12 @@ struct network_conf {
#define NET_WIRED (1<<1)
#define NET_SPLIT_HORIZON (1 << 2)
#define NET_LQ (1 << 3)
#define NET_FARAWAY (1 << 4)
/* Only INTERFERING can appear on the wire. */
#define NET_CHANNEL_UNKNOWN 0
#define NET_CHANNEL_INTERFERING 255
#define NET_CHANNEL_NONINTERFERING -2
struct network {
struct network *next;
......@@ -53,6 +61,7 @@ struct network {
unsigned int ifindex;
unsigned short flags;
unsigned short cost;
int channel;
struct timeval hello_timeout;
struct timeval update_timeout;
struct timeval flush_timeout;
......
......@@ -44,6 +44,8 @@ struct route *routes = NULL;
int numroutes = 0, maxroutes = 0;
int kernel_metric = 0;
int allow_duplicates = -1;
int diversity_kind = DIVERSITY_NONE;
int diversity_factor = 256; /* in units of 1/256 */
int keep_unfeasible = 0;
struct route *
......@@ -237,12 +239,11 @@ switch_routes(struct route *old, struct route *new)
}
static void
change_route_metric(struct route *route, unsigned newmetric)
change_route_metric(struct route *route,
unsigned refmetric, unsigned cost, unsigned add)
{
int old, new;
if(route_metric(route) == newmetric)
return;
int newmetric = MIN(refmetric + cost + add, INFINITY);
old = metric_to_kernel(route_metric(route));
new = metric_to_kernel(newmetric);
......@@ -260,15 +261,16 @@ change_route_metric(struct route *route, unsigned newmetric)
}
}
route->metric = newmetric;
route->refmetric = refmetric;
route->cost = cost;
route->add_metric = add;
local_notify_route(route, LOCAL_CHANGE);
}
static void
retract_route(struct route *route)
{
route->refmetric = INFINITY;
change_route_metric(route, INFINITY);
change_route_metric(route, INFINITY, INFINITY, 0);
}
int
......@@ -289,6 +291,46 @@ route_expired(struct route *route)
return route->time < now.tv_sec - route->hold_time;
}
static int
channels_interfere(int ch1, int ch2)
{
if(ch1 == NET_CHANNEL_NONINTERFERING || ch2 == NET_CHANNEL_NONINTERFERING)
return 0;
if(ch1 == NET_CHANNEL_INTERFERING || ch2 == NET_CHANNEL_INTERFERING)
return 1;
return ch1 == ch2;
}
int
route_interferes(struct route *route, struct network *net)
{
switch(diversity_kind) {
case DIVERSITY_NONE:
return 1;
case DIVERSITY_INTERFACE_1:
return route->neigh->network == net;
case DIVERSITY_CHANNEL_1:
case DIVERSITY_CHANNEL:
if(route->neigh->network == net)
return 1;
if(channels_interfere(net->channel, route->neigh->network->channel))
return 1;
if(diversity_kind == DIVERSITY_CHANNEL) {
int i;
for(i = 0; i < DIVERSITY_HOPS; i++) {
if(route->channels[i] == 0)
break;
if(channels_interfere(net->channel, route->channels[i]))
return 1;
}
}
return 0;
default:
fprintf(stderr, "Unknown kind of diversity.\n");
return 1;
}
}
int
update_feasible(struct source *src,
unsigned short seqno, unsigned short refmetric)
......@@ -350,15 +392,10 @@ update_route_metric(struct route *route)
route->src->prefix, route->src->plen,
neigh->address,
neigh->network->ifindex);
int newmetric = MIN(route->refmetric +
add_metric +
neighbour_cost(route->neigh),
INFINITY);
if(newmetric != oldmetric) {
change_route_metric(route, newmetric);
change_route_metric(route, route->refmetric,
neighbour_cost(route->neigh), add_metric);
if(route_metric(route) != oldmetric)
route_changed(route, route->src, oldmetric);
}
}
}
......@@ -400,7 +437,8 @@ struct route *
update_route(const unsigned char *a, const unsigned char *p, unsigned char plen,
unsigned short seqno, unsigned short refmetric,
unsigned short interval,
struct neighbour *neigh, const unsigned char *nexthop)
struct neighbour *neigh, const unsigned char *nexthop,
const unsigned char *channels, int channels_len)
{
struct route *route;
struct source *src;
......@@ -429,7 +467,6 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen,
feasible = update_feasible(src, seqno, refmetric);
route = find_route(p, plen, neigh, nexthop);
metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY);
if(route) {
struct source *oldsrc;
unsigned short oldmetric;
......@@ -459,8 +496,8 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen,
if((feasible || keep_unfeasible) && refmetric < INFINITY)
route->time = now.tv_sec;
route->seqno = seqno;
route->refmetric = refmetric;
change_route_metric(route, metric);
change_route_metric(route,
refmetric, neighbour_cost(neigh), add_metric);
route->hold_time = hold_time;
route_changed(route, oldsrc, oldmetric);
......@@ -494,13 +531,18 @@ update_route(const unsigned char *a, const unsigned char *p, unsigned char plen,
route = &routes[numroutes];
route->src = src;
route->refmetric = refmetric;
route->cost = neighbour_cost(neigh);
route->add_metric = add_metric;
route->seqno = seqno;
route->metric = metric;
route->neigh = neigh;
memcpy(route->nexthop, nexthop, 16);
route->time = now.tv_sec;
route->hold_time = hold_time;
route->installed = 0;
memset(&route->channels, 0, sizeof(route->channels));
if(channels_len > 0)
memcpy(&route->channels, channels,
MIN(channels_len, DIVERSITY_HOPS));
numroutes++;
local_notify_route(route, LOCAL_ADD);
consider_route(route);
......
......@@ -20,28 +20,50 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#define DIVERSITY_NONE 0
#define DIVERSITY_INTERFACE_1 1
#define DIVERSITY_CHANNEL_1 2
#define DIVERSITY_CHANNEL 3
#define DIVERSITY_HOPS 8
struct route {
struct source *src;
unsigned short metric;
unsigned short refmetric;
unsigned short cost;
unsigned short add_metric;
unsigned short seqno;
struct neighbour *neigh;
unsigned char nexthop[16];
time_t time;
unsigned short hold_time; /* in seconds */
short installed;
unsigned char channels[DIVERSITY_HOPS];
};
extern struct route *routes;
extern int numroutes, maxroutes;
extern int kernel_metric, allow_duplicates;
extern int diversity_kind, diversity_factor;
extern int keep_unfeasible;
static inline int
route_metric(const struct route *route)
{
return route->metric;
int m = (int)route->refmetric + route->cost + route->add_metric;
return MIN(m, INFINITY);
}
extern struct route *routes;
extern int numroutes, maxroutes;
extern int kernel_metric, allow_duplicates;
extern int keep_unfeasible;
static inline int
route_metric_noninterfering(const struct route *route)
{
int m =
(int)route->refmetric +
(diversity_factor * route->cost + 128) / 256 +
route->add_metric;
m = MAX(m, route->refmetric + 1);
return MIN(m, INFINITY);
}
struct route *find_route(const unsigned char *prefix, unsigned char plen,
struct neighbour *neigh, const unsigned char *nexthop);
......@@ -56,6 +78,7 @@ void switch_route(struct route *old, struct route *new);
int route_feasible(struct route *route);
int route_old(struct route *route);
int route_expired(struct route *route);
int route_interferes(struct route *route, struct network *net);
int update_feasible(struct source *src,
unsigned short seqno, unsigned short refmetric);
struct route *find_best_route(const unsigned char *prefix, unsigned char plen,
......@@ -69,7 +92,8 @@ struct route *update_route(const unsigned char *a,
const unsigned char *p, unsigned char plen,
unsigned short seqno, unsigned short refmetric,
unsigned short interval, struct neighbour *neigh,
const unsigned char *nexthop);
const unsigned char *nexthop,
const unsigned char *channels, int channels_len);
void retract_neighbour_routes(struct neighbour *neigh);
void send_unfeasible_request(struct neighbour *neigh, int force,
unsigned short seqno, unsigned short metric,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment