summaryrefslogtreecommitdiffstats
path: root/ffd/send.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffd/send.c')
-rw-r--r--ffd/send.c127
1 files changed, 118 insertions, 9 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 <sys/uio.h>
+
+typedef struct _announce_info_t {
+ ffd_node_id_t node;
+ uint16_t type;
+ uint16_t key;
+} announce_info_t;
+
+struct _ffd_update_t {
+ ffd_iface_t *iface;
+ ffd_neigh_t *neigh;
+
+ ffd_packet_t *packet;
+ size_t max_len;
+
+ ffd_node_id_t node;
+
+ unsigned n_updates;
+ announce_info_t announces[];
+};
+
+
static bool send_eth(const eth_addr_t *addr, unsigned ifindex, const void *buf, size_t len) {
static 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);