Implement retransmits of important updates

This commit is contained in:
Matthias Schiffer 2012-10-21 00:13:59 +02:00
parent c3a0c36d3c
commit a4986182dc
10 changed files with 170 additions and 28 deletions

View file

@ -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)

View file

@ -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);
} }

View file

@ -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;

View file

@ -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);

View file

@ -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;

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);

View file

@ -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;

View file

@ -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;

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_ */

116
ffd/update.c Normal file
View 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);
}
}