diff options
Diffstat (limited to 'ffd/send.c')
-rw-r--r-- | ffd/send.c | 127 |
1 files changed, 118 insertions, 9 deletions
@@ -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); |