diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 64cda12..f8c0a8a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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") diff --git a/src/babel.c b/src/babel.c index 3c0e219..0fab0a7 100644 --- a/src/babel.c +++ b/src/babel.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Matthias Schiffer + Copyright (c) 2013-2014, Matthias Schiffer 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; diff --git a/src/babel.h b/src/babel.h index 625b570..27748a7 100644 --- a/src/babel.h +++ b/src/babel.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Matthias Schiffer + Copyright (c) 2013-2014, Matthias Schiffer 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); diff --git a/src/neigh.c b/src/neigh.c index b97540d..86f8189 100644 --- a/src/neigh.c +++ b/src/neigh.c @@ -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); } diff --git a/src/packet.h b/src/packet.h index 09b6dc0..0b89b56 100644 --- a/src/packet.h +++ b/src/packet.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Matthias Schiffer + Copyright (c) 2013-2014, Matthias Schiffer All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/route.c b/src/route.c index db89896..bffb4c7 100644 --- a/src/route.c +++ b/src/route.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Matthias Schiffer + Copyright (c) 2013-2014, Matthias Schiffer 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 #include 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) - gp_babel_send_seqno_request_for(ctx, NULL, route); + 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) + 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); + } - nexthop->metric_seqno = ms; - nexthop->interval = interval; - nexthop->requested_update = false; - - gp_babel_route_update(ctx, route); + gp_babel_route_maintain(ctx, route); } diff --git a/src/send.c b/src/send.c index e1c582f..f5734b5 100644 --- a/src/send.c +++ b/src/send.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Matthias Schiffer + Copyright (c) 2013-2014, Matthias Schiffer 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) { diff --git a/src/tlv.c b/src/tlv.c index d8a5be5..94e6e04 100644 --- a/src/tlv.c +++ b/src/tlv.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Matthias Schiffer + Copyright (c) 2013-2014, Matthias Schiffer All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/tlv.h b/src/tlv.h index 2cfd73d..6208ae2 100644 --- a/src/tlv.h +++ b/src/tlv.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Matthias Schiffer + Copyright (c) 2013-2014, Matthias Schiffer All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/tlv_types.c b/src/tlv_types.c index fd96e98..2a20f5d 100644 --- a/src/tlv_types.c +++ b/src/tlv_types.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Matthias Schiffer + Copyright (c) 2013-2014, Matthias Schiffer 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) { diff --git a/src/tlv_types.h b/src/tlv_types.h index 08a23b6..c859873 100644 --- a/src/tlv_types.h +++ b/src/tlv_types.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Matthias Schiffer + Copyright (c) 2013-2014, Matthias Schiffer All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/types.h b/src/types.h index 0907232..069e44a 100644 --- a/src/types.h +++ b/src/types.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, Matthias Schiffer + Copyright (c) 2013-2014, Matthias Schiffer All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,6 +30,9 @@ #include +#define UNUSED __attribute__((unused)) + + #define GP_BABEL_NODE_ID_LENGTH 8 typedef struct __attribute__((packed)) gp_gabel_node_id {