Compare commits
10 commits
e912f03740
...
e11b48f3ea
Author | SHA1 | Date | |
---|---|---|---|
e11b48f3ea | |||
758611ccd2 | |||
aa15b96d39 | |||
a45854b5d8 | |||
2bfd77c934 | |||
a4986182dc | |||
c3a0c36d3c | |||
4a40b6246a | |||
bc9f976d7f | |||
8e810f5fd8 |
14 changed files with 786 additions and 94 deletions
|
@ -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
91
ffd/ack.c
Normal 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);
|
||||||
|
}
|
107
ffd/announce.c
107
ffd/announce.c
|
@ -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);
|
||||||
|
}
|
||||||
|
|
145
ffd/ffd.c
145
ffd/ffd.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ffd_announce_seqno_request(announce, neigh, seqno)) {
|
||||||
fprintf(stderr, "debug: received seqno request, forwarding\n");
|
fprintf(stderr, "debug: received seqno request, forwarding\n");
|
||||||
ffd_send_seqno_request(announce->selected->neigh, announce, ntohs(tlv_req->seqno));
|
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();
|
||||||
|
|
||||||
|
|
39
ffd/ffd.h
39
ffd/ffd.h
|
@ -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_ */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
42
ffd/queue.c
Normal 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
75
ffd/queue.h
Normal 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_ */
|
142
ffd/send.c
142
ffd/send.c
|
@ -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
56
ffd/send.h
Normal 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_ */
|
|
@ -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
158
ffd/update.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
Reference in a new issue