Implement retransmits of important updates
This commit is contained in:
parent
c3a0c36d3c
commit
a4986182dc
10 changed files with 170 additions and 28 deletions
|
@ -8,6 +8,7 @@ add_executable(ffd
|
||||||
queue.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)
|
||||||
|
|
|
@ -123,7 +123,7 @@ static inline void seqno_update(ffd_announce_t *announce) {
|
||||||
next = cur;
|
next = cur;
|
||||||
|
|
||||||
fprintf(stderr, "debug: update matches seqno request, forwarding\n");
|
fprintf(stderr, "debug: update matches seqno request, forwarding\n");
|
||||||
ffd_send_update(NULL, req->neigh, announce, false);
|
ffd_update_enqueue(&announce->node, announce->type, announce->key, req->neigh, true);
|
||||||
ffd_neigh_unref(req->neigh);
|
ffd_neigh_unref(req->neigh);
|
||||||
free(req);
|
free(req);
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@ 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)
|
if (announce->selected)
|
||||||
|
@ -269,11 +269,13 @@ bool ffd_announce_seqno_request(ffd_announce_t *announce, ffd_neigh_t *neigh, ui
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ffd_announce_seqno_request_free_list(ffd_announce_t *announce) {
|
void ffd_announce_free(ffd_announce_t *announce) {
|
||||||
ffd_seqno_req_t *req, *next;
|
ffd_seqno_req_t *req, *req_next;
|
||||||
for (req = announce->seqno_req_list; req; req = next) {
|
for (req = announce->seqno_req_list; req; req = req_next) {
|
||||||
next = req->next;
|
req_next = req->next;
|
||||||
ffd_neigh_unref(req->neigh);
|
ffd_neigh_unref(req->neigh);
|
||||||
free(req);
|
free(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(announce);
|
||||||
}
|
}
|
||||||
|
|
22
ffd/ffd.c
22
ffd/ffd.c
|
@ -52,7 +52,7 @@ static char *mesh = "bat0";
|
||||||
int sockfd;
|
int sockfd;
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
|
|
||||||
static ffd_queue_head *tasks;
|
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;
|
||||||
|
@ -397,14 +397,14 @@ static void handle_tlv_seqno_req(const ffd_tlv_seqno_req_t *tlv_req, size_t len,
|
||||||
|
|
||||||
if ((int16_t)(seqno-announce->selected->metric_seqno.seqno) <= 0) {
|
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, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!announce->selected->neigh) {
|
if (!announce->selected->neigh) {
|
||||||
fprintf(stderr, "debug: received seqno request, 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, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,8 +533,7 @@ static void maintenance(void) {
|
||||||
if (!announce->nexthop_list) {
|
if (!announce->nexthop_list) {
|
||||||
*cur = *next;
|
*cur = *next;
|
||||||
next = cur;
|
next = cur;
|
||||||
ffd_announce_seqno_request_free_list(announce);
|
ffd_announce_free(announce);
|
||||||
free(announce);
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -591,6 +590,16 @@ static void register_periodic_tasks(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
@ -606,10 +615,11 @@ int main() {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ffd_queue_run(&tasks);
|
ffd_queue_run(&tasks);
|
||||||
|
ffd_update_run();
|
||||||
|
|
||||||
struct pollfd fds[1];
|
struct pollfd fds[1];
|
||||||
|
|
||||||
int timeout = 10*ffd_queue_timeout(&tasks);
|
int timeout = 10*timeout_min(ffd_queue_timeout(&tasks), ffd_update_timeout());
|
||||||
if (timeout < 0)
|
if (timeout < 0)
|
||||||
timeout = -1;
|
timeout = -1;
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,8 @@
|
||||||
|
|
||||||
#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_UPDATE_WITH_DATA 0x01
|
#define FFD_UPDATE_WITH_DATA 0x01
|
||||||
|
|
||||||
|
@ -203,7 +205,11 @@ ffd_announce_t* ffd_announce_get(const ffd_node_id_t *node, uint16_t type, uint1
|
||||||
ffd_nexthop_t* ffd_announce_nexthop_find(const ffd_announce_t *announce, ffd_neigh_t *neigh);
|
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);
|
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);
|
bool ffd_announce_seqno_request(ffd_announce_t *announce, ffd_neigh_t *neigh, uint16_t seqno);
|
||||||
void ffd_announce_seqno_request_free_list(ffd_announce_t *announce);
|
void ffd_announce_free(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);
|
||||||
|
int ffd_update_timeout(void);
|
||||||
|
void ffd_update_run(void);
|
||||||
|
|
||||||
void ffd_send_ack(ffd_neigh_t *neigh, uint16_t nonce);
|
void ffd_send_ack(ffd_neigh_t *neigh, uint16_t nonce);
|
||||||
void ffd_send_hellos(void);
|
void ffd_send_hellos(void);
|
||||||
|
|
|
@ -55,6 +55,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);
|
||||||
|
|
|
@ -27,11 +27,11 @@
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
|
|
||||||
|
|
||||||
void ffd_queue_put(ffd_queue_head **queue, ffd_queue_cb cb, const struct timespec *timeout, void *arg) {
|
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))
|
while (*queue && timespec_after(timeout, &(*queue)->timeout))
|
||||||
queue = &(*queue)->next;
|
queue = &(*queue)->next;
|
||||||
|
|
||||||
ffd_queue_head *entry = malloc(sizeof(ffd_queue_head));
|
ffd_queue_t *entry = malloc(sizeof(ffd_queue_t));
|
||||||
|
|
||||||
entry->cb = cb;
|
entry->cb = cb;
|
||||||
entry->timeout = *timeout;
|
entry->timeout = *timeout;
|
||||||
|
|
22
ffd/queue.h
22
ffd/queue.h
|
@ -32,26 +32,32 @@
|
||||||
|
|
||||||
typedef void (*ffd_queue_cb)(const struct timespec *timeout, void *arg);
|
typedef void (*ffd_queue_cb)(const struct timespec *timeout, void *arg);
|
||||||
|
|
||||||
typedef struct _ffd_queue_head {
|
struct _ffd_queue_t {
|
||||||
struct _ffd_queue_head *next;
|
ffd_queue_t *next;
|
||||||
ffd_queue_cb cb;
|
ffd_queue_cb cb;
|
||||||
struct timespec timeout;
|
struct timespec timeout;
|
||||||
void *arg;
|
void *arg;
|
||||||
} ffd_queue_head;
|
};
|
||||||
|
|
||||||
|
|
||||||
void ffd_queue_put(ffd_queue_head **queue, ffd_queue_cb cb, const 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_head **queue, ffd_queue_cb cb, const struct timespec *timeout, int delay, 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;
|
struct timespec timeout_delayed = *timeout;
|
||||||
add_interval(&timeout_delayed, delay);
|
add_interval(&timeout_delayed, delay);
|
||||||
ffd_queue_put(queue, cb, &timeout_delayed, arg);
|
ffd_queue_put(queue, cb, &timeout_delayed, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ffd_queue_run(ffd_queue_head **queue) {
|
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)) {
|
while (*queue && timespec_after(&now, &(*queue)->timeout)) {
|
||||||
ffd_queue_head *entry = *queue;
|
ffd_queue_t *entry = *queue;
|
||||||
*queue = (*queue)->next;
|
*queue = (*queue)->next;
|
||||||
|
|
||||||
entry->cb(&entry->timeout, entry->arg);
|
entry->cb(&entry->timeout, entry->arg);
|
||||||
|
@ -59,7 +65,7 @@ static inline void ffd_queue_run(ffd_queue_head **queue) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ffd_queue_timeout(ffd_queue_head *const *queue) {
|
static inline int ffd_queue_timeout(ffd_queue_t *const *queue) {
|
||||||
if (!*queue)
|
if (!*queue)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
116
ffd/update.c
Normal file
116
ffd/update.c
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
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 <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
static ffd_queue_t *pending_updates = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _update_arg {
|
||||||
|
ffd_node_id_t node;
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t key;
|
||||||
|
|
||||||
|
ffd_neigh_t *neigh;
|
||||||
|
unsigned ref;
|
||||||
|
} update_arg;
|
||||||
|
|
||||||
|
|
||||||
|
static inline update_arg* update_new(const ffd_node_id_t *node, uint16_t type, uint16_t key, ffd_neigh_t *neigh) {
|
||||||
|
update_arg *arg = malloc(sizeof(update_arg));
|
||||||
|
|
||||||
|
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* update_ref(update_arg *arg) {
|
||||||
|
arg->ref++;
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void update_unref(update_arg *arg) {
|
||||||
|
if (!--arg->ref) {
|
||||||
|
if (arg->neigh)
|
||||||
|
ffd_neigh_unref(arg->neigh);
|
||||||
|
|
||||||
|
free(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 *arg = update_new(node, type, key, neigh);
|
||||||
|
|
||||||
|
if (urgent) {
|
||||||
|
ffd_queue_put_delayed(&pending_updates, NULL, &now, FFD_URGENT_DELAY, update_ref(arg));
|
||||||
|
ffd_queue_put_delayed(&pending_updates, NULL, &now, 2*FFD_URGENT_DELAY, update_ref(arg));
|
||||||
|
ffd_queue_put_delayed(&pending_updates, NULL, &now, 3*FFD_URGENT_DELAY, update_ref(arg));
|
||||||
|
ffd_queue_put_delayed(&pending_updates, NULL, &now, 4*FFD_URGENT_DELAY, update_ref(arg));
|
||||||
|
ffd_queue_put_delayed(&pending_updates, NULL, &now, 5*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()) {
|
||||||
|
update_arg *arg = pending_updates->arg;
|
||||||
|
|
||||||
|
ffd_neigh_t *neigh = arg->neigh;
|
||||||
|
ffd_announce_t *announce = ffd_announce_find(&arg->node, arg->type, arg->key);
|
||||||
|
|
||||||
|
fprintf(stderr, "debug: sending scheduled update.\n");
|
||||||
|
|
||||||
|
if (announce)
|
||||||
|
ffd_send_update(NULL, neigh, announce, false);
|
||||||
|
else
|
||||||
|
ffd_send_retract(neigh, arg->node, arg->type, arg->key);
|
||||||
|
|
||||||
|
update_unref(arg);
|
||||||
|
ffd_queue_drop(&pending_updates);
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue