Compare commits

...

10 commits

14 changed files with 786 additions and 94 deletions

View file

@ -1,12 +1,15 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${FFD_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${FFD_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
add_executable(ffd add_executable(ffd
ack.c
announce.c announce.c
ffd.c ffd.c
neigh.c neigh.c
netif.c netif.c
queue.c
send.c send.c
tlv.c tlv.c
update.c
util.c util.c
) )
target_link_libraries(ffd rt) target_link_libraries(ffd rt)

91
ffd/ack.c Normal file
View file

@ -0,0 +1,91 @@
/*
Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ffd.h"
#include "queue.h"
static uint8_t acks[1 << 13] = {};
static ffd_queue_t *ack_requests = NULL;
static uint16_t nonce = 0;
#define SET_ACK(n) do {acks[n >> 3] |= 1 << (n & 7);} while(0)
#define UNSET_ACK(n) do {acks[n >> 3] &= ~(1 << (n & 7));} while(0)
#define GET_ACK(n) ((acks[n >> 3] & (1 << (n & 7))) != 0)
typedef struct _ack_arg_t {
void (*cb)(uint16_t nonce, void *arg);
void (*free)(uint16_t nonce, void *arg);
void *arg;
uint16_t nonce;
unsigned interval;
unsigned retries;
} ack_arg_t;
void ffd_ack_handle(uint16_t n) {
SET_ACK(n);
}
static void ack_resend(const struct timespec *timeout, void *argp) {
ack_arg_t *arg = argp;
if (GET_ACK(arg->nonce) || !(--arg->retries)) {
arg->free(arg->nonce, arg->arg);
free(arg);
return;
}
arg->cb(arg->nonce, arg->arg);
ffd_queue_put_delayed(&ack_requests, ack_resend, timeout, arg->interval, arg);
}
void ffd_ack_request(void (*cb)(uint16_t nonce, void *arg), void (*free_cb)(uint16_t nonce, void *arg), unsigned interval, unsigned retries, void *arg) {
UNSET_ACK(nonce);
cb(nonce, arg);
ack_arg_t *ack_arg = malloc(sizeof(ack_arg_t));
ack_arg->cb = cb;
ack_arg->free = free_cb;
ack_arg->arg = arg;
ack_arg->nonce = nonce++;
ack_arg->interval = interval;
ack_arg->retries = retries;
ffd_queue_put_delayed(&ack_requests, ack_resend, &now, interval, ack_arg);
}
int ffd_ack_timeout(void) {
return ffd_queue_timeout(&ack_requests);
}
void ffd_ack_run(void) {
ffd_queue_run(&ack_requests);
}

View file

@ -26,6 +26,7 @@
#include "ffd.h" #include "ffd.h"
#include "neigh.h" #include "neigh.h"
#include "send.h"
#include <stdio.h> #include <stdio.h>
@ -110,6 +111,26 @@ ffd_metric_seqno_t get_metric(const ffd_announce_t *announce) {
return (ffd_metric_seqno_t){0xffff, 0}; return (ffd_metric_seqno_t){0xffff, 0};
} }
static inline void seqno_update(ffd_announce_t *announce) {
ffd_seqno_req_t **cur, **next;
for (cur = &announce->seqno_req_list; *cur; cur = next) {
ffd_seqno_req_t *req = *cur;
next = &req->next;
int16_t diff = announce->selected->metric_seqno.seqno - req->seqno;
if (diff >= 0) {
*cur = *next;
next = cur;
fprintf(stderr, "debug: update matches seqno request, forwarding\n");
ffd_update_enqueue(&announce->node, announce->type, announce->key, req->neigh, true);
ffd_neigh_unref(req->neigh);
free(req);
}
}
}
void ffd_announce_update(ffd_announce_t *announce) { void ffd_announce_update(ffd_announce_t *announce) {
maintain_nexthops(announce); maintain_nexthops(announce);
@ -125,8 +146,11 @@ void ffd_announce_update(ffd_announce_t *announce) {
if (((announce->last_metric == 0xffff) != (announce->metric.metric == 0xffff)) if (((announce->last_metric == 0xffff) != (announce->metric.metric == 0xffff))
|| diff <= -1024 || diff >= 384) { || diff <= -1024 || diff >= 384) {
fprintf(stderr, "info: announce metric has changed significantly, sending updates\n"); fprintf(stderr, "info: announce metric has changed significantly, sending updates\n");
ffd_send_update(NULL, NULL, announce, false); ffd_update_enqueue(&announce->node, announce->type, announce->key, NULL, announce->metric.metric == 0xffff);
} }
if (announce->selected)
seqno_update(announce);
} }
void ffd_announce_update_nexthop(ffd_announce_t *announce, ffd_nexthop_t *nexthop, ffd_metric_seqno_t ms, uint16_t interval) { void ffd_announce_update_nexthop(ffd_announce_t *announce, ffd_nexthop_t *nexthop, ffd_metric_seqno_t ms, uint16_t interval) {
@ -175,3 +199,84 @@ ffd_announce_t* ffd_announce_get(const ffd_node_id_t *node, uint16_t type, uint1
return announce; return announce;
} }
ffd_nexthop_t* ffd_announce_nexthop_find(const ffd_announce_t *announce, ffd_neigh_t *neigh) {
ffd_nexthop_t *nexthop;
for (nexthop = announce->nexthop_list; nexthop; nexthop = nexthop->next) {
if (nexthop->neigh == neigh)
return nexthop;
}
return NULL;
}
ffd_nexthop_t* ffd_announce_nexthop_new(ffd_announce_t *announce, ffd_neigh_t *neigh) {
ffd_nexthop_t *nexthop = calloc(1, sizeof(ffd_nexthop_t));
nexthop->neigh = neigh;
nexthop->next = announce->nexthop_list;
announce->nexthop_list = nexthop;
ffd_neigh_ref(neigh);
return nexthop;
}
static inline bool find_seqno_request(ffd_seqno_req_t **reqp, ffd_announce_t *announce, ffd_neigh_t *neigh, uint16_t seqno) {
ffd_seqno_req_t *req;
bool ret = true;
*reqp = NULL;
for (req = announce->seqno_req_list; req; req = req->next) {
if (req->neigh == neigh)
*reqp = req;
int16_t diff = req->seqno - seqno;
if (timespec_diff(&now, &req->last_req) < FFD_SEQNO_REQUEST_TIMEOUT && diff >= 0)
ret = false;
}
return ret;
}
bool ffd_announce_seqno_request(ffd_announce_t *announce, ffd_neigh_t *neigh, uint16_t seqno) {
ffd_seqno_req_t *req;
bool ret = find_seqno_request(&req, announce, neigh, seqno);
if (!req) {
req = calloc(1, sizeof(ffd_seqno_req_t));
req->neigh = neigh;
req->seqno = seqno;
req->last_req = now;
ffd_neigh_ref(neigh);
req->next = announce->seqno_req_list;
announce->seqno_req_list = req;
}
int16_t diff = seqno - req->seqno;
if (diff > 0) {
req->seqno = seqno;
req->last_req = now;
}
if (ret) {
req->last_req = now;
return true;
}
return false;
}
void ffd_announce_free(ffd_announce_t *announce) {
ffd_seqno_req_t *req, *req_next;
for (req = announce->seqno_req_list; req; req = req_next) {
req_next = req->next;
ffd_neigh_unref(req->neigh);
free(req);
}
free(announce);
}

147
ffd/ffd.c
View file

@ -28,6 +28,8 @@
#include "neigh.h" #include "neigh.h"
#include "netif.h" #include "netif.h"
#include "packet.h" #include "packet.h"
#include "queue.h"
#include "send.h"
#include "tlv.h" #include "tlv.h"
#include "tlv_types.h" #include "tlv_types.h"
@ -51,10 +53,10 @@ static char *mesh = "bat0";
int sockfd; int sockfd;
struct timespec now; struct timespec now;
static ffd_queue_t *tasks = NULL;
ffd_node_id_t self; ffd_node_id_t self;
ffd_iface_t *iface_list = NULL; ffd_iface_t *iface_list = NULL;
ffd_announce_t *announce_list = NULL; ffd_announce_t *announce_list = NULL;
@ -201,6 +203,15 @@ static void handle_tlv_ack_req(const ffd_tlv_ack_req_t *tlv_req, size_t len, han
ffd_send_ack(neigh, ntohs(tlv_req->nonce)); ffd_send_ack(neigh, ntohs(tlv_req->nonce));
} }
static void handle_tlv_ack(const ffd_tlv_ack_t *tlv_ack, size_t len, handle_tlv_arg_t *arg) {
if (len < sizeof(ffd_tlv_ack_t)) {
fprintf(stderr, "warn: received short acknowledement TLV.\n");
return;
}
ffd_ack_handle(ntohs(tlv_ack->nonce));
}
static void handle_tlv_hello(const ffd_tlv_hello_t *tlv_hello, size_t len, handle_tlv_arg_t *arg) { static void handle_tlv_hello(const ffd_tlv_hello_t *tlv_hello, size_t len, handle_tlv_arg_t *arg) {
if (len < sizeof(ffd_tlv_hello_t)) { if (len < sizeof(ffd_tlv_hello_t)) {
fprintf(stderr, "warn: received short hello TLV.\n"); fprintf(stderr, "warn: received short hello TLV.\n");
@ -284,28 +295,6 @@ static void handle_tlv_node_id(const ffd_tlv_node_id_t *tlv_node_id, size_t len,
arg->node_id = tlv_node_id->id; arg->node_id = tlv_node_id->id;
} }
static ffd_nexthop_t* find_nexthop(const ffd_announce_t *announce, ffd_neigh_t *neigh) {
ffd_nexthop_t *nexthop;
for (nexthop = announce->nexthop_list; nexthop; nexthop = nexthop->next) {
if (nexthop->neigh == neigh)
return nexthop;
}
return NULL;
}
static ffd_nexthop_t* new_nexthop(ffd_announce_t *announce, ffd_neigh_t *neigh) {
ffd_nexthop_t *nexthop = calloc(1, sizeof(ffd_nexthop_t));
nexthop->neigh = neigh;
nexthop->next = announce->nexthop_list;
announce->nexthop_list = nexthop;
ffd_neigh_ref(neigh);
return nexthop;
}
static void handle_tlv_update(const ffd_tlv_update_t *tlv_update, size_t len, handle_tlv_arg_t *arg) { static void handle_tlv_update(const ffd_tlv_update_t *tlv_update, size_t len, handle_tlv_arg_t *arg) {
if (len < sizeof(ffd_tlv_update_t)) { if (len < sizeof(ffd_tlv_update_t)) {
fprintf(stderr, "warn: received short update TLV.\n"); fprintf(stderr, "warn: received short update TLV.\n");
@ -329,11 +318,11 @@ static void handle_tlv_update(const ffd_tlv_update_t *tlv_update, size_t len, ha
bool feasible = ffd_is_feasible(announce, ms); bool feasible = ffd_is_feasible(announce, ms);
ffd_neigh_t *neigh = get_tlv_neigh(arg); ffd_neigh_t *neigh = get_tlv_neigh(arg);
ffd_nexthop_t *nexthop = find_nexthop(announce, neigh); ffd_nexthop_t *nexthop = ffd_announce_nexthop_find(announce, neigh);
if (!nexthop) { if (!nexthop) {
if (feasible && tlv_update->metric != 0xffff /* no need to ntohs */) if (feasible && tlv_update->metric != 0xffff /* no need to ntohs */)
nexthop = new_nexthop(announce, neigh); nexthop = ffd_announce_nexthop_new(announce, neigh);
} }
else { else {
if (!feasible && nexthop == announce->selected) { if (!feasible && nexthop == announce->selected) {
@ -397,8 +386,6 @@ static void handle_tlv_seqno_req(const ffd_tlv_seqno_req_t *tlv_req, size_t len,
return; return;
} }
fprintf(stderr, "debug: received seqno request\n");
ffd_announce_t *announce = ffd_announce_find(&tlv_req->node, ntohs(tlv_req->type), ntohs(tlv_req->key)); ffd_announce_t *announce = ffd_announce_find(&tlv_req->node, ntohs(tlv_req->type), ntohs(tlv_req->key));
if (!announce) { if (!announce) {
@ -416,21 +403,28 @@ static void handle_tlv_seqno_req(const ffd_tlv_seqno_req_t *tlv_req, size_t len,
if (announce->selected->neigh == neigh) if (announce->selected->neigh == neigh)
return; return;
if ((int16_t)(ntohs(tlv_req->seqno)-announce->selected->metric_seqno.seqno) <= 0) { uint16_t seqno = ntohs(tlv_req->seqno);
if ((int16_t)(seqno-announce->selected->metric_seqno.seqno) <= 0) {
fprintf(stderr, "debug: received seqno request, seqno already ok\n"); fprintf(stderr, "debug: received seqno request, seqno already ok\n");
ffd_send_update(NULL, neigh, announce, false); ffd_update_enqueue(&announce->node, announce->type, announce->key, neigh, true);
return; return;
} }
if (!announce->selected->neigh) { if (!announce->selected->neigh) {
fprintf(stderr, "debug: incrementing seqno\n"); fprintf(stderr, "debug: received seqno request, incrementing seqno\n");
announce->selected->metric_seqno.seqno++; announce->selected->metric_seqno.seqno++;
ffd_send_update(NULL, neigh, announce, false); ffd_update_enqueue(&announce->node, announce->type, announce->key, neigh, true);
return; return;
} }
fprintf(stderr, "debug: received seqno request, forwarding\n"); if (ffd_announce_seqno_request(announce, neigh, seqno)) {
ffd_send_seqno_request(announce->selected->neigh, announce, ntohs(tlv_req->seqno)); fprintf(stderr, "debug: received seqno request, forwarding\n");
ffd_send_seqno_request(announce->selected->neigh, announce, seqno);
}
else {
fprintf(stderr, "debug: received seqno request, not forwarding again\n");
}
} }
static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void *arg) { static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void *arg) {
@ -440,7 +434,7 @@ static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void *
return; return;
case TLV_ACK: case TLV_ACK:
/* we don't send ack reqs */ handle_tlv_ack(data, len, arg);
return; return;
case TLV_HELLO: case TLV_HELLO:
@ -506,6 +500,8 @@ static void receive_packet(void) {
} }
static void send_updates(void) { static void send_updates(void) {
fprintf(stderr, "debug: sending periodic updates.\n");
ffd_iface_t *iface; ffd_iface_t *iface;
for (iface = iface_list; iface; iface = iface->next) { for (iface = iface_list; iface; iface = iface->next) {
ffd_send_update(iface, NULL, NULL, false); ffd_send_update(iface, NULL, NULL, false);
@ -547,7 +543,7 @@ static void maintenance(void) {
if (!announce->nexthop_list) { if (!announce->nexthop_list) {
*cur = *next; *cur = *next;
next = cur; next = cur;
free(announce); ffd_announce_free(announce);
continue; continue;
} }
@ -574,6 +570,46 @@ static void maintenance(void) {
} }
} }
typedef struct _periodic_task_info {
void (*handle)(void);
unsigned delay;
unsigned interval;
} periodic_task_info;
static const periodic_task_info periodic_tasks [] = {
{maintenance, 0, FFD_MAINTENANCE_INTERVAL},
{ffd_send_hellos, FFD_HELLO_INTERVAL, FFD_HELLO_INTERVAL},
{send_updates, 1, FFD_UPDATE_INTERVAL},
{NULL}
};
static void handle_periodic_task(const struct timespec *timeout, void *arg) {
const periodic_task_info *info = arg;
info->handle();
ffd_queue_put_delayed(&tasks, handle_periodic_task, timeout, info->interval, arg);
}
static void register_periodic_tasks(void) {
const periodic_task_info *info;
for (info = periodic_tasks; info->handle; info++)
ffd_queue_put_delayed(&tasks, handle_periodic_task, &now, info->delay, (void*)info);
}
static inline int timeout_min(int a, int b) {
if (a < 0)
return b;
else if (b < 0)
return a;
else
return min(a, b);
}
int main() { int main() {
if (!check_config()) if (!check_config())
return 1; return 1;
@ -585,44 +621,23 @@ int main() {
return 1; return 1;
update_time(); update_time();
register_periodic_tasks();
struct timespec next_hello = now;
struct timespec next_update = now;
struct timespec next_maintenance = now;
while (true) { while (true) {
int maintenance_timeout = timespec_diff(&next_maintenance, &now); ffd_queue_run(&tasks);
if (maintenance_timeout <= 0) { ffd_update_run();
maintenance(); ffd_ack_run();
add_interval(&next_maintenance, FFD_MAINTENANCE_INTERVAL);
}
int hello_timeout = timespec_diff(&next_hello, &now);
if (hello_timeout <= 0) {
ffd_send_hellos();
add_interval(&next_hello, FFD_HELLO_INTERVAL);
}
int update_timeout = timespec_diff(&next_update, &now);
if (update_timeout <= 0) {
fprintf(stderr, "Sending periodic update.\n");
send_updates();
add_interval(&next_update, FFD_UPDATE_INTERVAL);
}
int timeout = min(min(hello_timeout, update_timeout), maintenance_timeout);
if (timeout <= 0)
continue;
struct pollfd fds[1]; struct pollfd fds[1];
int timeout = 10*timeout_min(timeout_min(ffd_queue_timeout(&tasks), ffd_update_timeout()), ffd_ack_timeout());
if (timeout < 0)
timeout = -1;
fds[0].fd = sockfd; fds[0].fd = sockfd;
fds[0].events = POLLIN; fds[0].events = POLLIN;
poll(fds, 1, 10*timeout); poll(fds, 1, timeout);
update_time(); update_time();

View file

@ -47,8 +47,13 @@
#define FFD_UPDATE_REQUEST_TIMEOUT(interval) ((interval)*13/4) /* 3.25 intervals */ #define FFD_UPDATE_REQUEST_TIMEOUT(interval) ((interval)*13/4) /* 3.25 intervals */
#define FFD_SEQNO_REQUEST_TIMEOUT 50
#define FFD_MAINTENANCE_INTERVAL FFD_HELLO_INTERVAL #define FFD_MAINTENANCE_INTERVAL FFD_HELLO_INTERVAL
#define FFD_DELAY (FFD_HELLO_INTERVAL/2)
#define FFD_URGENT_DELAY 20
#define FFD_ACK_INTERVAL FFD_URGENT_DELAY
#define FFD_UPDATE_WITH_DATA 0x01 #define FFD_UPDATE_WITH_DATA 0x01
@ -73,6 +78,14 @@ typedef struct _ffd_nexthop_t {
bool requested_update; bool requested_update;
} ffd_nexthop_t; } ffd_nexthop_t;
typedef struct _ffd_seqno_req_t {
struct _ffd_seqno_req_t *next;
struct timespec last_req;
struct _ffd_neigh_t *neigh;
uint16_t seqno;
} ffd_seqno_req_t;
typedef struct _ffd_announce_t { typedef struct _ffd_announce_t {
struct _ffd_announce_t *next; struct _ffd_announce_t *next;
@ -84,6 +97,8 @@ typedef struct _ffd_announce_t {
uint16_t last_metric; uint16_t last_metric;
ffd_metric_seqno_t feasibility_distance; ffd_metric_seqno_t feasibility_distance;
ffd_seqno_req_t *seqno_req_list;
ffd_nexthop_t *selected; ffd_nexthop_t *selected;
ffd_nexthop_t *nexthop_list; ffd_nexthop_t *nexthop_list;
@ -133,7 +148,6 @@ extern ffd_iface_t *iface_list;
extern ffd_announce_t *announce_list; extern ffd_announce_t *announce_list;
extern int sockfd; extern int sockfd;
extern struct timespec now;
#define FFD_NODE_ID_UNSPEC ((ffd_node_id_t){}) #define FFD_NODE_ID_UNSPEC ((ffd_node_id_t){})
@ -189,19 +203,18 @@ void ffd_announce_update_nexthop(ffd_announce_t *announce, ffd_nexthop_t *nextho
ffd_announce_t* ffd_announce_new(void); ffd_announce_t* ffd_announce_new(void);
ffd_announce_t* ffd_announce_find(const ffd_node_id_t *node, uint16_t type, uint16_t key); ffd_announce_t* ffd_announce_find(const ffd_node_id_t *node, uint16_t type, uint16_t key);
ffd_announce_t* ffd_announce_get(const ffd_node_id_t *node, uint16_t type, uint16_t key); ffd_announce_t* ffd_announce_get(const ffd_node_id_t *node, uint16_t type, uint16_t key);
ffd_nexthop_t* ffd_announce_nexthop_find(const ffd_announce_t *announce, ffd_neigh_t *neigh);
ffd_nexthop_t* ffd_announce_nexthop_new(ffd_announce_t *announce, ffd_neigh_t *neigh);
bool ffd_announce_seqno_request(ffd_announce_t *announce, ffd_neigh_t *neigh, uint16_t seqno);
void ffd_announce_free(ffd_announce_t *announce);
void ffd_send_ack(ffd_neigh_t *neigh, uint16_t nonce); void ffd_ack_handle(uint16_t n);
void ffd_send_hellos(void); void ffd_ack_request(void (*cb)(uint16_t nonce, void *arg), void (*free_cb)(uint16_t nonce, void *arg), unsigned interval, unsigned retries, void *arg);
void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool with_data); int ffd_ack_timeout(void);
void ffd_send_retract(ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key); void ffd_ack_run(void);
void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key, bool with_data);
void ffd_send_seqno_request(ffd_neigh_t *neigh, ffd_announce_t *announce, uint16_t seqno);
static inline void ffd_send_seqno_request_for(ffd_neigh_t *neigh, ffd_announce_t *announce) { void ffd_update_enqueue(const ffd_node_id_t *node, uint16_t type, uint16_t key, ffd_neigh_t *neigh, bool urgent);
if (FFD_IS_INFINITY(announce->feasibility_distance)) int ffd_update_timeout(void);
return; void ffd_update_run(void);
ffd_send_seqno_request(neigh, announce, announce->feasibility_distance.seqno+1);
}
#endif /* _FFD_FFD_H_ */ #endif /* _FFD_FFD_H_ */

View file

@ -25,6 +25,7 @@
#include "neigh.h" #include "neigh.h"
#include "send.h"
ffd_neigh_t* ffd_neigh_get(ffd_iface_t *iface, const eth_addr_t *addr) { ffd_neigh_t* ffd_neigh_get(ffd_iface_t *iface, const eth_addr_t *addr) {
@ -55,6 +56,11 @@ void ffd_neigh_unref_list(ffd_neigh_t *neigh) {
} }
} }
void ffd_neigh_unref(ffd_neigh_t *neigh) {
if (!(--neigh->ref) && !neigh->iface)
free(neigh);
}
uint16_t ffd_neigh_get_rxcost(const ffd_neigh_t *neigh) { uint16_t ffd_neigh_get_rxcost(const ffd_neigh_t *neigh) {
if (!neigh->hello_log || !neigh->hello_interval || !neigh->iface) if (!neigh->hello_log || !neigh->hello_interval || !neigh->iface)
return 0xffff; return 0xffff;

View file

@ -44,10 +44,6 @@ static inline void ffd_neigh_ref(ffd_neigh_t *neigh) {
neigh->ref++; neigh->ref++;
} }
static inline void ffd_neigh_unref(ffd_neigh_t *neigh) {
if (!(--neigh->ref) && !neigh->iface)
free(neigh);
}
ffd_neigh_t* ffd_neigh_get(ffd_iface_t *iface, const eth_addr_t *addr); ffd_neigh_t* ffd_neigh_get(ffd_iface_t *iface, const eth_addr_t *addr);
void ffd_neigh_unref(ffd_neigh_t *neigh); void ffd_neigh_unref(ffd_neigh_t *neigh);

42
ffd/queue.c Normal file
View file

@ -0,0 +1,42 @@
/*
Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "queue.h"
void ffd_queue_put(ffd_queue_t **queue, ffd_queue_cb cb, const struct timespec *timeout, void *arg) {
while (*queue && timespec_after(timeout, &(*queue)->timeout))
queue = &(*queue)->next;
ffd_queue_t *entry = malloc(sizeof(ffd_queue_t));
entry->cb = cb;
entry->timeout = *timeout;
entry->arg = arg;
entry->next = *queue;
*queue = entry;
}

75
ffd/queue.h Normal file
View file

@ -0,0 +1,75 @@
/*
Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FFD_QUEUE_H_
#define _FFD_QUEUE_H_
#include "util.h"
typedef void (*ffd_queue_cb)(const struct timespec *timeout, void *arg);
struct _ffd_queue_t {
ffd_queue_t *next;
ffd_queue_cb cb;
struct timespec timeout;
void *arg;
};
void ffd_queue_put(ffd_queue_t **queue, ffd_queue_cb cb, const struct timespec *timeout, void *arg);
static inline void ffd_queue_put_delayed(ffd_queue_t **queue, ffd_queue_cb cb, const struct timespec *timeout, int delay, void *arg) {
struct timespec timeout_delayed = *timeout;
add_interval(&timeout_delayed, delay);
ffd_queue_put(queue, cb, &timeout_delayed, arg);
}
static inline void ffd_queue_drop(ffd_queue_t **queue) {
ffd_queue_t *entry = *queue;
*queue = entry->next;
free(entry);
}
static inline void ffd_queue_run(ffd_queue_t **queue) {
while (*queue && timespec_after(&now, &(*queue)->timeout)) {
ffd_queue_t *entry = *queue;
*queue = (*queue)->next;
entry->cb(&entry->timeout, entry->arg);
free(entry);
}
}
static inline int ffd_queue_timeout(ffd_queue_t *const *queue) {
if (!*queue)
return -1;
return max(timespec_diff(&(*queue)->timeout, &now), 0);
}
#endif /* _FFD_QUEUE_H_ */

View file

@ -27,6 +27,7 @@
#include "ffd.h" #include "ffd.h"
#include "neigh.h" #include "neigh.h"
#include "packet.h" #include "packet.h"
#include "send.h"
#include "tlv.h" #include "tlv.h"
#include "tlv_types.h" #include "tlv_types.h"
@ -40,6 +41,27 @@
#include <sys/uio.h> #include <sys/uio.h>
typedef struct _announce_info_t {
ffd_node_id_t node;
uint16_t type;
uint16_t key;
} announce_info_t;
struct _ffd_update_t {
ffd_iface_t *iface;
ffd_neigh_t *neigh;
ffd_packet_t *packet;
size_t max_len;
ffd_node_id_t node;
unsigned n_updates;
announce_info_t announces[];
};
static bool send_eth(const eth_addr_t *addr, unsigned ifindex, const void *buf, size_t len) { static bool send_eth(const eth_addr_t *addr, unsigned ifindex, const void *buf, size_t len) {
static const uint8_t zeros[46] = {0}; static const uint8_t zeros[46] = {0};
@ -166,6 +188,18 @@ void ffd_send_hellos(void) {
} }
} }
static bool add_ack_request(ffd_packet_t *packet, uint16_t nonce) {
ffd_tlv_ack_req_t *tlv = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_ACK_REQ, sizeof(ffd_tlv_ack_req_t));
if (!tlv)
return false;
tlv->reserved = 0;
tlv->nonce = htons(nonce);
tlv->interval = htons(FFD_ACK_INTERVAL);
return true;
}
static bool add_node_id(ffd_packet_t *packet, size_t max_len, ffd_node_id_t node_id) { static bool add_node_id(ffd_packet_t *packet, size_t max_len, ffd_node_id_t node_id) {
ffd_tlv_node_id_t *tlv = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_NODE_ID, sizeof(ffd_tlv_node_id_t)); ffd_tlv_node_id_t *tlv = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_NODE_ID, sizeof(ffd_tlv_node_id_t));
if (!tlv) if (!tlv)
@ -223,6 +257,34 @@ static bool add_update(ffd_packet_t *packet, size_t max_len, ffd_node_id_t *node
return true; return true;
} }
static bool add_retract(ffd_packet_t *packet, size_t max_len, ffd_node_id_t *node_id, ffd_node_id_t node, uint16_t type, uint16_t key) {
uint16_t len = packet->len;
if (!node_id || !ffd_are_node_ids_equal(node_id, &node)) {
if (!add_node_id(packet, max_len, node))
return false;
if (node_id)
*node_id = node;
}
ffd_tlv_update_t *update = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_UPDATE, sizeof(ffd_tlv_update_t));
if (!update) {
packet->len = len;
return false;
}
update->flags = 0;
update->reserved = 0;
update->interval = htons(FFD_UPDATE_INTERVAL);
update->seqno = 0;
update->metric = 0xffff; /* no need to htons */
update->type = htons(type);
update->key = htons(key);
return true;
}
void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool with_data) { void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool with_data) {
ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX);
@ -264,21 +326,83 @@ void ffd_send_retract(ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uin
if (!add_node_id(packet, FFD_PACKET_MAX, node)) if (!add_node_id(packet, FFD_PACKET_MAX, node))
return; return;
ffd_tlv_update_t *req = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_UPDATE, sizeof(ffd_tlv_update_t)); ffd_tlv_update_t *update = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_UPDATE, sizeof(ffd_tlv_update_t));
if (!req) if (!update)
return; return;
req->flags = 0; update->flags = 0;
req->reserved = 0; update->reserved = 0;
req->interval = htons(FFD_UPDATE_INTERVAL); update->interval = htons(FFD_UPDATE_INTERVAL);
req->seqno = 0; update->seqno = 0;
req->metric = 0xffff; /* no need to htons */ update->metric = 0xffff; /* no need to htons */
req->type = htons(type); update->type = htons(type);
req->key = htons(key); update->key = htons(key);
send_neigh(neigh, packet); send_neigh(neigh, packet);
} }
ffd_update_t* ffd_send_update_new(ffd_iface_t *iface, ffd_neigh_t *neigh, const uint16_t *nonce) {
unsigned max_updates = (FFD_PACKET_MAX+sizeof(ffd_tlv_update_t)+1)/(sizeof(ffd_tlv_update_t)+2);
ffd_update_t *update = calloc(1, sizeof(ffd_update_t) + max_updates*sizeof(announce_info_t));
update->iface = iface;
update->neigh = neigh;
update->max_len = FFD_PACKET_MAX;
update->packet = malloc(sizeof(ffd_packet_t)+FFD_PACKET_MAX);
update->packet->version_magic = htons(FFD_VERSION_MAGIC);
update->packet->len = 0;
if (nonce)
add_ack_request(update->packet, *nonce);
return update;
}
static inline bool is_update_duplicate(ffd_update_t *update, ffd_node_id_t node, uint16_t type, uint16_t key) {
unsigned i;
for (i = 0; i < update->n_updates; i++) {
if (ffd_are_node_ids_equal(&update->announces[i].node, &node)
&& update->announces[i].type == type && update->announces[i].key == key)
return true;
}
return false;
}
bool ffd_send_update_add(ffd_update_t *update, ffd_announce_t *announce) {
if (is_update_duplicate(update, announce->node, announce->type, announce->key))
return false;
if (!add_update(update->packet, update->max_len, &update->node, announce, false, update->neigh))
return false;
update->announces[update->n_updates++] = (announce_info_t){announce->node, announce->type, announce->key};
return true;
}
bool ffd_send_update_retract(ffd_update_t *update, ffd_node_id_t node, uint16_t type, uint16_t key) {
if (is_update_duplicate(update, node, type, key))
return false;
if (!add_retract(update->packet, update->max_len, &update->node, node, type, key))
return false;
update->announces[update->n_updates++] = (announce_info_t){node, type, key};
return true;
}
void ffd_send_update_finish(ffd_update_t *update) {
fprintf(stderr, "debug: sending %u aggregated update(s).\n", update->n_updates);
if (update->packet->len)
send_any(update->iface, update->neigh, update->packet);
free(update->packet);
free(update);
}
void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key, bool with_data) { void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key, bool with_data) {
ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX);

56
ffd/send.h Normal file
View file

@ -0,0 +1,56 @@
/*
Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FFD_SEND_H_
#define _FFD_SEND_H_
#include "ffd.h"
typedef struct _ffd_update_t ffd_update_t;
void ffd_send_ack(ffd_neigh_t *neigh, uint16_t nonce);
void ffd_send_hellos(void);
void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool with_data);
void ffd_send_retract(ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key);
void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key, bool with_data);
void ffd_send_seqno_request(ffd_neigh_t *neigh, ffd_announce_t *announce, uint16_t seqno);
ffd_update_t* ffd_send_update_new(ffd_iface_t *iface, ffd_neigh_t *neigh, const uint16_t *nonce);
bool ffd_send_update_add(ffd_update_t *update, ffd_announce_t *announce);
bool ffd_send_update_retract(ffd_update_t *update, ffd_node_id_t node, uint16_t type, uint16_t key);
void ffd_send_update_finish(ffd_update_t *update);
static inline void ffd_send_seqno_request_for(ffd_neigh_t *neigh, ffd_announce_t *announce) {
if (FFD_IS_INFINITY(announce->feasibility_distance))
return;
ffd_send_seqno_request(neigh, announce, announce->feasibility_distance.seqno+1);
}
#endif /* _FFD_SEND_H_ */

View file

@ -41,6 +41,6 @@ typedef struct __attribute__((packed)) _eth_addr_t {
typedef struct _ffd_packet_t ffd_packet_t; typedef struct _ffd_packet_t ffd_packet_t;
typedef struct _ffd_queue_t ffd_queue_t;
#endif /* _FFD_TYPES_H_ */ #endif /* _FFD_TYPES_H_ */

158
ffd/update.c Normal file
View file

@ -0,0 +1,158 @@
/*
Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ffd.h"
#include "neigh.h"
#include "queue.h"
#include "send.h"
#include <stdio.h>
static ffd_queue_t *pending_updates = NULL;
typedef struct _update_arg_t {
ffd_node_id_t node;
uint16_t type;
uint16_t key;
ffd_neigh_t *neigh;
unsigned ref;
} update_arg_t;
static inline update_arg_t* update_new(const ffd_node_id_t *node, uint16_t type, uint16_t key, ffd_neigh_t *neigh) {
update_arg_t *arg = malloc(sizeof(update_arg_t));
arg->node = *node;
arg->type = type;
arg->key = key;
if (neigh)
ffd_neigh_ref(neigh);
arg->neigh = neigh;
arg->ref = 0;
return arg;
}
static inline update_arg_t* update_ref(update_arg_t *arg) {
arg->ref++;
return arg;
}
static inline void update_unref(update_arg_t *arg) {
if (!--arg->ref) {
if (arg->neigh)
ffd_neigh_unref(arg->neigh);
free(arg);
}
}
static void update_request_ack(uint16_t nonce, void *argp) {
update_arg_t *arg = argp;
fprintf(stderr, "debug: sending acked update with nonce %u.\n", nonce);
ffd_update_t *update = ffd_send_update_new(NULL, arg->neigh, &nonce);
ffd_announce_t *announce = ffd_announce_find(&arg->node, arg->type, arg->key);
if (announce)
ffd_send_update_add(update, announce);
else
ffd_send_update_retract(update, arg->node, arg->type, arg->key);
ffd_send_update_finish(update);
}
static void update_request_ack_free(uint16_t nonce, void *arg) {
update_unref(arg);
}
void ffd_update_enqueue(const ffd_node_id_t *node, uint16_t type, uint16_t key, ffd_neigh_t *neigh, bool urgent) {
if (neigh)
ffd_neigh_ref(neigh);
update_arg_t *arg = update_new(node, type, key, neigh);
if (urgent) {
if (neigh) {
ffd_ack_request(update_request_ack, update_request_ack_free, FFD_ACK_INTERVAL, 10, update_ref(arg));
}
else {
int i;
for (i = 1; i <= 5; i++)
ffd_queue_put_delayed(&pending_updates, NULL, &now, i*FFD_URGENT_DELAY, update_ref(arg));
}
}
else {
ffd_queue_put_delayed(&pending_updates, NULL, &now, FFD_DELAY, update_ref(arg));
}
}
int ffd_update_timeout(void) {
return ffd_queue_timeout(&pending_updates);
}
void ffd_update_run(void) {
while (!ffd_update_timeout()) {
ffd_neigh_t *neigh = ((update_arg_t*)pending_updates->arg)->neigh;
ffd_update_t *update = ffd_send_update_new(NULL, neigh, NULL);
fprintf(stderr, "debug: sending scheduled updates.\n");
ffd_queue_t **entry;
for (entry = &pending_updates; *entry;) {
update_arg_t *arg = (*entry)->arg;
if (arg->neigh != neigh) {
entry = &(*entry)->next;
continue;
}
ffd_announce_t *announce = ffd_announce_find(&arg->node, arg->type, arg->key);
bool ret;
if (announce)
ret = ffd_send_update_add(update, announce);
else
ret = ffd_send_update_retract(update, arg->node, arg->type, arg->key);
if (!ret)
break;
update_unref(arg);
ffd_queue_drop(entry);
}
ffd_send_update_finish(update);
}
}

View file

@ -34,6 +34,9 @@
#include <time.h> #include <time.h>
extern struct timespec now;
bool file_readv(const char *file, const char *format, va_list ap); bool file_readv(const char *file, const char *format, va_list ap);
void random_bytes(void *buffer, size_t len); void random_bytes(void *buffer, size_t len);
@ -53,6 +56,11 @@ static inline bool are_eth_addrs_equal(const eth_addr_t *address1, const eth_add
return (a[0]==b[0] && a[1]==b[1] && a[2]==b[2] && a[3]==b[3] && a[4]==b[4] && a[5]==b[5]); return (a[0]==b[0] && a[1]==b[1] && a[2]==b[2] && a[3]==b[3] && a[4]==b[4] && a[5]==b[5]);
} }
static inline bool timespec_after(const struct timespec *tp1, const struct timespec *tp2) {
return (tp1->tv_sec > tp2->tv_sec ||
(tp1->tv_sec == tp2->tv_sec && tp1->tv_nsec > tp2->tv_nsec));
}
/* returns (tp1 - tp2) in centiseconds */ /* returns (tp1 - tp2) in centiseconds */
static inline int timespec_diff(const struct timespec *tp1, const struct timespec *tp2) { static inline int timespec_diff(const struct timespec *tp1, const struct timespec *tp2) {
return ((tp1->tv_sec - tp2->tv_sec))*100 + (tp1->tv_nsec - tp2->tv_nsec)/1e7; return ((tp1->tv_sec - tp2->tv_sec))*100 + (tp1->tv_nsec - tp2->tv_nsec)/1e7;