Compare commits

..

10 commits

12 changed files with 153 additions and 88 deletions

View file

@ -1,4 +1,5 @@
include_directories(${GMRF_INCLUDE_DIR})
set_directory_properties(PROPERTIES COMPILE_DEFINITIONS _GNU_SOURCE)
add_library(mmss_proto_babel MODULE
babel.c
@ -9,4 +10,4 @@ add_library(mmss_proto_babel MODULE
tlv_types.c
)
target_link_libraries(mmss_proto_babel ${MMSS_PROTOCOL_LIB})
set_target_properties(mmss_proto_babel PROPERTIES LINK_FLAGS "-Wl,--undefined=mmss_protocol_info")
set_target_properties(mmss_proto_babel PROPERTIES COMPILE_FLAGS "-std=c99 -Wall" LINK_FLAGS "-Wl,--undefined=mmss_protocol_info")

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2013-2014, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -35,13 +35,13 @@ const char *gmrf_protocol_name = "babel";
const char *gmrf_protocol_version = "experimental";
static void send_hellos(gmrf_context_t *ctx, void *arg) {
static void send_hellos(gmrf_context_t *ctx, void *arg UNUSED) {
gmrf_schedule(ctx->gmrf, send_hellos, NULL, GP_BABEL_HELLO_INTERVAL*10);
gp_babel_send_hellos(ctx);
}
static void send_updates(gmrf_context_t *ctx, void *arg) {
static void send_updates(gmrf_context_t *ctx, void *arg UNUSED) {
gmrf_schedule(ctx->gmrf, send_updates, NULL, GP_BABEL_UPDATE_INTERVAL*10);
gmrf_logf(ctx->gmrf, LOG_DEBUG, "sending periodic updates.");
@ -68,6 +68,7 @@ static void maintain_neighbours(gmrf_context_t *ctx) {
neigh->addr.d[0], neigh->addr.d[1], neigh->addr.d[2], neigh->addr.d[3],
neigh->addr.d[4], neigh->addr.d[5], neigh->addr.d[6], neigh->addr.d[7],
gmrf_iface_get_name(ctx->gmrf, iface->gmrf_iface), (int)gp_babel_since(ctx, neigh->last_packet)*10);
gmrf_debug_neigh_lost(ctx->gmrf, iface->gmrf_iface, &neigh->addr);
*cur = *next;
next = cur;
@ -81,6 +82,7 @@ static void maintain_neighbours(gmrf_context_t *ctx) {
neigh->addr.d[4], neigh->addr.d[5], neigh->addr.d[6], neigh->addr.d[7],
gmrf_iface_get_name(ctx->gmrf, iface->gmrf_iface), gp_babel_neigh_get_cost(ctx, neigh),
gp_babel_neigh_get_rxcost(ctx, neigh), gp_babel_neigh_get_txcost(ctx, neigh));
gmrf_debug_neigh(ctx->gmrf, iface->gmrf_iface, &neigh->addr, gp_babel_neigh_get_rxcost(ctx, neigh), gp_babel_neigh_get_txcost(ctx, neigh));
}
}
}
@ -91,9 +93,13 @@ static void maintain_routes(gmrf_context_t *ctx) {
gp_babel_route_t *route = *cur;
next = &route->next;
gp_babel_route_update(ctx, route);
gp_babel_route_maintain(ctx, route);
if (!route->nexthops && gp_babel_since(ctx, route->last_nexthop) > GP_BABEL_PURGE_TIMEOUT) {
gmrf_logf(ctx->gmrf, LOG_DEBUG, "node %04x%04x (%u, seqno=%04x): purging.",
ntohl(*(uint32_t*)route->node.id), ntohl(*(uint32_t*)(route->node.id+4)),
route->metric.metric, route->metric.seqno);
if (!route->nexthops) {
*cur = *next;
next = cur;
gp_babel_route_free(ctx, route);
@ -124,7 +130,7 @@ static void maintain_routes(gmrf_context_t *ctx) {
}
}
static void maintenance(gmrf_context_t *ctx, void *arg) {
static void maintenance(gmrf_context_t *ctx, void *arg UNUSED) {
gmrf_schedule(ctx->gmrf, maintenance, NULL, GP_BABEL_MAINTENANCE_INTERVAL*10);
maintain_neighbours(ctx);
@ -143,6 +149,8 @@ gmrf_context_t* gmrf_protocol_init(gmrf_t *gmrf) {
ctx->gmrf = gmrf;
gmrf_random_bytes(gmrf, &ctx->self, sizeof(gp_babel_node_id_t));
gmrf_debug_init(gmrf, ctx->self.id, sizeof(gp_babel_node_id_t));
gp_babel_route_t *route = gp_babel_route_new(ctx);
route->node = ctx->self;

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2013-2014, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -45,6 +45,7 @@
#define GP_BABEL_UPDATE_REQUEST_TIMEOUT(interval) ((interval)*13/4) /* 3.25 intervals */
#define GP_BABEL_MAINTENANCE_INTERVAL GP_BABEL_HELLO_INTERVAL
#define GP_BABEL_PURGE_TIMEOUT GP_BABEL_UPDATE_TIMEOUT(GP_BABEL_UPDATE_INTERVAL)
#define GP_BABEL_NEIGH_PACKET_TIMEOUT 6000
@ -55,6 +56,7 @@ struct gmrf_context {
gmrf_t *gmrf;
gp_babel_node_id_t self;
uint16_t hello_seqno;
gmrf_iface_state_t *interfaces;
gp_babel_neigh_t *neighbours;
@ -67,8 +69,6 @@ struct gmrf_iface_state {
gmrf_iface_t *gmrf_iface;
uint16_t seqno;
gp_babel_neigh_t *neighbours;
};
@ -103,6 +103,8 @@ struct gp_babel_route {
gp_babel_nexthop_t *selected;
gp_babel_nexthop_t *nexthops;
gmrf_time_t last_nexthop;
};
struct gp_babel_nexthop {
@ -132,11 +134,12 @@ void gp_babel_send_seqno_request(gmrf_context_t *ctx, gp_babel_neigh_t *neigh, g
gp_babel_route_t* gp_babel_route_new(gmrf_context_t *ctx);
gp_babel_route_t* gp_babel_route_find(gmrf_context_t *ctx, const gp_babel_node_id_t *node);
gp_babel_route_t* gp_babel_route_get(gmrf_context_t *ctx, const gp_babel_node_id_t *node);
void gp_babel_route_update(gmrf_context_t *ctx, gp_babel_route_t *route);
void gp_babel_route_maintain(gmrf_context_t *ctx, gp_babel_route_t *route);
void gp_babel_route_free(gmrf_context_t *ctx, gp_babel_route_t *route);
gp_babel_nexthop_t* gp_babel_route_nexthop_new(gp_babel_route_t *route, gp_babel_neigh_t *neigh);
gp_babel_nexthop_t* gp_babel_route_nexthop_find(const gp_babel_route_t *route, gp_babel_neigh_t *neigh);
void gp_babel_route_nexthop_delete(gmrf_context_t *ctx, gp_babel_route_t *route, gp_babel_nexthop_t *nexthop);
void gp_babel_route_update_nexthop(gmrf_context_t *ctx, gp_babel_route_t *route, gp_babel_nexthop_t *nexthop, gp_babel_metric_seqno_t ms, uint16_t interval);

View file

@ -107,5 +107,18 @@ uint16_t gp_babel_neigh_get_cost(gmrf_context_t *ctx, const gp_babel_neigh_t *ne
}
void gp_babel_neigh_reset(gmrf_context_t *ctx, gmrf_iface_state_t *iface, gp_babel_neigh_t *neigh) {
gmrf_logf(ctx->gmrf, LOG_DEBUG, "resetting neighbour %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x[%s].",
neigh->addr.d[0], neigh->addr.d[1], neigh->addr.d[2], neigh->addr.d[3],
neigh->addr.d[4], neigh->addr.d[5], neigh->addr.d[6], neigh->addr.d[7],
gmrf_iface_get_name(ctx->gmrf, neigh->iface->gmrf_iface));
gp_babel_route_t *route;
for (route = ctx->routes; route; route = route->next) {
gp_babel_nexthop_t *nexthop = gp_babel_route_nexthop_find(route, neigh);
if (nexthop)
gp_babel_route_nexthop_delete(ctx, route, nexthop);
}
gp_babel_send_route_request(ctx, iface, neigh, NULL);
}

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2013-2014, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2013-2014, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -27,18 +27,20 @@
#include "babel.h"
#include "neigh.h"
#include <assert.h>
#include <stdlib.h>
gp_babel_route_t* gp_babel_route_new(gmrf_context_t *ctx) {
gp_babel_route_t *a = calloc(1, sizeof(gp_babel_route_t));
gp_babel_route_t *route = calloc(1, sizeof(gp_babel_route_t));
a->metric.metric = a->feasibility_distance.metric = a->last_metric = GP_BABEL_INFINITY;
route->metric.metric = route->feasibility_distance.metric = route->last_metric = GP_BABEL_INFINITY;
route->last_nexthop = gmrf_time_unspec;
a->next = ctx->routes;
ctx->routes = a;
route->next = ctx->routes;
ctx->routes = route;
return a;
return route;
}
gp_babel_route_t* gp_babel_route_find(gmrf_context_t *ctx, const gp_babel_node_id_t *node) {
@ -62,7 +64,7 @@ gp_babel_route_t* gp_babel_route_get(gmrf_context_t *ctx, const gp_babel_node_id
return route;
}
void gp_babel_route_free(gmrf_context_t *ctx, gp_babel_route_t *route) {
void gp_babel_route_free(gmrf_context_t *ctx UNUSED, gp_babel_route_t *route) {
free(route);
}
@ -88,54 +90,11 @@ gp_babel_nexthop_t* gp_babel_route_nexthop_new(gp_babel_route_t *route, gp_babel
return nexthop;
}
static void maintain_nexthops(gmrf_context_t *ctx, gp_babel_route_t *route) {
gp_babel_nexthop_t **cur, **next;
for (cur = &route->nexthops; *cur; cur = next) {
gp_babel_nexthop_t *nexthop = *cur;
next = &nexthop->next;
if (!nexthop->neigh) /* local */
continue;
if (!nexthop->neigh->iface) {
// TODO find out what this is supposed to to
if (nexthop->metric_seqno.metric != GP_BABEL_INFINITY) {
nexthop->metric_seqno.metric = GP_BABEL_INFINITY;
nexthop->last_update = gmrf_now(ctx->gmrf);
nexthop->last_update += GP_BABEL_UPDATE_TIMEOUT(nexthop->interval)*10;
}
continue;
}
if (gp_babel_since(ctx, nexthop->last_update) > GP_BABEL_UPDATE_TIMEOUT(nexthop->interval)) {
if (nexthop->metric_seqno.metric == GP_BABEL_INFINITY) {
*cur = *next;
next = cur;
if (route->selected == nexthop)
route->selected = NULL;
gp_babel_neigh_unref(nexthop->neigh);
free(nexthop);
}
else {
nexthop->metric_seqno.metric = GP_BABEL_INFINITY;
nexthop->last_update += GP_BABEL_UPDATE_TIMEOUT(nexthop->interval)*10;
}
}
else if (gp_babel_since(ctx, nexthop->last_update) > GP_BABEL_UPDATE_REQUEST_TIMEOUT(nexthop->interval) && route->selected == nexthop) {
if (!nexthop->requested_update) {
gmrf_logf(ctx->gmrf, LOG_INFO, "route about to expire, requesting update");
gp_babel_send_route_request(ctx, NULL, nexthop->neigh, &route->node);
nexthop->requested_update = true;
}
}
}
static inline bool nexthop_has_expired(gmrf_context_t *ctx, gp_babel_nexthop_t *nexthop) {
return (gp_babel_since(ctx, nexthop->last_update) > GP_BABEL_UPDATE_TIMEOUT(nexthop->interval));
}
static gp_babel_nexthop_t* select_nexthop(gmrf_context_t *ctx, const gp_babel_route_t *route) {
uint16_t ret_metric = GP_BABEL_INFINITY;
gp_babel_nexthop_t *ret = NULL;
@ -159,7 +118,7 @@ static gp_babel_nexthop_t* select_nexthop(gmrf_context_t *ctx, const gp_babel_ro
return ret;
}
gp_babel_metric_seqno_t get_metric(gmrf_context_t *ctx, const gp_babel_route_t *route) {
static gp_babel_metric_seqno_t get_metric(gmrf_context_t *ctx, const gp_babel_route_t *route) {
if (route->selected) {
uint32_t metric = route->selected->metric_seqno.metric + gp_babel_neigh_get_cost(ctx, route->selected->neigh);
@ -170,32 +129,106 @@ gp_babel_metric_seqno_t get_metric(gmrf_context_t *ctx, const gp_babel_route_t *
return (gp_babel_metric_seqno_t){GP_BABEL_INFINITY, 0};
}
void gp_babel_route_update(gmrf_context_t *ctx, gp_babel_route_t *route) {
maintain_nexthops(ctx, route);
static void update_nexthop(gmrf_context_t *ctx, gp_babel_route_t *route) {
bool had_selected = route->selected;
route->selected = select_nexthop(ctx, route);
route->metric = get_metric(ctx, route);
if (!route->selected)
if (route->selected) {
if (route->selected->neigh)
gmrf_debug_route(ctx->gmrf, route->node.id, sizeof(gp_babel_node_id_t), route->selected->neigh->iface->gmrf_iface,
&route->selected->neigh->addr, route->metric.metric);
}
else {
if (had_selected) {
gp_babel_send_seqno_request_for(ctx, NULL, route);
gmrf_debug_route_lost(ctx->gmrf, route->node.id, sizeof(gp_babel_node_id_t));
}
}
/* triggered updates */
/*int diff = route->metric.metric - route->last_metric;
int diff = route->metric.metric - route->last_metric;
if (((route->last_metric == GP_BABEL_INFINITY) != (route->metric.metric == GP_BABEL_INFINITY))
|| diff <= -1024 || diff >= 384) {
gmrf_logf(gmrf, LOG_INFO, "route metric has changed significantly, sending updates");
gp_babel_update_enqueue(&route->node, route->type, route->key, NULL, route->metric.metric == GP_BABEL_INFINITY);
} */
gmrf_logf(ctx->gmrf, LOG_INFO, "route metric has changed significantly, sending updates");
gmrf_iface_state_t *iface;
for (iface = ctx->interfaces; iface; iface = iface->next)
gp_babel_send_update_for_route(ctx, iface, NULL, route);
}
}
static void delete_nexthop(gmrf_context_t *ctx, gp_babel_route_t *route, gp_babel_nexthop_t *nexthop) {
gp_babel_nexthop_t **nexthopp;
for (nexthopp = &route->nexthops; *nexthopp; nexthopp = &(*nexthopp)->next) {
if (*nexthopp == nexthop)
break;
}
assert(*nexthopp == nexthop);
*nexthopp = nexthop->next;
if (route->selected == nexthop)
route->selected = NULL;
gp_babel_neigh_unref(nexthop->neigh);
free(nexthop);
route->last_nexthop = gmrf_now(ctx->gmrf);
}
void gp_babel_route_nexthop_delete(gmrf_context_t *ctx, gp_babel_route_t *route, gp_babel_nexthop_t *nexthop) {
delete_nexthop(ctx, route, nexthop);
if (!route->selected)
gp_babel_route_maintain(ctx, route);
}
static void maintain_nexthop(gmrf_context_t *ctx, gp_babel_route_t *route, gp_babel_nexthop_t *nexthop) {
if (!nexthop->neigh) /* local */
return;
if (nexthop_has_expired(ctx, nexthop)) {
delete_nexthop(ctx, route, nexthop);
return;
}
if (gp_babel_since(ctx, nexthop->last_update) > GP_BABEL_UPDATE_REQUEST_TIMEOUT(nexthop->interval)
&& route->selected == nexthop && !nexthop->requested_update) {
gmrf_logf(ctx->gmrf, LOG_INFO, "route about to expire, requesting update");
gp_babel_send_route_request(ctx, NULL, nexthop->neigh, &route->node);
nexthop->requested_update = true;
}
}
static void maintain_nexthops(gmrf_context_t *ctx, gp_babel_route_t *route) {
gp_babel_nexthop_t *nexthop, *next;
for (nexthop = route->nexthops; nexthop; nexthop = next) {
next = nexthop->next;
maintain_nexthop(ctx, route, nexthop);
}
}
void gp_babel_route_maintain(gmrf_context_t *ctx, gp_babel_route_t *route) {
maintain_nexthops(ctx, route);
update_nexthop(ctx, route);
}
void gp_babel_route_update_nexthop(gmrf_context_t *ctx, gp_babel_route_t *route, gp_babel_nexthop_t *nexthop, gp_babel_metric_seqno_t ms, uint16_t interval) {
if (ms.metric != GP_BABEL_INFINITY || nexthop->metric_seqno.metric != GP_BABEL_INFINITY)
nexthop->last_update = gmrf_now(ctx->gmrf);
if (ms.metric == GP_BABEL_INFINITY) {
gmrf_logf(ctx->gmrf, LOG_DEBUG, "retract received, deleting nexthop");
delete_nexthop(ctx, route, nexthop);
}
else {
nexthop->metric_seqno = ms;
nexthop->interval = interval;
nexthop->requested_update = false;
nexthop->last_update = gmrf_now(ctx->gmrf);
}
gp_babel_route_update(ctx, route);
gp_babel_route_maintain(ctx, route);
}

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2013-2014, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -104,13 +104,15 @@ void gp_babel_send_hellos(gmrf_context_t *ctx) {
gmrf_iface_state_t *iface;
for (iface = ctx->interfaces; iface; iface = iface->next) {
hello->seqno = htons(iface->seqno++);
hello->seqno = htons(ctx->hello_seqno);
buf->packet.len = len;
add_ihus(ctx, buf, iface);
send_iface(ctx, iface, &buf->packet);
}
ctx->hello_seqno++;
}
/*static inline bool add_node_id_tlv(gp_babel_packet_buf_t *buf, const gp_babel_node_id_t *node_id) {

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2013-2014, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2013-2014, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2013-2014, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -54,7 +54,7 @@ static void handle_tlv_ack_req(gmrf_context_t *ctx, const gp_babel_tlv_ack_req_t
gp_babel_send_ack(ctx, get_tlv_neigh(ctx, arg), ntohs(tlv->nonce));
}
static void handle_tlv_ack(gmrf_context_t *ctx, const gp_babel_tlv_ack_t *tlv, size_t len, handle_tlv_arg_t *arg) {
static void handle_tlv_ack(gmrf_context_t *ctx, const gp_babel_tlv_ack_t *tlv UNUSED, size_t len, handle_tlv_arg_t *arg UNUSED) {
if (len < sizeof(gp_babel_tlv_ack_t)) {
gmrf_logf(ctx->gmrf, LOG_WARNING, "received short acknowledement TLV.");
return;
@ -111,6 +111,7 @@ static void handle_tlv_hello(gmrf_context_t *ctx, const gp_babel_tlv_hello_t *tl
gp_babel_neigh_reset(ctx, arg->iface, neigh);
gmrf_logf(ctx->gmrf, LOG_DEBUG, "accepted hello, log %04x, rxcost is %u, cost is %u now.", neigh->hello_log, gp_babel_neigh_get_rxcost(ctx, neigh), gp_babel_neigh_get_cost(ctx, neigh));
gmrf_debug_neigh(ctx->gmrf, arg->iface->gmrf_iface, &neigh->addr, gp_babel_neigh_get_rxcost(ctx, neigh), gp_babel_neigh_get_txcost(ctx, neigh));
}
static void handle_tlv_ihu(gmrf_context_t *ctx, const gp_babel_tlv_ihu_t *tlv, size_t len, handle_tlv_arg_t *arg) {
@ -139,6 +140,7 @@ static void handle_tlv_ihu(gmrf_context_t *ctx, const gp_babel_tlv_ihu_t *tlv, s
neigh->txcost = ntohs(tlv->rxcost);
gmrf_logf(ctx->gmrf, LOG_DEBUG, "accepted IHU, txcost is %u, cost is %u now.", gp_babel_neigh_get_txcost(ctx, neigh), gp_babel_neigh_get_cost(ctx, neigh));
gmrf_debug_neigh(ctx->gmrf, arg->iface->gmrf_iface, &neigh->addr, gp_babel_neigh_get_rxcost(ctx, neigh), gp_babel_neigh_get_txcost(ctx, neigh));
}
static void handle_tlv_node_id(gmrf_context_t *ctx, const gp_babel_tlv_node_id_t *tlv, size_t len, handle_tlv_arg_t *arg) {

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2013-2014, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2013-2014, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -30,6 +30,9 @@
#include <gmrf/gmrf.h>
#define UNUSED __attribute__((unused))
#define GP_BABEL_NODE_ID_LENGTH 8
typedef struct __attribute__((packed)) gp_gabel_node_id {