From 8e810f5fd809bad3047ea9224dd058edd20a64ac Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 8 Oct 2012 07:32:38 +0200 Subject: [PATCH 01/10] Keep track of forwarded seqno requests --- ffd/announce.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ ffd/ffd.c | 44 +++++++-------------- ffd/ffd.h | 16 ++++++++ 3 files changed, 132 insertions(+), 30 deletions(-) diff --git a/ffd/announce.c b/ffd/announce.c index 26ced28..00bd78c 100644 --- a/ffd/announce.c +++ b/ffd/announce.c @@ -110,6 +110,26 @@ ffd_metric_seqno_t get_metric(const ffd_announce_t *announce) { 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_send_update(NULL, req->neigh, announce, false); + ffd_neigh_unref(req->neigh); + free(req); + } + } +} + void ffd_announce_update(ffd_announce_t *announce) { maintain_nexthops(announce); @@ -127,6 +147,9 @@ void ffd_announce_update(ffd_announce_t *announce) { fprintf(stderr, "info: announce metric has changed significantly, sending updates\n"); ffd_send_update(NULL, NULL, announce, false); } + + 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) { @@ -175,3 +198,82 @@ ffd_announce_t* ffd_announce_get(const ffd_node_id_t *node, uint16_t type, uint1 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_seqno_request_free_list(ffd_announce_t *announce) { + ffd_seqno_req_t *req, *next; + for (req = announce->seqno_req_list; req; req = next) { + next = req->next; + ffd_neigh_unref(req->neigh); + free(req); + } +} diff --git a/ffd/ffd.c b/ffd/ffd.c index 5e967f3..7af9b29 100644 --- a/ffd/ffd.c +++ b/ffd/ffd.c @@ -284,28 +284,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; } -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) { if (len < sizeof(ffd_tlv_update_t)) { fprintf(stderr, "warn: received short update TLV.\n"); @@ -329,11 +307,11 @@ static void handle_tlv_update(const ffd_tlv_update_t *tlv_update, size_t len, ha bool feasible = ffd_is_feasible(announce, ms); 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 (feasible && tlv_update->metric != 0xffff /* no need to ntohs */) - nexthop = new_nexthop(announce, neigh); + nexthop = ffd_announce_nexthop_new(announce, neigh); } else { if (!feasible && nexthop == announce->selected) { @@ -397,8 +375,6 @@ static void handle_tlv_seqno_req(const ffd_tlv_seqno_req_t *tlv_req, size_t len, 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)); if (!announce) { @@ -416,21 +392,28 @@ static void handle_tlv_seqno_req(const ffd_tlv_seqno_req_t *tlv_req, size_t len, if (announce->selected->neigh == neigh) 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"); ffd_send_update(NULL, neigh, announce, false); return; } if (!announce->selected->neigh) { - fprintf(stderr, "debug: incrementing seqno\n"); + fprintf(stderr, "debug: received seqno request, incrementing seqno\n"); announce->selected->metric_seqno.seqno++; ffd_send_update(NULL, neigh, announce, false); return; } - fprintf(stderr, "debug: received seqno request, forwarding\n"); - ffd_send_seqno_request(announce->selected->neigh, announce, ntohs(tlv_req->seqno)); + if (ffd_announce_seqno_request(announce, neigh, 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) { @@ -547,6 +530,7 @@ static void maintenance(void) { if (!announce->nexthop_list) { *cur = *next; next = cur; + ffd_announce_seqno_request_free_list(announce); free(announce); continue; diff --git a/ffd/ffd.h b/ffd/ffd.h index e7c48d7..bf00984 100644 --- a/ffd/ffd.h +++ b/ffd/ffd.h @@ -47,6 +47,8 @@ #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 @@ -73,6 +75,14 @@ typedef struct _ffd_nexthop_t { bool requested_update; } 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 { struct _ffd_announce_t *next; @@ -84,6 +94,8 @@ typedef struct _ffd_announce_t { uint16_t last_metric; ffd_metric_seqno_t feasibility_distance; + ffd_seqno_req_t *seqno_req_list; + ffd_nexthop_t *selected; ffd_nexthop_t *nexthop_list; @@ -189,6 +201,10 @@ 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_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_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_seqno_request_free_list(ffd_announce_t *announce); void ffd_send_ack(ffd_neigh_t *neigh, uint16_t nonce); void ffd_send_hellos(void); From bc9f976d7fe70176aac4bc9c87205d6ac1f530cc Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 13 Oct 2012 20:01:48 +0200 Subject: [PATCH 02/10] Add timeout queues --- ffd/CMakeLists.txt | 1 + ffd/ffd.c | 74 ++++++++++++++++++++++++++-------------------- ffd/ffd.h | 1 - ffd/queue.c | 42 ++++++++++++++++++++++++++ ffd/queue.h | 69 ++++++++++++++++++++++++++++++++++++++++++ ffd/util.h | 8 +++++ 6 files changed, 162 insertions(+), 33 deletions(-) create mode 100644 ffd/queue.c create mode 100644 ffd/queue.h diff --git a/ffd/CMakeLists.txt b/ffd/CMakeLists.txt index 1571580..432ac61 100644 --- a/ffd/CMakeLists.txt +++ b/ffd/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(ffd ffd.c neigh.c netif.c + queue.c send.c tlv.c util.c diff --git a/ffd/ffd.c b/ffd/ffd.c index 7af9b29..9351476 100644 --- a/ffd/ffd.c +++ b/ffd/ffd.c @@ -28,6 +28,7 @@ #include "neigh.h" #include "netif.h" #include "packet.h" +#include "queue.h" #include "tlv.h" #include "tlv_types.h" @@ -51,10 +52,10 @@ static char *mesh = "bat0"; int sockfd; struct timespec now; +static ffd_queue_head *tasks; + ffd_node_id_t self; - ffd_iface_t *iface_list = NULL; - ffd_announce_t *announce_list = NULL; @@ -489,6 +490,8 @@ static void receive_packet(void) { } static void send_updates(void) { + fprintf(stderr, "debug: sending periodic updates.\n"); + ffd_iface_t *iface; for (iface = iface_list; iface; iface = iface->next) { ffd_send_update(iface, NULL, NULL, false); @@ -558,6 +561,36 @@ 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); +} + + int main() { if (!check_config()) return 1; @@ -569,44 +602,21 @@ int main() { return 1; update_time(); - - struct timespec next_hello = now; - struct timespec next_update = now; - struct timespec next_maintenance = now; + register_periodic_tasks(); while (true) { - int maintenance_timeout = timespec_diff(&next_maintenance, &now); - if (maintenance_timeout <= 0) { - maintenance(); - - 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; + ffd_queue_run(&tasks); struct pollfd fds[1]; + int timeout = 10*ffd_queue_timeout(&tasks); + if (timeout < 0) + timeout = -1; + fds[0].fd = sockfd; fds[0].events = POLLIN; - poll(fds, 1, 10*timeout); + poll(fds, 1, timeout); update_time(); diff --git a/ffd/ffd.h b/ffd/ffd.h index bf00984..edba710 100644 --- a/ffd/ffd.h +++ b/ffd/ffd.h @@ -145,7 +145,6 @@ extern ffd_iface_t *iface_list; extern ffd_announce_t *announce_list; extern int sockfd; -extern struct timespec now; #define FFD_NODE_ID_UNSPEC ((ffd_node_id_t){}) diff --git a/ffd/queue.c b/ffd/queue.c new file mode 100644 index 0000000..3729e50 --- /dev/null +++ b/ffd/queue.c @@ -0,0 +1,42 @@ +/* + Copyright (c) 2012, Matthias Schiffer + 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_head **queue, ffd_queue_cb cb, const struct timespec *timeout, void *arg) { + while (*queue && timespec_after(timeout, &(*queue)->timeout)) + queue = &(*queue)->next; + + ffd_queue_head *entry = malloc(sizeof(ffd_queue_head)); + + entry->cb = cb; + entry->timeout = *timeout; + entry->arg = arg; + + entry->next = *queue; + *queue = entry; +} diff --git a/ffd/queue.h b/ffd/queue.h new file mode 100644 index 0000000..9fae53d --- /dev/null +++ b/ffd/queue.h @@ -0,0 +1,69 @@ +/* + Copyright (c) 2012, Matthias Schiffer + 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); + +typedef struct _ffd_queue_head { + struct _ffd_queue_head *next; + ffd_queue_cb cb; + struct timespec timeout; + void *arg; +} ffd_queue_head; + + +void ffd_queue_put(ffd_queue_head **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) { + struct timespec timeout_delayed = *timeout; + add_interval(&timeout_delayed, delay); + ffd_queue_put(queue, cb, &timeout_delayed, arg); +} + +static inline void ffd_queue_run(ffd_queue_head **queue) { + while (*queue && timespec_after(&now, &(*queue)->timeout)) { + ffd_queue_head *entry = *queue; + *queue = (*queue)->next; + + entry->cb(&entry->timeout, entry->arg); + free(entry); + } +} + +static inline int ffd_queue_timeout(ffd_queue_head *const *queue) { + if (!*queue) + return -1; + + return max(timespec_diff(&(*queue)->timeout, &now), 0); +} + +#endif /* _FFD_QUEUE_H_ */ diff --git a/ffd/util.h b/ffd/util.h index 9d481cb..0660b94 100644 --- a/ffd/util.h +++ b/ffd/util.h @@ -34,6 +34,9 @@ #include +extern struct timespec now; + + bool file_readv(const char *file, const char *format, va_list ap); 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]); } +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 */ 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; From 4a40b6246a4862ac52fa4ef7f692f63784e72330 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 20 Oct 2012 05:04:19 +0200 Subject: [PATCH 03/10] Somewhat hacky implementation of update retransmits --- ffd/announce.c | 4 +-- ffd/ffd.c | 26 +++++++++++----- ffd/ffd.h | 2 +- ffd/queue.h | 4 +++ ffd/send.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 104 insertions(+), 16 deletions(-) diff --git a/ffd/announce.c b/ffd/announce.c index 00bd78c..491aefd 100644 --- a/ffd/announce.c +++ b/ffd/announce.c @@ -123,7 +123,7 @@ static inline void seqno_update(ffd_announce_t *announce) { next = cur; fprintf(stderr, "debug: update matches seqno request, forwarding\n"); - ffd_send_update(NULL, req->neigh, announce, false); + ffd_send_update(NULL, req->neigh, announce, true, false); ffd_neigh_unref(req->neigh); free(req); } @@ -145,7 +145,7 @@ void ffd_announce_update(ffd_announce_t *announce) { if (((announce->last_metric == 0xffff) != (announce->metric.metric == 0xffff)) || diff <= -1024 || diff >= 384) { fprintf(stderr, "info: announce metric has changed significantly, sending updates\n"); - ffd_send_update(NULL, NULL, announce, false); + ffd_send_update(NULL, NULL, announce, announce->metric.metric == 0xffff, false); } if (announce->selected) diff --git a/ffd/ffd.c b/ffd/ffd.c index 9351476..fd82d0c 100644 --- a/ffd/ffd.c +++ b/ffd/ffd.c @@ -52,7 +52,8 @@ static char *mesh = "bat0"; int sockfd; struct timespec now; -static ffd_queue_head *tasks; +ffd_queue_head *tasks = NULL; +ffd_queue_head *retransmits = NULL; ffd_node_id_t self; ffd_iface_t *iface_list = NULL; @@ -358,13 +359,13 @@ static void handle_tlv_announce_req(const ffd_tlv_announce_req_t *tlv_req, size_ fprintf(stderr, "debug: received announce request\n"); if (ffd_is_node_id_unspec(&tlv_req->node)) { - ffd_send_update(NULL, get_tlv_neigh(arg), NULL, tlv_req->flags & FFD_UPDATE_WITH_DATA); + ffd_send_update(NULL, get_tlv_neigh(arg), NULL, false, tlv_req->flags & FFD_UPDATE_WITH_DATA); } else { ffd_announce_t *announce = ffd_announce_find(&tlv_req->node, ntohs(tlv_req->type), ntohs(tlv_req->key)); if (announce) - ffd_send_update(NULL, get_tlv_neigh(arg), announce, tlv_req->flags & FFD_UPDATE_WITH_DATA); + ffd_send_update(NULL, get_tlv_neigh(arg), announce, false, tlv_req->flags & FFD_UPDATE_WITH_DATA); else ffd_send_retract(get_tlv_neigh(arg), tlv_req->node, ntohs(tlv_req->type), ntohs(tlv_req->key)); } @@ -397,14 +398,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) { fprintf(stderr, "debug: received seqno request, seqno already ok\n"); - ffd_send_update(NULL, neigh, announce, false); + ffd_send_update(NULL, neigh, announce, true, false); return; } if (!announce->selected->neigh) { fprintf(stderr, "debug: received seqno request, incrementing seqno\n"); announce->selected->metric_seqno.seqno++; - ffd_send_update(NULL, neigh, announce, false); + ffd_send_update(NULL, neigh, announce, true, false); return; } @@ -494,7 +495,7 @@ static void send_updates(void) { ffd_iface_t *iface; for (iface = iface_list; iface; iface = iface->next) { - ffd_send_update(iface, NULL, NULL, false); + ffd_send_update(iface, NULL, NULL, false, false); } } @@ -591,6 +592,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() { if (!check_config()) return 1; @@ -606,10 +617,11 @@ int main() { while (true) { ffd_queue_run(&tasks); + ffd_queue_run(&retransmits); struct pollfd fds[1]; - int timeout = 10*ffd_queue_timeout(&tasks); + int timeout = 10*timeout_min(ffd_queue_timeout(&tasks), ffd_queue_timeout(&retransmits)); if (timeout < 0) timeout = -1; diff --git a/ffd/ffd.h b/ffd/ffd.h index edba710..4bb7038 100644 --- a/ffd/ffd.h +++ b/ffd/ffd.h @@ -207,7 +207,7 @@ void ffd_announce_seqno_request_free_list(ffd_announce_t *announce); 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_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool urgent, 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); diff --git a/ffd/queue.h b/ffd/queue.h index 9fae53d..4674481 100644 --- a/ffd/queue.h +++ b/ffd/queue.h @@ -40,6 +40,10 @@ typedef struct _ffd_queue_head { } ffd_queue_head; +extern ffd_queue_head *tasks; +extern ffd_queue_head *retransmits; + + void ffd_queue_put(ffd_queue_head **queue, ffd_queue_cb cb, const struct timespec *timeout, void *arg); diff --git a/ffd/send.c b/ffd/send.c index ebda0de..936e1fb 100644 --- a/ffd/send.c +++ b/ffd/send.c @@ -27,6 +27,7 @@ #include "ffd.h" #include "neigh.h" #include "packet.h" +#include "queue.h" #include "tlv.h" #include "tlv_types.h" @@ -72,6 +73,7 @@ static bool send_eth(const eth_addr_t *addr, unsigned ifindex, const void *buf, return true; } + static inline bool send_neigh(const ffd_neigh_t *neigh, const ffd_packet_t *packet) { if (!neigh->iface) return false; @@ -84,8 +86,12 @@ static inline bool send_neigh(const ffd_neigh_t *neigh, const ffd_packet_t *pack return true; } +static inline bool send_ifindex(unsigned ifindex, const ffd_packet_t *packet) { + return send_eth(&ffd_addr, ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len)); +} + static inline bool send_iface(const ffd_iface_t *iface, const ffd_packet_t *packet) { - if (!send_eth(&ffd_addr, iface->ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len))) { + if (!send_ifindex(iface->ifindex, packet)) { fprintf(stderr, "send_eth: %m\n"); return false; } @@ -108,6 +114,54 @@ static inline void send_any(const ffd_iface_t *iface, const ffd_neigh_t *neigh, send_broadcast(packet); } + +typedef struct _retransmit_arg { + unsigned iface; + ffd_neigh_t *neigh; + ffd_packet_t *packet; + + unsigned ref; +} retransmit_arg; + +static void retransmit_cb(const struct timespec *timeout, void *argp) { + retransmit_arg *arg = argp; + + fprintf(stderr, "debug: doing retransmit\n"); + + if (arg->neigh) + send_neigh(arg->neigh, arg->packet); + else if(arg->iface) + send_ifindex(arg->iface, arg->packet); + else + send_broadcast(arg->packet); + + if (!--arg->ref) { + if (arg->neigh) + ffd_neigh_unref(arg->neigh); + + free(arg->packet); + free(arg); + } +} + +static void send_retransmit(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_packet_t *packet) { + if (neigh) + ffd_neigh_ref(neigh); + + retransmit_arg *arg = malloc(sizeof(retransmit_arg)); + arg->iface = iface ? iface->ifindex : 0; + arg->neigh = neigh; + arg->packet = packet; + arg->ref = 5; + + ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 100, arg); + ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 75, arg); + ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 50, arg); + ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 25, arg); + ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 0, arg); +} + + void ffd_send_ack(ffd_neigh_t *neigh, uint16_t nonce) { ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); @@ -223,8 +277,12 @@ static bool add_update(ffd_packet_t *packet, size_t max_len, ffd_node_id_t *node return true; } -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); +void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool urgent, bool with_data) { + ffd_packet_t *packet; + if (urgent) + packet = malloc(sizeof(ffd_packet_t)+FFD_PACKET_MAX); + else + packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); packet->version_magic = htons(FFD_VERSION_MAGIC); packet->len = 0; @@ -238,7 +296,13 @@ void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *ann ffd_announce_t *a; for (a = announce_list; a; a = a->next) { if (!add_update(packet, FFD_PACKET_MAX, &node_id, a, with_data, iface || neigh)) { - send_any(iface, neigh, packet); + if (urgent) { + send_retransmit(iface, neigh, packet); + packet = malloc(sizeof(ffd_packet_t)+FFD_PACKET_MAX); + } + else { + send_any(iface, neigh, packet); + } node_id = FFD_NODE_ID_UNSPEC; packet->len = 0; @@ -251,8 +315,16 @@ void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *ann } } - if (packet->len) - send_any(iface, neigh, packet); + if (urgent) { + if (packet->len) + send_retransmit(iface, neigh, packet); + else + free(packet); + } + else { + if (packet->len) + send_any(iface, neigh, packet); + } } void ffd_send_retract(ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key) { From c3a0c36d3c935097ccc72d92581f0f2b7bc794a9 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 20 Oct 2012 10:58:10 +0200 Subject: [PATCH 04/10] Revert "Somewhat hacky implementation of update retransmits" This reverts commit 4a40b6246a4862ac52fa4ef7f692f63784e72330. --- ffd/announce.c | 4 +-- ffd/ffd.c | 26 +++++----------- ffd/ffd.h | 2 +- ffd/queue.h | 4 --- ffd/send.c | 84 ++++---------------------------------------------- 5 files changed, 16 insertions(+), 104 deletions(-) diff --git a/ffd/announce.c b/ffd/announce.c index 491aefd..00bd78c 100644 --- a/ffd/announce.c +++ b/ffd/announce.c @@ -123,7 +123,7 @@ static inline void seqno_update(ffd_announce_t *announce) { next = cur; fprintf(stderr, "debug: update matches seqno request, forwarding\n"); - ffd_send_update(NULL, req->neigh, announce, true, false); + ffd_send_update(NULL, req->neigh, announce, false); ffd_neigh_unref(req->neigh); free(req); } @@ -145,7 +145,7 @@ void ffd_announce_update(ffd_announce_t *announce) { if (((announce->last_metric == 0xffff) != (announce->metric.metric == 0xffff)) || diff <= -1024 || diff >= 384) { fprintf(stderr, "info: announce metric has changed significantly, sending updates\n"); - ffd_send_update(NULL, NULL, announce, announce->metric.metric == 0xffff, false); + ffd_send_update(NULL, NULL, announce, false); } if (announce->selected) diff --git a/ffd/ffd.c b/ffd/ffd.c index fd82d0c..9351476 100644 --- a/ffd/ffd.c +++ b/ffd/ffd.c @@ -52,8 +52,7 @@ static char *mesh = "bat0"; int sockfd; struct timespec now; -ffd_queue_head *tasks = NULL; -ffd_queue_head *retransmits = NULL; +static ffd_queue_head *tasks; ffd_node_id_t self; ffd_iface_t *iface_list = NULL; @@ -359,13 +358,13 @@ static void handle_tlv_announce_req(const ffd_tlv_announce_req_t *tlv_req, size_ fprintf(stderr, "debug: received announce request\n"); if (ffd_is_node_id_unspec(&tlv_req->node)) { - ffd_send_update(NULL, get_tlv_neigh(arg), NULL, false, tlv_req->flags & FFD_UPDATE_WITH_DATA); + ffd_send_update(NULL, get_tlv_neigh(arg), NULL, tlv_req->flags & FFD_UPDATE_WITH_DATA); } else { ffd_announce_t *announce = ffd_announce_find(&tlv_req->node, ntohs(tlv_req->type), ntohs(tlv_req->key)); if (announce) - ffd_send_update(NULL, get_tlv_neigh(arg), announce, false, tlv_req->flags & FFD_UPDATE_WITH_DATA); + ffd_send_update(NULL, get_tlv_neigh(arg), announce, tlv_req->flags & FFD_UPDATE_WITH_DATA); else ffd_send_retract(get_tlv_neigh(arg), tlv_req->node, ntohs(tlv_req->type), ntohs(tlv_req->key)); } @@ -398,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) { fprintf(stderr, "debug: received seqno request, seqno already ok\n"); - ffd_send_update(NULL, neigh, announce, true, false); + ffd_send_update(NULL, neigh, announce, false); return; } if (!announce->selected->neigh) { fprintf(stderr, "debug: received seqno request, incrementing seqno\n"); announce->selected->metric_seqno.seqno++; - ffd_send_update(NULL, neigh, announce, true, false); + ffd_send_update(NULL, neigh, announce, false); return; } @@ -495,7 +494,7 @@ static void send_updates(void) { ffd_iface_t *iface; for (iface = iface_list; iface; iface = iface->next) { - ffd_send_update(iface, NULL, NULL, false, false); + ffd_send_update(iface, NULL, NULL, false); } } @@ -592,16 +591,6 @@ 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() { if (!check_config()) return 1; @@ -617,11 +606,10 @@ int main() { while (true) { ffd_queue_run(&tasks); - ffd_queue_run(&retransmits); struct pollfd fds[1]; - int timeout = 10*timeout_min(ffd_queue_timeout(&tasks), ffd_queue_timeout(&retransmits)); + int timeout = 10*ffd_queue_timeout(&tasks); if (timeout < 0) timeout = -1; diff --git a/ffd/ffd.h b/ffd/ffd.h index 4bb7038..edba710 100644 --- a/ffd/ffd.h +++ b/ffd/ffd.h @@ -207,7 +207,7 @@ void ffd_announce_seqno_request_free_list(ffd_announce_t *announce); 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 urgent, bool with_data); +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); diff --git a/ffd/queue.h b/ffd/queue.h index 4674481..9fae53d 100644 --- a/ffd/queue.h +++ b/ffd/queue.h @@ -40,10 +40,6 @@ typedef struct _ffd_queue_head { } ffd_queue_head; -extern ffd_queue_head *tasks; -extern ffd_queue_head *retransmits; - - void ffd_queue_put(ffd_queue_head **queue, ffd_queue_cb cb, const struct timespec *timeout, void *arg); diff --git a/ffd/send.c b/ffd/send.c index 936e1fb..ebda0de 100644 --- a/ffd/send.c +++ b/ffd/send.c @@ -27,7 +27,6 @@ #include "ffd.h" #include "neigh.h" #include "packet.h" -#include "queue.h" #include "tlv.h" #include "tlv_types.h" @@ -73,7 +72,6 @@ static bool send_eth(const eth_addr_t *addr, unsigned ifindex, const void *buf, return true; } - static inline bool send_neigh(const ffd_neigh_t *neigh, const ffd_packet_t *packet) { if (!neigh->iface) return false; @@ -86,12 +84,8 @@ static inline bool send_neigh(const ffd_neigh_t *neigh, const ffd_packet_t *pack return true; } -static inline bool send_ifindex(unsigned ifindex, const ffd_packet_t *packet) { - return send_eth(&ffd_addr, ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len)); -} - static inline bool send_iface(const ffd_iface_t *iface, const ffd_packet_t *packet) { - if (!send_ifindex(iface->ifindex, packet)) { + if (!send_eth(&ffd_addr, iface->ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len))) { fprintf(stderr, "send_eth: %m\n"); return false; } @@ -114,54 +108,6 @@ static inline void send_any(const ffd_iface_t *iface, const ffd_neigh_t *neigh, send_broadcast(packet); } - -typedef struct _retransmit_arg { - unsigned iface; - ffd_neigh_t *neigh; - ffd_packet_t *packet; - - unsigned ref; -} retransmit_arg; - -static void retransmit_cb(const struct timespec *timeout, void *argp) { - retransmit_arg *arg = argp; - - fprintf(stderr, "debug: doing retransmit\n"); - - if (arg->neigh) - send_neigh(arg->neigh, arg->packet); - else if(arg->iface) - send_ifindex(arg->iface, arg->packet); - else - send_broadcast(arg->packet); - - if (!--arg->ref) { - if (arg->neigh) - ffd_neigh_unref(arg->neigh); - - free(arg->packet); - free(arg); - } -} - -static void send_retransmit(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_packet_t *packet) { - if (neigh) - ffd_neigh_ref(neigh); - - retransmit_arg *arg = malloc(sizeof(retransmit_arg)); - arg->iface = iface ? iface->ifindex : 0; - arg->neigh = neigh; - arg->packet = packet; - arg->ref = 5; - - ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 100, arg); - ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 75, arg); - ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 50, arg); - ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 25, arg); - ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 0, arg); -} - - void ffd_send_ack(ffd_neigh_t *neigh, uint16_t nonce) { ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); @@ -277,12 +223,8 @@ static bool add_update(ffd_packet_t *packet, size_t max_len, ffd_node_id_t *node return true; } -void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool urgent, bool with_data) { - ffd_packet_t *packet; - if (urgent) - packet = malloc(sizeof(ffd_packet_t)+FFD_PACKET_MAX); - else - packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); +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); packet->version_magic = htons(FFD_VERSION_MAGIC); packet->len = 0; @@ -296,13 +238,7 @@ void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *ann ffd_announce_t *a; for (a = announce_list; a; a = a->next) { if (!add_update(packet, FFD_PACKET_MAX, &node_id, a, with_data, iface || neigh)) { - if (urgent) { - send_retransmit(iface, neigh, packet); - packet = malloc(sizeof(ffd_packet_t)+FFD_PACKET_MAX); - } - else { - send_any(iface, neigh, packet); - } + send_any(iface, neigh, packet); node_id = FFD_NODE_ID_UNSPEC; packet->len = 0; @@ -315,16 +251,8 @@ void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *ann } } - if (urgent) { - if (packet->len) - send_retransmit(iface, neigh, packet); - else - free(packet); - } - else { - if (packet->len) - send_any(iface, neigh, packet); - } + if (packet->len) + send_any(iface, neigh, packet); } void ffd_send_retract(ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key) { From a4986182dcad508c17a6eb8fd3e556f18cfaa349 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 21 Oct 2012 00:13:59 +0200 Subject: [PATCH 05/10] Implement retransmits of important updates --- ffd/CMakeLists.txt | 1 + ffd/announce.c | 14 +++--- ffd/ffd.c | 22 ++++++--- ffd/ffd.h | 8 +++- ffd/neigh.c | 5 ++ ffd/neigh.h | 4 -- ffd/queue.c | 4 +- ffd/queue.h | 22 +++++---- ffd/types.h | 2 +- ffd/update.c | 116 +++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 170 insertions(+), 28 deletions(-) create mode 100644 ffd/update.c diff --git a/ffd/CMakeLists.txt b/ffd/CMakeLists.txt index 432ac61..830fef4 100644 --- a/ffd/CMakeLists.txt +++ b/ffd/CMakeLists.txt @@ -8,6 +8,7 @@ add_executable(ffd queue.c send.c tlv.c + update.c util.c ) target_link_libraries(ffd rt) diff --git a/ffd/announce.c b/ffd/announce.c index 00bd78c..2e54725 100644 --- a/ffd/announce.c +++ b/ffd/announce.c @@ -123,7 +123,7 @@ static inline void seqno_update(ffd_announce_t *announce) { next = cur; 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); free(req); } @@ -145,7 +145,7 @@ void ffd_announce_update(ffd_announce_t *announce) { if (((announce->last_metric == 0xffff) != (announce->metric.metric == 0xffff)) || diff <= -1024 || diff >= 384) { 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) @@ -269,11 +269,13 @@ bool ffd_announce_seqno_request(ffd_announce_t *announce, ffd_neigh_t *neigh, ui return false; } -void ffd_announce_seqno_request_free_list(ffd_announce_t *announce) { - ffd_seqno_req_t *req, *next; - for (req = announce->seqno_req_list; req; req = next) { - next = req->next; +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); } diff --git a/ffd/ffd.c b/ffd/ffd.c index 9351476..5ff5f1b 100644 --- a/ffd/ffd.c +++ b/ffd/ffd.c @@ -52,7 +52,7 @@ static char *mesh = "bat0"; int sockfd; struct timespec now; -static ffd_queue_head *tasks; +static ffd_queue_t *tasks = NULL; ffd_node_id_t self; 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) { 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; } if (!announce->selected->neigh) { fprintf(stderr, "debug: received seqno request, incrementing seqno\n"); announce->selected->metric_seqno.seqno++; - ffd_send_update(NULL, neigh, announce, false); + ffd_update_enqueue(&announce->node, announce->type, announce->key, neigh, false); return; } @@ -533,8 +533,7 @@ static void maintenance(void) { if (!announce->nexthop_list) { *cur = *next; next = cur; - ffd_announce_seqno_request_free_list(announce); - free(announce); + ffd_announce_free(announce); 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() { if (!check_config()) return 1; @@ -606,10 +615,11 @@ int main() { while (true) { ffd_queue_run(&tasks); + ffd_update_run(); 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) timeout = -1; diff --git a/ffd/ffd.h b/ffd/ffd.h index edba710..748082f 100644 --- a/ffd/ffd.h +++ b/ffd/ffd.h @@ -51,6 +51,8 @@ #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 @@ -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_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_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_hellos(void); diff --git a/ffd/neigh.c b/ffd/neigh.c index 1b0d41d..2c73362 100644 --- a/ffd/neigh.c +++ b/ffd/neigh.c @@ -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) { if (!neigh->hello_log || !neigh->hello_interval || !neigh->iface) return 0xffff; diff --git a/ffd/neigh.h b/ffd/neigh.h index aa0d1f9..3e84a8e 100644 --- a/ffd/neigh.h +++ b/ffd/neigh.h @@ -44,10 +44,6 @@ static inline void ffd_neigh_ref(ffd_neigh_t *neigh) { 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); void ffd_neigh_unref(ffd_neigh_t *neigh); diff --git a/ffd/queue.c b/ffd/queue.c index 3729e50..23f96bc 100644 --- a/ffd/queue.c +++ b/ffd/queue.c @@ -27,11 +27,11 @@ #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)) 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->timeout = *timeout; diff --git a/ffd/queue.h b/ffd/queue.h index 9fae53d..f9b8008 100644 --- a/ffd/queue.h +++ b/ffd/queue.h @@ -32,26 +32,32 @@ typedef void (*ffd_queue_cb)(const struct timespec *timeout, void *arg); -typedef struct _ffd_queue_head { - struct _ffd_queue_head *next; +struct _ffd_queue_t { + ffd_queue_t *next; ffd_queue_cb cb; struct timespec timeout; 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; add_interval(&timeout_delayed, delay); 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)) { - ffd_queue_head *entry = *queue; + ffd_queue_t *entry = *queue; *queue = (*queue)->next; 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) return -1; diff --git a/ffd/types.h b/ffd/types.h index f0c6c39..b20d691 100644 --- a/ffd/types.h +++ b/ffd/types.h @@ -41,6 +41,6 @@ typedef struct __attribute__((packed)) _eth_addr_t { typedef struct _ffd_packet_t ffd_packet_t; - +typedef struct _ffd_queue_t ffd_queue_t; #endif /* _FFD_TYPES_H_ */ diff --git a/ffd/update.c b/ffd/update.c new file mode 100644 index 0000000..e5faab5 --- /dev/null +++ b/ffd/update.c @@ -0,0 +1,116 @@ +/* + Copyright (c) 2012, Matthias Schiffer + 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 + + +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); + } +} From 2bfd77c93454037152aa7af07f44cb6ca9229e83 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 21 Oct 2012 00:24:28 +0200 Subject: [PATCH 06/10] Move send functions to a new header --- ffd/announce.c | 1 + ffd/ffd.c | 1 + ffd/ffd.h | 14 -------------- ffd/neigh.c | 1 + ffd/send.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ ffd/update.c | 1 + 6 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 ffd/send.h diff --git a/ffd/announce.c b/ffd/announce.c index 2e54725..f68bb48 100644 --- a/ffd/announce.c +++ b/ffd/announce.c @@ -26,6 +26,7 @@ #include "ffd.h" #include "neigh.h" +#include "send.h" #include diff --git a/ffd/ffd.c b/ffd/ffd.c index 5ff5f1b..9acd201 100644 --- a/ffd/ffd.c +++ b/ffd/ffd.c @@ -29,6 +29,7 @@ #include "netif.h" #include "packet.h" #include "queue.h" +#include "send.h" #include "tlv.h" #include "tlv_types.h" diff --git a/ffd/ffd.h b/ffd/ffd.h index 748082f..42d679c 100644 --- a/ffd/ffd.h +++ b/ffd/ffd.h @@ -211,18 +211,4 @@ void ffd_update_enqueue(const ffd_node_id_t *node, uint16_t type, uint16_t key, int ffd_update_timeout(void); void ffd_update_run(void); -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); - -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_FFD_H_ */ diff --git a/ffd/neigh.c b/ffd/neigh.c index 2c73362..e8e7d0f 100644 --- a/ffd/neigh.c +++ b/ffd/neigh.c @@ -25,6 +25,7 @@ #include "neigh.h" +#include "send.h" ffd_neigh_t* ffd_neigh_get(ffd_iface_t *iface, const eth_addr_t *addr) { diff --git a/ffd/send.h b/ffd/send.h new file mode 100644 index 0000000..ce70199 --- /dev/null +++ b/ffd/send.h @@ -0,0 +1,47 @@ +/* + Copyright (c) 2012, Matthias Schiffer + 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" + + +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); + +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_ */ diff --git a/ffd/update.c b/ffd/update.c index e5faab5..5ae3006 100644 --- a/ffd/update.c +++ b/ffd/update.c @@ -27,6 +27,7 @@ #include "ffd.h" #include "neigh.h" #include "queue.h" +#include "send.h" #include From a45854b5d8dc699e68c5b538e299d5ef8fda59f3 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 21 Oct 2012 01:28:33 +0200 Subject: [PATCH 07/10] Aggregate similar updates --- ffd/send.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++---- ffd/send.h | 9 ++++ ffd/update.c | 51 ++++++++++++++------- 3 files changed, 161 insertions(+), 26 deletions(-) diff --git a/ffd/send.c b/ffd/send.c index ebda0de..dc6544b 100644 --- a/ffd/send.c +++ b/ffd/send.c @@ -27,6 +27,7 @@ #include "ffd.h" #include "neigh.h" #include "packet.h" +#include "send.h" #include "tlv.h" #include "tlv_types.h" @@ -40,6 +41,27 @@ #include + +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 const uint8_t zeros[46] = {0}; @@ -223,6 +245,34 @@ static bool add_update(ffd_packet_t *packet, size_t max_len, ffd_node_id_t *node 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) { ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); @@ -264,21 +314,80 @@ 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)) return; - ffd_tlv_update_t *req = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_UPDATE, sizeof(ffd_tlv_update_t)); - if (!req) + ffd_tlv_update_t *update = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_UPDATE, sizeof(ffd_tlv_update_t)); + if (!update) return; - req->flags = 0; - req->reserved = 0; - req->interval = htons(FFD_UPDATE_INTERVAL); - req->seqno = 0; - req->metric = 0xffff; /* no need to htons */ - req->type = htons(type); - req->key = htons(key); + 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); send_neigh(neigh, packet); } +ffd_update_t* ffd_send_update_new(ffd_iface_t *iface, ffd_neigh_t *neigh) { + 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; + + 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) { ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); diff --git a/ffd/send.h b/ffd/send.h index ce70199..fbd9062 100644 --- a/ffd/send.h +++ b/ffd/send.h @@ -30,6 +30,9 @@ #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); @@ -37,6 +40,12 @@ void ffd_send_retract(ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uin 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); +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; diff --git a/ffd/update.c b/ffd/update.c index 5ae3006..d273fec 100644 --- a/ffd/update.c +++ b/ffd/update.c @@ -35,18 +35,18 @@ static ffd_queue_t *pending_updates = NULL; -typedef struct _update_arg { +typedef struct _update_arg_t { ffd_node_id_t node; uint16_t type; uint16_t key; ffd_neigh_t *neigh; unsigned ref; -} update_arg; +} update_arg_t; -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)); +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; @@ -61,12 +61,12 @@ static inline update_arg* update_new(const ffd_node_id_t *node, uint16_t type, u return arg; } -static inline update_arg* update_ref(update_arg *arg) { +static inline update_arg_t* update_ref(update_arg_t *arg) { arg->ref++; return arg; } -static inline void update_unref(update_arg *arg) { +static inline void update_unref(update_arg_t *arg) { if (!--arg->ref) { if (arg->neigh) ffd_neigh_unref(arg->neigh); @@ -79,7 +79,7 @@ void ffd_update_enqueue(const ffd_node_id_t *node, uint16_t type, uint16_t key, if (neigh) ffd_neigh_ref(neigh); - update_arg *arg = update_new(node, type, key, neigh); + update_arg_t *arg = update_new(node, type, key, neigh); if (urgent) { ffd_queue_put_delayed(&pending_updates, NULL, &now, FFD_URGENT_DELAY, update_ref(arg)); @@ -99,19 +99,36 @@ int ffd_update_timeout(void) { void ffd_update_run(void) { while (!ffd_update_timeout()) { - update_arg *arg = pending_updates->arg; + ffd_neigh_t *neigh = ((update_arg_t*)pending_updates->arg)->neigh; - ffd_neigh_t *neigh = arg->neigh; - ffd_announce_t *announce = ffd_announce_find(&arg->node, arg->type, arg->key); + ffd_update_t *update = ffd_send_update_new(NULL, neigh); - fprintf(stderr, "debug: sending scheduled update.\n"); + fprintf(stderr, "debug: sending scheduled updates.\n"); - if (announce) - ffd_send_update(NULL, neigh, announce, false); - else - ffd_send_retract(neigh, arg->node, arg->type, arg->key); + ffd_queue_t **entry; + for (entry = &pending_updates; *entry;) { + update_arg_t *arg = (*entry)->arg; - update_unref(arg); - ffd_queue_drop(&pending_updates); + 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); } } From aa15b96d39dd0242c33b7a11c7c02ebdba50f150 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 21 Oct 2012 04:44:20 +0200 Subject: [PATCH 08/10] Add infrastructure for ack handling --- ffd/CMakeLists.txt | 1 + ffd/ack.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++ ffd/ffd.c | 14 ++++++-- ffd/ffd.h | 6 ++++ 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 ffd/ack.c diff --git a/ffd/CMakeLists.txt b/ffd/CMakeLists.txt index 830fef4..2cc8cd4 100644 --- a/ffd/CMakeLists.txt +++ b/ffd/CMakeLists.txt @@ -1,6 +1,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${FFD_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) add_executable(ffd + ack.c announce.c ffd.c neigh.c diff --git a/ffd/ack.c b/ffd/ack.c new file mode 100644 index 0000000..0dbb13c --- /dev/null +++ b/ffd/ack.c @@ -0,0 +1,88 @@ +/* + Copyright (c) 2012, Matthias Schiffer + 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 *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)) { + 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), 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->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); +} diff --git a/ffd/ffd.c b/ffd/ffd.c index 9acd201..6b01cd3 100644 --- a/ffd/ffd.c +++ b/ffd/ffd.c @@ -203,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)); } +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) { if (len < sizeof(ffd_tlv_hello_t)) { fprintf(stderr, "warn: received short hello TLV.\n"); @@ -425,7 +434,7 @@ static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void * return; case TLV_ACK: - /* we don't send ack reqs */ + handle_tlv_ack(data, len, arg); return; case TLV_HELLO: @@ -617,10 +626,11 @@ int main() { while (true) { ffd_queue_run(&tasks); ffd_update_run(); + ffd_ack_run(); struct pollfd fds[1]; - int timeout = 10*timeout_min(ffd_queue_timeout(&tasks), ffd_update_timeout()); + int timeout = 10*timeout_min(timeout_min(ffd_queue_timeout(&tasks), ffd_update_timeout()), ffd_ack_timeout()); if (timeout < 0) timeout = -1; diff --git a/ffd/ffd.h b/ffd/ffd.h index 42d679c..b78f7af 100644 --- a/ffd/ffd.h +++ b/ffd/ffd.h @@ -53,6 +53,7 @@ #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 @@ -207,6 +208,11 @@ ffd_nexthop_t* ffd_announce_nexthop_new(ffd_announce_t *announce, ffd_neigh_t *n 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_ack_handle(uint16_t n); +void ffd_ack_request(void (*cb)(uint16_t nonce, void *arg), unsigned interval, unsigned retries, void *arg); +int ffd_ack_timeout(void); +void ffd_ack_run(void); + 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); From 758611ccd2a8ce105258cf766fc5aa7b0719ae95 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 21 Oct 2012 05:32:43 +0200 Subject: [PATCH 09/10] Use acked updates for seqno request replies --- ffd/ack.c | 5 ++++- ffd/ffd.c | 4 ++-- ffd/ffd.h | 2 +- ffd/send.c | 17 ++++++++++++++++- ffd/send.h | 2 +- ffd/update.c | 38 ++++++++++++++++++++++++++++++++------ 6 files changed, 56 insertions(+), 12 deletions(-) diff --git a/ffd/ack.c b/ffd/ack.c index 0dbb13c..cd21d0f 100644 --- a/ffd/ack.c +++ b/ffd/ack.c @@ -40,6 +40,7 @@ static uint16_t nonce = 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; @@ -56,6 +57,7 @@ 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; } @@ -65,12 +67,13 @@ static void ack_resend(const struct timespec *timeout, void *argp) { ffd_queue_put_delayed(&ack_requests, ack_resend, timeout, arg->interval, arg); } -void ffd_ack_request(void (*cb)(uint16_t nonce, void *arg), unsigned interval, unsigned retries, void *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; diff --git a/ffd/ffd.c b/ffd/ffd.c index 6b01cd3..0504085 100644 --- a/ffd/ffd.c +++ b/ffd/ffd.c @@ -407,14 +407,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) { fprintf(stderr, "debug: received seqno request, seqno already ok\n"); - ffd_update_enqueue(&announce->node, announce->type, announce->key, neigh, false); + ffd_update_enqueue(&announce->node, announce->type, announce->key, neigh, true); return; } if (!announce->selected->neigh) { fprintf(stderr, "debug: received seqno request, incrementing seqno\n"); announce->selected->metric_seqno.seqno++; - ffd_update_enqueue(&announce->node, announce->type, announce->key, neigh, false); + ffd_update_enqueue(&announce->node, announce->type, announce->key, neigh, true); return; } diff --git a/ffd/ffd.h b/ffd/ffd.h index b78f7af..2999be4 100644 --- a/ffd/ffd.h +++ b/ffd/ffd.h @@ -209,7 +209,7 @@ bool ffd_announce_seqno_request(ffd_announce_t *announce, ffd_neigh_t *neigh, ui void ffd_announce_free(ffd_announce_t *announce); void ffd_ack_handle(uint16_t n); -void ffd_ack_request(void (*cb)(uint16_t nonce, void *arg), unsigned interval, unsigned retries, void *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); int ffd_ack_timeout(void); void ffd_ack_run(void); diff --git a/ffd/send.c b/ffd/send.c index dc6544b..2cd57bf 100644 --- a/ffd/send.c +++ b/ffd/send.c @@ -188,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) { ffd_tlv_node_id_t *tlv = ffd_tlv_add(packet, FFD_PACKET_MAX, TLV_NODE_ID, sizeof(ffd_tlv_node_id_t)); if (!tlv) @@ -329,7 +341,7 @@ void ffd_send_retract(ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uin send_neigh(neigh, packet); } -ffd_update_t* ffd_send_update_new(ffd_iface_t *iface, ffd_neigh_t *neigh) { +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; @@ -340,6 +352,9 @@ ffd_update_t* ffd_send_update_new(ffd_iface_t *iface, ffd_neigh_t *neigh) { update->packet->version_magic = htons(FFD_VERSION_MAGIC); update->packet->len = 0; + if (nonce) + add_ack_request(update->packet, *nonce); + return update; } diff --git a/ffd/send.h b/ffd/send.h index fbd9062..50a61e2 100644 --- a/ffd/send.h +++ b/ffd/send.h @@ -40,7 +40,7 @@ void ffd_send_retract(ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uin 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); +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); diff --git a/ffd/update.c b/ffd/update.c index d273fec..77319bd 100644 --- a/ffd/update.c +++ b/ffd/update.c @@ -75,6 +75,27 @@ static inline void update_unref(update_arg_t *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); @@ -82,11 +103,16 @@ void ffd_update_enqueue(const ffd_node_id_t *node, uint16_t type, uint16_t key, update_arg_t *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)); + if (neigh) { + ffd_ack_request(update_request_ack, update_request_ack_free, FFD_ACK_INTERVAL, 10, update_ref(arg)); + } + else { + 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)); @@ -101,7 +127,7 @@ 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); + ffd_update_t *update = ffd_send_update_new(NULL, neigh, NULL); fprintf(stderr, "debug: sending scheduled updates.\n"); From e11b48f3eab5d67ffc45dd1f77a6651a1f91b2ab Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 23 Oct 2012 03:46:02 +0200 Subject: [PATCH 10/10] Simplify urgent update resend setup code --- ffd/update.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ffd/update.c b/ffd/update.c index 77319bd..7ae760a 100644 --- a/ffd/update.c +++ b/ffd/update.c @@ -107,11 +107,9 @@ void ffd_update_enqueue(const ffd_node_id_t *node, uint16_t type, uint16_t key, ffd_ack_request(update_request_ack, update_request_ack_free, FFD_ACK_INTERVAL, 10, update_ref(arg)); } else { - 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)); + int i; + for (i = 1; i <= 5; i++) + ffd_queue_put_delayed(&pending_updates, NULL, &now, i*FFD_URGENT_DELAY, update_ref(arg)); } } else {