diff --git a/code/bngblaster/src/bbl_ctrl.c b/code/bngblaster/src/bbl_ctrl.c index c4ec6ffe..3a302feb 100644 --- a/code/bngblaster/src/bbl_ctrl.c +++ b/code/bngblaster/src/bbl_ctrl.c @@ -225,6 +225,7 @@ struct action actions[] = { {"isis-lsp-purge", isis_ctrl_lsp_purge, false}, {"isis-lsp-flap", isis_ctrl_lsp_flap, false}, {"isis-teardown", isis_ctrl_teardown, false}, + {"ospf-database", ospf_ctrl_database, true}, {"bgp-sessions", bgp_ctrl_sessions, true}, {"bgp-disconnect", bgp_ctrl_disconnect, false}, {"bgp-teardown", bgp_ctrl_teardown, true}, diff --git a/code/bngblaster/src/isis/isis_def.h b/code/bngblaster/src/isis/isis_def.h index 07e3da53..d9de72ff 100644 --- a/code/bngblaster/src/isis/isis_def.h +++ b/code/bngblaster/src/isis/isis_def.h @@ -352,7 +352,7 @@ typedef struct isis_lsp_ { isis_instance_s *instance; struct { - isis_lsp_source type; + isis_lsp_source type; isis_adjacency_s *adjacency; } source; diff --git a/code/bngblaster/src/ospf/ospf.c b/code/bngblaster/src/ospf/ospf.c index a583ea99..81197cd9 100644 --- a/code/bngblaster/src/ospf/ospf.c +++ b/code/bngblaster/src/ospf/ospf.c @@ -8,6 +8,9 @@ */ #include "ospf.h" +uint8_t g_pdu_buf[OSPF_GLOBAL_PDU_BUF_LEN] = {0}; +ospf_lsa_key_s g_lsa_key_zero = {0}; + /** * ospf_init * @@ -28,7 +31,10 @@ ospf_init() { g_ctx->ospf_instances = instance; } instance->config = config; - instance->lsdb = hb_tree_new((dict_compare_func)ospf_lsa_id_compare); + + for(uint8_t type=OSPF_LSA_TYPE_1; type < OSPF_LSA_TYPE_MAX; type++) { + instance->lsdb[type] = hb_tree_new((dict_compare_func)ospf_lsa_key_compare); + } if(!ospf_lsa_self_update(instance)) { LOG(OSPF, "Failed to generate self originated LSA for OSPFv%u instance %u\n", diff --git a/code/bngblaster/src/ospf/ospf.h b/code/bngblaster/src/ospf/ospf.h index 9dccaf19..95da0328 100644 --- a/code/bngblaster/src/ospf/ospf.h +++ b/code/bngblaster/src/ospf/ospf.h @@ -21,7 +21,7 @@ #include "ospf_mrt.h" int -ospf_lsa_id_compare(void *id1, void *id2); +ospf_lsa_key_compare(void *id1, void *id2); bool ospf_init(); diff --git a/code/bngblaster/src/ospf/ospf_ctrl.c b/code/bngblaster/src/ospf/ospf_ctrl.c index e2783790..46e02c57 100644 --- a/code/bngblaster/src/ospf/ospf_ctrl.c +++ b/code/bngblaster/src/ospf/ospf_ctrl.c @@ -8,3 +8,107 @@ */ #include "ospf.h" #include "../bbl_ctrl.h" + +#define OSPF_CTRL_ARG_INSTANCE(_arguments, _fd, _instance_id, _instance) \ + do { \ + if(json_unpack(_arguments, "{s:i}", "instance", &_instance_id) != 0) { \ + return bbl_ctrl_status(_fd, "error", 400, "missing OSPF instance"); \ + } \ + /* Search for matching instance */ \ + _instance = g_ctx->ospf_instances; \ + while(_instance) { \ + if(_instance->config->id == _instance_id) { \ + break; \ + } \ + _instance = _instance->next; \ + } \ + if(!_instance) { \ + return bbl_ctrl_status(_fd, "error", 404, "OSPF instance not found"); \ + } \ + } while(0) + +static void +ospf_ctrl_append_database_entries(hb_tree *lsdb, json_t *array, struct timespec *now) +{ + json_t *entry; + ospf_lsa_s *lsa; + hb_itor *itor; + bool next; + + struct timespec ago; + uint16_t age; + + uint32_t lsa_id, lsa_router; + + if(!lsdb) return; + + + itor = hb_itor_new(lsdb); + next = hb_itor_first(itor); + + while(next) { + lsa = *hb_itor_datum(itor); + + if(lsa->deleted) { + /* Ignore deleted LSP. */ + next = hb_itor_next(itor); + continue; + } + timespec_sub(&ago, now, &lsa->timestamp); + age = lsa->age + ago.tv_sec; + if(age >= OSPF_LSA_MAX_AGE) { + age = OSPF_LSA_MAX_AGE; + } + + lsa_id = lsa->key.id; + lsa_router = lsa->key.router; + entry = json_pack("{si ss ss sI si ss ss}", + "type", lsa->type, + "id", format_ipv4_address(&lsa_id), + "router", format_ipv4_address(&lsa_router), + "seq", lsa->seq, + "age", age, + "source-type", ospf_source_string(lsa->source.type), + "source-router-id", format_ipv4_address(&lsa->source.router_id)); + + if(entry) { + json_array_append(array, entry); + } + next = hb_itor_next(itor); + } + hb_itor_free(itor); +} + +int +ospf_ctrl_database(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) +{ + int result = 0; + json_t *root = NULL; + json_t *database = NULL; + ospf_instance_s *instance = NULL; + int instance_id = 0; + uint8_t type; + + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + /* Unpack further arguments */ + OSPF_CTRL_ARG_INSTANCE(arguments, fd, instance_id, instance); + + database = json_array(); + for(type=OSPF_LSA_TYPE_1; type < OSPF_LSA_TYPE_MAX; type++) { + ospf_ctrl_append_database_entries(instance->lsdb[type], database, &now); + } + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "ospf-database", database); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(database); + } + return result; +} \ No newline at end of file diff --git a/code/bngblaster/src/ospf/ospf_ctrl.h b/code/bngblaster/src/ospf/ospf_ctrl.h index c1e447ec..d2c312ae 100644 --- a/code/bngblaster/src/ospf/ospf_ctrl.h +++ b/code/bngblaster/src/ospf/ospf_ctrl.h @@ -9,4 +9,7 @@ #ifndef __BBL_OSPF_CTRL_H__ #define __BBL_OSPF_CTRL_H__ +int +ospf_ctrl_database(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); + #endif \ No newline at end of file diff --git a/code/bngblaster/src/ospf/ospf_def.h b/code/bngblaster/src/ospf/ospf_def.h index 6cee24fb..5bfcac92 100644 --- a/code/bngblaster/src/ospf/ospf_def.h +++ b/code/bngblaster/src/ospf/ospf_def.h @@ -17,7 +17,7 @@ #define OSPF_DEFAULT_ROUTER_PRIORITY 64 #define OSPF_DEFAULT_METRIC 10 -#define OSPF_LSA_TYPES 12 +#define OSPF_LSA_TYPES 11 #define OSPF_LSA_LINK_P2P 1 #define OSPF_LSA_LINK_TRANSIT 2 @@ -42,7 +42,7 @@ #define OSPFV3_LS_ACK_LEN_MIN 16 #define OSPF_TX_BUF_LEN 1500 -#define OSPF_MAX_SELF_LSA_LEN 1024 +#define OSPF_MAX_SELF_LSA_LEN UINT16_MAX #define OSPF_GLOBAL_PDU_BUF_LEN UINT16_MAX @@ -225,7 +225,7 @@ typedef enum ospf_lsa_type_ { OSPF_LSA_TYPE_9 = 9, OSPF_LSA_TYPE_10 = 10, OSPF_LSA_TYPE_11 = 11, - OSPF_LSA_TYPE_MAX, + OSPF_LSA_TYPE_MAX = 12, } ospf_lsa_type; typedef enum ospf_lsa_scope_ { @@ -256,8 +256,7 @@ typedef struct ospf_lsa_link_s { } __attribute__ ((__packed__)) ospf_lsa_link_s; typedef struct ospf_lsa_key_ { - uint8_t type; /* LS Type */ - uint32_t id; /* Link State ID */ + uint32_t id; /* Link State ID */ uint32_t router; /* Advertising Router */ } __attribute__ ((__packed__)) ospf_lsa_key_s; @@ -327,15 +326,25 @@ typedef struct ospf_neighbor_ { uint32_t dd; uint8_t state; + struct { + uint32_t dd; + uint8_t flags; + uint8_t options; + } rx; + + + uint8_t dbd_lsa_type_start; + uint8_t dbd_lsa_type_next; + ospf_lsa_key_s dbd_lsa_start; /* DBD LSA cursor */ ospf_lsa_key_s dbd_lsa_next; /* DBD LSA cursor */ bool dbd_more; /* DBD LSA cursor */ - hb_tree *lsa_update_tree; /* Send LS Update (unicast) */ - hb_tree *lsa_retry_tree; /* Send LS Update (unicast) */ - hb_tree *lsa_request_tree; /* Send LS Request (unicast) */ - hb_tree *lsa_ack_tree; /* Send LS Ack (direct unicast) */ + hb_tree *lsa_update_tree[OSPF_LSA_TYPE_MAX]; /* Send LS Direct Update (unicast) */ + hb_tree *lsa_retry_tree[OSPF_LSA_TYPE_MAX]; /* Send LS Retry Update (unicast) */ + hb_tree *lsa_request_tree[OSPF_LSA_TYPE_MAX]; /* Send LS Request (unicast) */ + hb_tree *lsa_ack_tree[OSPF_LSA_TYPE_MAX]; /* Send LS Ack (direct unicast) */ struct timer_ *timer_dbd_retry; struct timer_ *timer_lsa_retry; @@ -354,16 +363,13 @@ typedef struct ospf_interface_ { uint8_t type; /* OSPF inteface type (P2P, broadcast, ...) */ uint8_t state; - uint16_t max_len; /* max OSPF payload len without fragmentation */ - uint16_t max_fragment_len; /* max OSPF payload len with fragmentation */ - uint16_t metric; uint32_t dr; uint32_t bdr; - hb_tree *lsa_flood_tree; /* Send LS Update (multicast) */ - hb_tree *lsa_ack_tree; /* Send LS Ack (delayed multicast) */ + hb_tree *lsa_flood_tree[OSPF_LSA_TYPE_MAX]; /* Send LS Update (multicast) */ + hb_tree *lsa_ack_tree[OSPF_LSA_TYPE_MAX]; /* Send LS Ack (delayed multicast) */ struct timer_ *timer_lsa_flood; struct timer_ *timer_lsa_ack; @@ -388,12 +394,12 @@ typedef struct ospf_interface_ { typedef struct ospf_instance_ { ospf_config_s *config; bool overload; - bool teardown; + struct timer_ *timer_teardown; struct timer_ *timer_lsa_gc; - hb_tree *lsdb; + hb_tree *lsdb[OSPF_LSA_TYPE_MAX]; ospf_interface_s *interfaces; @@ -427,9 +433,11 @@ typedef struct ospf_pdu_ { } ospf_pdu_s; typedef struct ospf_lsa_ { + /* LSA KEY */ + uint8_t type; + ospf_lsa_key_s key; ospf_instance_s *instance; - ospf_lsa_key_s key; struct { ospf_lsa_source type; uint32_t router_id; @@ -442,17 +450,19 @@ typedef struct ospf_lsa_ { struct timer_ *timer_lifetime; struct timer_ *timer_refresh; - uint32_t seq; /* Sequence Number */ uint32_t refcount; bool expired; bool deleted; + uint32_t seq; /* Sequence Number */ + uint8_t *lsa; uint16_t lsa_len; uint16_t lsa_buf_len; } ospf_lsa_s; typedef struct ospf_lsa_tree_entry_ { + ospf_lsa_key_s key; ospf_lsa_header_s hdr; struct timespec timestamp; ospf_lsa_s *lsa; diff --git a/code/bngblaster/src/ospf/ospf_interface.c b/code/bngblaster/src/ospf/ospf_interface.c index 8dfac05f..acbd742a 100644 --- a/code/bngblaster/src/ospf/ospf_interface.c +++ b/code/bngblaster/src/ospf/ospf_interface.c @@ -233,13 +233,15 @@ ospf_interface_init(bbl_network_interface_s *interface, if(interface_type == OSPF_INTERFACE_P2P || interface_type == OSPF_INTERFACE_VIRTUAL) { - ospf_interface->state = OSPF_IFSTATE_P2P; + ospf_interface_update_state(ospf_interface, OSPF_IFSTATE_P2P); } else { - ospf_interface->state = OSPF_IFSTATE_WAITING; + ospf_interface_update_state(ospf_interface, OSPF_IFSTATE_WAITING); } - ospf_interface->lsa_flood_tree = hb_tree_new((dict_compare_func)ospf_lsa_id_compare); - ospf_interface->lsa_ack_tree = hb_tree_new((dict_compare_func)ospf_lsa_id_compare); + for(uint8_t type=OSPF_LSA_TYPE_1; type < OSPF_LSA_TYPE_MAX; type++) { + ospf_interface->lsa_flood_tree[type] = hb_tree_new((dict_compare_func)ospf_lsa_key_compare); + ospf_interface->lsa_ack_tree[type] = hb_tree_new((dict_compare_func)ospf_lsa_key_compare); + } timer_add_periodic(&g_ctx->timer_root, &ospf_interface->timer_hello, "OSPF HELLO", diff --git a/code/bngblaster/src/ospf/ospf_lsa.c b/code/bngblaster/src/ospf/ospf_lsa.c index 52f8101a..e83077f4 100644 --- a/code/bngblaster/src/ospf/ospf_lsa.c +++ b/code/bngblaster/src/ospf/ospf_lsa.c @@ -8,83 +8,8 @@ */ #include "ospf.h" -uint8_t g_pdu_buf[OSPF_GLOBAL_PDU_BUF_LEN] = {0}; -ospf_lsa_key_s g_lsa_key_zero = {0}; - -int -ospf_lsa_id_compare(void *id1, void *id2) -{ - const uint8_t t1 = *(const uint8_t*)id1; - const uint8_t t2 = *(const uint8_t*)id2; - const uint64_t k1 = *(const uint64_t*)((uint8_t*)id1+1); - const uint64_t k2 = *(const uint64_t*)((uint8_t*)id2+1); - - if(t1 == t2) { - return (k1 > k2) - (k1 < k2); - } else { - return (t1 > t2) - (t1 < t2); - } -} - -void -ospf_lsa_tree_entry_free(ospf_lsa_tree_entry_s *entry) -{ - if(entry) { - if(entry->lsa && entry->lsa->refcount) { - entry->lsa->refcount--; - } - free(entry); - } -} - -void -ospf_lsa_tree_entry_clear(void *key, void *ptr) -{ - UNUSED(key); - ospf_lsa_tree_entry_free(ptr); -} - -ospf_lsa_tree_entry_s * -ospf_lsa_tree_add(ospf_lsa_s *lsa, ospf_lsa_header_s *hdr, hb_tree *tree) -{ - ospf_lsa_tree_entry_s *entry; - dict_insert_result result; - - entry = calloc(1, sizeof(ospf_lsa_tree_entry_s)); - if(entry) { - if (hdr) { - memcpy(&entry->hdr, hdr, sizeof(ospf_lsa_header_s)); - } else if(lsa) { - memcpy(&entry->hdr, lsa->lsa, sizeof(ospf_lsa_header_s)); - } else { - free(entry); - return NULL; - } - result = hb_tree_insert(tree, &entry->hdr); - if(result.inserted) { - if(lsa) { - entry->lsa = lsa; lsa->refcount++; - } - *result.datum_ptr = entry; - } else { - free(entry); - if(result.datum_ptr && *result.datum_ptr) { - entry = *result.datum_ptr; - if(entry) { - if(hdr) { - memcpy(&entry->hdr, hdr, sizeof(ospf_lsa_header_s)); - } - if(!entry->lsa && lsa) { - entry->lsa = lsa; lsa->refcount++; - } - } - } else { - entry = NULL; - } - } - } - return entry; -} +extern uint8_t g_pdu_buf[]; +extern ospf_lsa_key_s g_lsa_key_zero; /** * Determining which LSA is newer as @@ -128,54 +53,124 @@ ospf_lsa_compare(ospf_lsa_header_s *hdr_a, ospf_lsa_header_s *hdr_b) } /** - * ospf_lsa_gc_job + * ospf_lsa_key_compare: * - * OSPF LSDB/LSA garbage collection job. + * libdict tree key compare function + */ +int +ospf_lsa_key_compare(void *id1, void *id2) +{ + const uint64_t a = *(const uint64_t*)id1; + const uint64_t b = *(const uint64_t*)id2; + return (a > b) - (a < b); +} + +/** + * ospf_lsa_tree_entry_free: * - * @param timer time + * Free LSA tree entry memory and update + * corresponding LSA reference count. + */ +static void +ospf_lsa_tree_entry_free(ospf_lsa_tree_entry_s *entry) +{ + ospf_lsa_s *lsa; + if(entry) { + lsa = entry->lsa; + if(lsa) { + assert(lsa->refcount); + if(lsa->refcount) lsa->refcount--; + } + free(entry); + } +} + +/** + * ospf_lsa_tree_entry_clear: + * + * libdict tree clear function */ void -ospf_lsa_gc_job(timer_s *timer) +ospf_lsa_tree_entry_clear(void *key, void *ptr) { - ospf_instance_s *ospf_instance = timer->data; - ospf_lsa_s *lsa; - hb_itor *itor; - bool next; + UNUSED(key); + ospf_lsa_tree_entry_free(ptr); +} - /* Deleting objects from a tree while iterating is unsafe, - * so instead, a list of objects is created during the iteration - * process to mark them for deletion. Once the iteration is complete, - * the objects in the delete list can be safely removed from the tree. */ - ospf_lsa_s *delete_list[OSPF_LSA_GC_DELETE_MAX]; - size_t delete_list_len = 0; +/** + * ospf_lsa_tree_add: + * + * The presence of either the parameter LSA or LSA header + * is obligatory, with at least one of them being required. + * + * @param lsa OSPF LSA + * @param hdr OSPF LSA header + * @param tree target LSA tree + * @return LSA tree entry (ospf_lsa_tree_entry_s) + */ +ospf_lsa_tree_entry_s * +ospf_lsa_tree_add(ospf_lsa_s *lsa, ospf_lsa_header_s *hdr, hb_tree *tree) +{ + ospf_lsa_tree_entry_s *entry; + dict_insert_result result; - dict_remove_result removed; + assert(tree && (lsa || hdr)); - if(!ospf_instance->lsdb) return; - - itor = hb_itor_new(ospf_instance->lsdb); - next = hb_itor_first(itor); - while(next) { - lsa = *hb_itor_datum(itor); - next = hb_itor_next(itor); - if(lsa && lsa->deleted && lsa->refcount == 0) { - timer_del(lsa->timer_lifetime); - timer_del(lsa->timer_refresh); - delete_list[delete_list_len++] = lsa; - if(delete_list_len == OSPF_LSA_GC_DELETE_MAX) { - next = NULL; + entry = calloc(1, sizeof(ospf_lsa_tree_entry_s)); + if(entry) { + if(hdr) { + memcpy(&entry->hdr, hdr, sizeof(ospf_lsa_header_s)); + } else if(lsa) { + memcpy(&entry->hdr, lsa->lsa, sizeof(ospf_lsa_header_s)); + } + entry->key.id = entry->hdr.id; + entry->key.router = entry->hdr.router; + result = hb_tree_insert(tree, &entry->key); + if(result.inserted) { + if(lsa) { + entry->lsa = lsa; + lsa->refcount++; + } + *result.datum_ptr = entry; + } else { + free(entry); + if(result.datum_ptr && *result.datum_ptr) { + entry = *result.datum_ptr; + if(entry) { + if(hdr && ospf_lsa_compare(&entry->hdr, hdr) == -1) { + memcpy(&entry->hdr, hdr, sizeof(ospf_lsa_header_s)); + } + if(!entry->lsa && lsa) { + entry->lsa = lsa; lsa->refcount++; + } + } + } else { + entry = NULL; } } } - hb_itor_free(itor); + return entry; +} - /* Finally delete from LSDB! */ - for(size_t i=0; i < delete_list_len; i++) { - removed = hb_tree_remove(ospf_instance->lsdb, &delete_list[i]->key); - if(removed.removed) { - free(removed.datum); - } +/** + * ospf_lsa_tree_remove: + * + * Remove LSA from tree. + * + * @param lsa OSPF LSA key + * @param tree target LSA tree + * @return true if entry was removed from tree + */ +static bool +ospf_lsa_tree_remove(ospf_lsa_key_s *key, hb_tree *tree) +{ + dict_remove_result removed; + removed = hb_tree_remove(tree, key); + if(removed.removed) { + ospf_lsa_tree_entry_free(removed.datum); + return true; } + return false; } /** @@ -190,13 +185,66 @@ ospf_lsa_gc_job(timer_s *timer) static bool ospf_lsa_retry_stop(ospf_lsa_s *lsa, ospf_neighbor_s *neighbor) { - dict_remove_result removed; - removed = hb_tree_remove(neighbor->lsa_retry_tree, &lsa->key); - if(removed.removed) { - ospf_lsa_tree_entry_free(removed.datum); - return true; + return ospf_lsa_tree_remove(&lsa->key, neighbor->lsa_retry_tree[lsa->type]); +} + +/** + * ospf_lsa_gc_job + * + * OSPF LSDB/LSA garbage collection job. + * + * @param timer time + */ +void +ospf_lsa_gc_job(timer_s *timer) +{ + ospf_instance_s *ospf_instance = timer->data; + ospf_lsa_s *lsa; + hb_itor *itor; + bool next; + uint8_t type; + + /* Deleting objects from a tree while iterating is unsafe, + * so instead, a list of objects is created during the iteration + * process to mark them for deletion. Once the iteration is complete, + * the objects in the delete list can be safely removed from the tree. */ + ospf_lsa_s *delete_list[OSPF_LSA_GC_DELETE_MAX]; + size_t delete_list_len; + size_t i; + + dict_remove_result removed; + + for(type=OSPF_LSA_TYPE_1; type < OSPF_LSA_TYPE_MAX; type++) { + delete_list_len = 0; + itor = hb_itor_new(ospf_instance->lsdb[type]); + next = hb_itor_first(itor); + while(next) { + lsa = *hb_itor_datum(itor); + next = hb_itor_next(itor); + if(lsa && lsa->deleted && lsa->refcount == 0) { + delete_list[delete_list_len++] = lsa; + if(delete_list_len == OSPF_LSA_GC_DELETE_MAX) { + next = NULL; + } + } + } + hb_itor_free(itor); + + /* Finally delete from LSDB! */ + for(i=0; i < delete_list_len; i++) { + removed = hb_tree_remove(ospf_instance->lsdb[type], &delete_list[i]->key); + if(removed.removed) { + lsa = removed.datum; + timer_del(lsa->timer_lifetime); + timer_del(lsa->timer_refresh); + if(lsa->lsa) { + free(lsa->lsa); + } + free(lsa); + } + } } - return false; + } /** @@ -213,41 +261,37 @@ void ospf_lsa_flood(ospf_lsa_s *lsa) { - ospf_interface_s *interface; - ospf_neighbor_s *neighbor; + ospf_interface_s *ospf_interface; + ospf_neighbor_s *ospf_neighbor; ospf_lsa_tree_entry_s *entry; + bool flood_interface; + struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - assert(lsa); - assert(lsa->lsa); - assert(lsa->lsa_len >= sizeof(ospf_lsa_header_s)); - assert(lsa->lsa_buf_len >= lsa->lsa_len); - - interface = lsa->instance->interfaces; - while(interface) { - /* Add to interface flood tree. */ - ospf_lsa_tree_add(lsa, NULL, interface->lsa_flood_tree); - + ospf_interface = lsa->instance->interfaces; + while(ospf_interface) { + flood_interface = false; /* Add to neighbors retry list. */ - neighbor = interface->neighbors; - while(neighbor) { - if(neighbor->state < OSPF_NBSTATE_EXCHANGE) { - goto NEXT; + ospf_neighbor = ospf_interface->neighbors; + while(ospf_neighbor) { + if(ospf_neighbor->state >= OSPF_NBSTATE_EXCHANGE && lsa->source.router_id != ospf_neighbor->router_id) { + flood_interface = true; + entry = ospf_lsa_tree_add(lsa, NULL, ospf_neighbor->lsa_retry_tree[lsa->type]); + if(entry) { + entry->timestamp.tv_sec = now.tv_sec; + entry->timestamp.tv_nsec = now.tv_nsec; + } } - if(lsa->source.router_id == neighbor->router_id) { - /* Do not flood over the neighbor from where LSA was received. */ - goto NEXT; - } - entry = ospf_lsa_tree_add(lsa, NULL, neighbor->lsa_retry_tree); - if(entry) { - entry->timestamp.tv_sec = now.tv_sec; - entry->timestamp.tv_nsec = now.tv_nsec; - } -NEXT: - neighbor = neighbor->next; + ospf_neighbor = ospf_neighbor->next; } + + /* Add to interface flood tree if placed on at least one neighbors retry list. */ + if(flood_interface) { + ospf_lsa_tree_add(lsa, NULL, ospf_interface->lsa_flood_tree[lsa->type]); + } + ospf_interface = ospf_interface->next; } } @@ -316,11 +360,12 @@ ospf_lsa_refresh_job(timer_s *timer) } static ospf_lsa_s * -ospf_lsa_new(ospf_lsa_key_s *key, ospf_instance_s *ospf_instance) +ospf_lsa_new(uint8_t type, ospf_lsa_key_s *key, ospf_instance_s *ospf_instance) { ospf_lsa_s *lsa = calloc(1, sizeof(ospf_lsa_s)); - lsa->instance = ospf_instance; memcpy(&lsa->key, key, sizeof(ospf_lsa_key_s)); + lsa->type = type; + lsa->instance = ospf_instance; return lsa; } @@ -345,27 +390,25 @@ ospf_lsa_purge(ospf_lsa_s *lsa) * @param instance OSPF instance */ void -ospf_lsa_purge_all_external(ospf_instance_s *instance) +ospf_lsa_purge_all_external(ospf_instance_s *ospf_instance) { - hb_tree *lsdb = instance->lsdb; - ospf_lsa_s *lsa; hb_itor *itor; bool next; + uint8_t type; - if(!lsdb) { - return; - } - - itor = hb_itor_new(lsdb); - next = hb_itor_first(itor); - - while(next) { - lsa = *hb_itor_datum(itor); - if(lsa && lsa->source.type == OSPF_SOURCE_EXTERNAL) { - ospf_lsa_purge(lsa); + for(type=OSPF_LSA_TYPE_1; type < OSPF_LSA_TYPE_MAX; type++) { + if(!ospf_instance->lsdb[type]) continue; + itor = hb_itor_new(ospf_instance->lsdb[type]); + next = hb_itor_first(itor); + while(next) { + lsa = *hb_itor_datum(itor); + if(lsa && lsa->source.type == OSPF_SOURCE_EXTERNAL) { + ospf_lsa_purge(lsa); + } + next = hb_itor_next(itor); } - next = hb_itor_next(itor); + hb_itor_free(itor); } } @@ -431,7 +474,7 @@ ospf_lsa_self_update(ospf_instance_s *ospf_instance) void **search = NULL; dict_insert_result result; - uint8_t options = 0; + uint8_t options = OSPF_OPTION_E_BIT; uint16_t *links; ospf_lsa_s *lsa; @@ -441,34 +484,33 @@ ospf_lsa_self_update(ospf_instance_s *ospf_instance) ospf_external_connection_s *external_connection = NULL; ospf_lsa_key_s key = { - .type = OSPF_LSA_TYPE_1, .id = config->router_id, .router = config->router_id }; - search = hb_tree_search(ospf_instance->lsdb, &key); + search = hb_tree_search(ospf_instance->lsdb[OSPF_LSA_TYPE_1], &key); if(search) { /* Update existing LSA. */ lsa = *search; } else { /* Create new LSA. */ - lsa = ospf_lsa_new(&key, ospf_instance); - result = hb_tree_insert(ospf_instance->lsdb, &key); + lsa = ospf_lsa_new(OSPF_LSA_TYPE_1, &key, ospf_instance); + result = hb_tree_insert(ospf_instance->lsdb[OSPF_LSA_TYPE_1], &lsa->key); + assert(result.inserted); if(result.inserted) { *result.datum_ptr = lsa; } else { - LOG_NOARG(OSPF, "Failed to add LSA to LSDB\n"); - return NULL; + LOG_NOARG(OSPF, "Failed to add self generated OSPF LSA to LSDB\n"); + return false; } } if(lsa->lsa_buf_len < OSPF_MAX_SELF_LSA_LEN) { if(lsa->lsa) free(lsa->lsa); lsa->lsa = malloc(OSPF_MAX_SELF_LSA_LEN); - lsa->lsa_len = 0; lsa->lsa_buf_len = OSPF_MAX_SELF_LSA_LEN; } - + lsa->lsa_len = OSPF_LSA_HDR_LEN; lsa->source.type = OSPF_SOURCE_SELF; lsa->seq++; lsa->instance = ospf_instance; @@ -478,12 +520,11 @@ ospf_lsa_self_update(ospf_instance_s *ospf_instance) hdr->age = htobe16(lsa->age); hdr->options = options; hdr->type = OSPF_LSA_TYPE_1; - hdr->id = config->router_id; - hdr->router = config->router_id; + hdr->id = key.id; + hdr->router = key.router; hdr->seq = htobe32(lsa->seq); hdr->checksum = 0; hdr->length = 0; - lsa->lsa_len = OSPF_LSA_HDR_LEN; *(lsa->lsa+lsa->lsa_len++) = OSPF_LSA_BORDER_ROUTER|OSPF_LSA_EXTERNAL_ROUTER; *(lsa->lsa+lsa->lsa_len++) = 0; @@ -533,6 +574,8 @@ ospf_lsa_update_tx(ospf_interface_s *ospf_interface, bool retry) { ospf_instance_s *ospf_instance = ospf_interface->instance; + ospf_config_s *config = ospf_instance->config; + bbl_network_interface_s *interface = ospf_interface->interface; ospf_lsa_tree_entry_s *entry; @@ -543,8 +586,7 @@ ospf_lsa_update_tx(ospf_interface_s *ospf_interface, void **search = NULL; uint16_t l3_hdr_len; uint16_t lsa_count = 0; - uint16_t lsa_retry_interval; - + uint8_t type; struct timespec now; struct timespec ago; clock_gettime(CLOCK_MONOTONIC, &now); @@ -558,8 +600,8 @@ ospf_lsa_update_tx(ospf_interface_s *ospf_interface, ospf_pdu_add_u8(&pdu, ospf_interface->version); ospf_pdu_add_u8(&pdu, pdu.pdu_type); ospf_pdu_add_u16(&pdu, 0); /* skip length */ - ospf_pdu_add_u32(&pdu, ospf_instance->config->router_id); /* Router ID */ - ospf_pdu_add_u32(&pdu, ospf_instance->config->area); /* Area ID */ + ospf_pdu_add_u32(&pdu, config->router_id); /* Router ID */ + ospf_pdu_add_u32(&pdu, config->area); /* Area ID */ ospf_pdu_add_u16(&pdu, 0); /* skip checksum */ if(ospf_interface->version == OSPF_VERSION_2) { l3_hdr_len = 20; @@ -572,55 +614,54 @@ ospf_lsa_update_tx(ospf_interface_s *ospf_interface, } ospf_pdu_add_u32(&pdu, 0); /* skip lsa_count */ - if(ospf_neighbor && retry) { - /* Retry. */ - lsa_retry_interval = ospf_instance->config->lsa_retry_interval; - - tree = ospf_neighbor->lsa_retry_tree; - itor = hb_itor_new(tree); - next = hb_itor_first(itor); - while(next) { - entry = *hb_itor_datum(itor); - next = hb_itor_next(itor); - timespec_sub(&ago, &now, &entry->timestamp); - if(ago.tv_sec < lsa_retry_interval) { - continue; - } - lsa = entry->lsa; - if(lsa && lsa->lsa_len >= OSPF_LSA_HDR_LEN) { - if(lsa_count > 0 && (l3_hdr_len + pdu.pdu_len + lsa->lsa_len) > interface->mtu) { - next = NULL; + for(type=OSPF_LSA_TYPE_1; type < OSPF_LSA_TYPE_MAX; type++) { + if(ospf_neighbor && retry) { + /* Retry. */ + tree = ospf_neighbor->lsa_retry_tree[type]; + itor = hb_itor_new(tree); + next = hb_itor_first(itor); + while(next) { + entry = *hb_itor_datum(itor); + next = hb_itor_next(itor); + timespec_sub(&ago, &now, &entry->timestamp); + if(ago.tv_sec < config->lsa_retry_interval) { + continue; + } + lsa = entry->lsa; + if(lsa && lsa->lsa_len >= OSPF_LSA_HDR_LEN) { + if(lsa_count > 0 && (l3_hdr_len + pdu.pdu_len + lsa->lsa_len) > interface->mtu) { + break; + } + ospf_lsa_update_age(entry->lsa, &now); + ospf_pdu_add_bytes(&pdu, lsa->lsa, lsa->lsa_len); + entry->timestamp.tv_sec = now.tv_sec; + entry->timestamp.tv_nsec = now.tv_nsec; + lsa_count++; } - ospf_lsa_update_age(entry->lsa, &now); - ospf_pdu_add_bytes(&pdu, lsa->lsa, lsa->lsa_len); - entry->timestamp.tv_sec = now.tv_sec; - entry->timestamp.tv_nsec = now.tv_nsec; - lsa_count++; } - } - hb_itor_free(itor); - } else { - /* Flooding and direct updates. */ - if(ospf_neighbor) { - tree = ospf_neighbor->lsa_update_tree; + hb_itor_free(itor); } else { - tree = ospf_interface->lsa_flood_tree; - } - search = hb_tree_search_gt(tree, &g_lsa_key_zero); - while(search) { - entry = *search; - lsa = entry->lsa; - if(lsa && lsa->lsa_len >= OSPF_LSA_HDR_LEN) { - if(lsa_count > 0 && (l3_hdr_len + pdu.pdu_len + lsa->lsa_len) > interface->mtu) { - break; - } - ospf_lsa_update_age(entry->lsa, &now); - ospf_pdu_add_bytes(&pdu, lsa->lsa, lsa->lsa_len); - lsa_count++; + /* Flooding and direct updates. */ + if(ospf_neighbor) { + tree = ospf_neighbor->lsa_update_tree[type]; + } else { + tree = ospf_interface->lsa_flood_tree[type]; } - hb_tree_remove(tree, &lsa->key); - ospf_lsa_tree_entry_free(entry); search = hb_tree_search_gt(tree, &g_lsa_key_zero); + while(search) { + entry = *search; + lsa = entry->lsa; + if(lsa && lsa->lsa_len >= OSPF_LSA_HDR_LEN) { + if(lsa_count > 0 && (l3_hdr_len + pdu.pdu_len + lsa->lsa_len) > interface->mtu) { + break; + } + ospf_lsa_update_age(entry->lsa, &now); + ospf_pdu_add_bytes(&pdu, lsa->lsa, lsa->lsa_len); + lsa_count++; + } + ospf_lsa_tree_remove((ospf_lsa_key_s*)&entry->key, tree); + search = hb_tree_search_gt(tree, &g_lsa_key_zero); + } } } if(lsa_count == 0) { @@ -654,7 +695,9 @@ ospf_lsa_req_tx(ospf_interface_s *ospf_interface, ospf_neighbor_s *ospf_neighbor ospf_lsa_tree_entry_s *entry; hb_tree *tree; - void **search = NULL; + hb_itor *itor; + bool next; + uint8_t type; uint16_t l3_hdr_len; uint16_t lsa_count = 0; @@ -682,16 +725,22 @@ ospf_lsa_req_tx(ospf_interface_s *ospf_interface, ospf_neighbor_s *ospf_neighbor l3_hdr_len = 40; ospf_pdu_add_u32(&pdu, 0); } - tree = ospf_neighbor->lsa_request_tree; - search = hb_tree_search_gt(tree, &g_lsa_key_zero); - while(search) { - entry = *search; - ospf_pdu_add_bytes(&pdu, (uint8_t*)&entry->hdr, OSPF_LSA_HDR_LEN); - lsa_count++; - if((l3_hdr_len + pdu.pdu_len + OSPF_LSA_HDR_LEN) > interface->mtu) { - break; + for(type=OSPF_LSA_TYPE_1; type < OSPF_LSA_TYPE_MAX; type++) { + tree = ospf_neighbor->lsa_request_tree[type]; + itor = hb_itor_new(tree); + next = hb_itor_first(itor); + while(next) { + entry = *hb_itor_datum(itor); + next = hb_itor_next(itor); + if(lsa_count > 0 && (l3_hdr_len + pdu.pdu_len + OSPF_LSA_HDR_LEN) > interface->mtu) { + break; + } + ospf_pdu_add_u32(&pdu, entry->hdr.type); + ospf_pdu_add_ipv4(&pdu, entry->hdr.id); + ospf_pdu_add_ipv4(&pdu, entry->hdr.router); + lsa_count++; } - search = hb_tree_search_gt(tree, &g_lsa_key_zero); + hb_itor_free(itor); } if(lsa_count == 0) { return EMPTY; @@ -720,6 +769,7 @@ ospf_lsa_ack_tx(ospf_interface_s *ospf_interface, ospf_neighbor_s *ospf_neighbor ospf_lsa_s *lsa; hb_tree *tree; void **search = NULL; + uint8_t type; uint16_t l3_hdr_len; uint16_t lsa_count = 0; @@ -747,30 +797,32 @@ ospf_lsa_ack_tx(ospf_interface_s *ospf_interface, ospf_neighbor_s *ospf_neighbor l3_hdr_len = 40; ospf_pdu_add_u16(&pdu, 0); } - if(ospf_neighbor) { - /* Direct LS ack */ - tree = ospf_neighbor->lsa_ack_tree; - } else { - /* Delayed LS ack */ - tree = ospf_interface->lsa_ack_tree; - } - search = hb_tree_search_gt(tree, &g_lsa_key_zero); - while(search) { - entry = *search; - lsa = entry->lsa; - if(lsa && lsa->lsa_len >= OSPF_LSA_HDR_LEN) { - ospf_lsa_update_age(entry->lsa, &now); - ospf_pdu_add_bytes(&pdu, lsa->lsa, OSPF_LSA_HDR_LEN); + + for(type=OSPF_LSA_TYPE_1; type < OSPF_LSA_TYPE_MAX; type++) { + if(ospf_neighbor) { + /* Direct LS ack */ + tree = ospf_neighbor->lsa_ack_tree[type]; } else { - ospf_pdu_add_bytes(&pdu, (uint8_t*)&entry->hdr, OSPF_LSA_HDR_LEN); - } - lsa_count++; - hb_tree_remove(tree, &entry->hdr.type); - ospf_lsa_tree_entry_free(entry); - if((l3_hdr_len + pdu.pdu_len + OSPF_LSA_HDR_LEN) > interface->mtu) { - break; + /* Delayed LS ack */ + tree = ospf_interface->lsa_ack_tree[type]; } search = hb_tree_search_gt(tree, &g_lsa_key_zero); + while(search) { + entry = *search; + lsa = entry->lsa; + if(lsa && lsa->lsa_len >= OSPF_LSA_HDR_LEN) { + ospf_lsa_update_age(lsa, &now); + ospf_pdu_add_bytes(&pdu, lsa->lsa, OSPF_LSA_HDR_LEN); + } else { + ospf_pdu_add_bytes(&pdu, (uint8_t*)&entry->hdr, OSPF_LSA_HDR_LEN); + } + lsa_count++; + ospf_lsa_tree_remove((ospf_lsa_key_s*)&entry->key, tree); + if((l3_hdr_len + pdu.pdu_len + OSPF_LSA_HDR_LEN) > interface->mtu) { + break; + } + search = hb_tree_search_gt(tree, &g_lsa_key_zero); + } } if(lsa_count == 0) { return EMPTY; @@ -808,12 +860,12 @@ ospf_lsa_update_handler_rx(ospf_interface_s *ospf_interface, ospf_lsa_key_s *key; ospf_lsa_s *lsa; - dict_remove_result removed; void **search = NULL; uint32_t lsa_count; uint16_t lsa_len; + int lsa_compare; struct timespec now; ospf_interface->stats.ls_upd_rx++; @@ -846,64 +898,71 @@ ospf_lsa_update_handler_rx(ospf_interface_s *ospf_interface, clock_gettime(CLOCK_MONOTONIC, &now); while(OSPF_PDU_CURSOR_LEN(pdu) >= OSPF_LSA_HDR_LEN && lsa_count) { hdr = (ospf_lsa_header_s*)OSPF_PDU_CURSOR(pdu); - key = (ospf_lsa_key_s*)&hdr->type; - lsa_len = be16toh(hdr->length); - if(lsa->lsa_len > OSPF_PDU_CURSOR_LEN(pdu)) { - ospf_rx_error(interface, pdu, "decode"); + key = (ospf_lsa_key_s*)&hdr->id; + + if(hdr->type < OSPF_LSA_TYPE_1 || hdr->type > OSPF_LSA_TYPE_11) { + ospf_rx_error(interface, pdu, "decode (invalid LSA type)"); return; } + lsa_len = be16toh(hdr->length); + if(lsa_len > OSPF_PDU_CURSOR_LEN(pdu)) { + ospf_rx_error(interface, pdu, "decode (invalid LSA len)"); + return; + } + OSPF_PDU_CURSOR_INC(pdu, lsa_len); lsa_count--; - search = hb_tree_search(ospf_neighbor->lsa_request_tree, key); + search = hb_tree_search(ospf_neighbor->lsa_request_tree[hdr->type], key); if(search) { entry = *search; if(ospf_lsa_compare((ospf_lsa_header_s*)&entry->hdr, hdr) != 1) { - removed = hb_tree_remove(ospf_neighbor->lsa_request_tree, &lsa->key); - if(removed.removed) { - ospf_lsa_tree_entry_free(removed.datum); - } + ospf_lsa_tree_remove(&entry->key, ospf_neighbor->lsa_request_tree[hdr->type]); } } - search = hb_tree_search(ospf_instance->lsdb, key); + search = hb_tree_search(ospf_instance->lsdb[hdr->type], key); if(search) { lsa = *search; ospf_lsa_update_age(lsa, &now); - switch(ospf_lsa_compare((ospf_lsa_header_s*)lsa->lsa, hdr)) { - case 1: /* LOCAL IS NEWER */ - if(!(lsa->seq == OSPF_LSA_SEQ_MAX && lsa->age >= OSPF_LSA_MAX_AGE)) { - /* Send direct LSA update. */ - ospf_lsa_tree_add(lsa, NULL, ospf_neighbor->lsa_update_tree); + lsa_compare = ospf_lsa_compare((ospf_lsa_header_s*)lsa->lsa, hdr); + if(lsa_compare == 1) { + /* LOCAL LSA IS NEWER */ + if(!(lsa->seq == OSPF_LSA_SEQ_MAX && lsa->age >= OSPF_LSA_MAX_AGE)) { + /* Send direct LSA update. */ + ospf_lsa_tree_add(lsa, NULL, ospf_neighbor->lsa_update_tree[lsa->type]); + } + /* Next LSA from update ... */ + continue; + } else if(lsa_compare == 0) { + /* EQUAL */ + if(ospf_lsa_retry_stop(lsa, ospf_neighbor)) { + /* Implied acknowledgment (see RFC2328 section 13, step 7a). */ + if(ospf_interface->state == OSPF_IFSTATE_BACKUP && + ospf_interface->dr == pdu->router_id) { + /* Send delayed LSA ack. */ + ospf_lsa_tree_add(lsa, NULL, ospf_interface->lsa_ack_tree[lsa->type]); } - continue; - case 0: /* EQUAL */ - if(ospf_lsa_retry_stop(lsa, ospf_neighbor)) { - /* Implied acknowledgment (see RFC2328 section 13, step 7a). */ - if(ospf_interface->state == OSPF_IFSTATE_BACKUP && - ospf_interface->dr == pdu->router_id) { - /* Send delayed LSA ack. */ - ospf_lsa_tree_add(lsa, NULL, ospf_interface->lsa_ack_tree); - } - } else { - /* Send direct LSA ack. */ - ospf_lsa_tree_add(lsa, NULL, ospf_neighbor->lsa_ack_tree); - } - continue; - case -1: /* RECEIVED IS NEWER */ - break; - } + } else { + /* Send direct LSA ack. */ + ospf_lsa_tree_add(lsa, NULL, ospf_neighbor->lsa_ack_tree[lsa->type]); + } + /* Next LSA from update ... */ + continue; + } + /* RECEIVED LSA IS NEWER ... */ } else { - lsa = ospf_lsa_new(key, ospf_instance); + /* NEW LSA */ + lsa = ospf_lsa_new(hdr->type, key, ospf_instance); } - + if(lsa->lsa_buf_len < lsa_len) { if(lsa->lsa) free(lsa->lsa); lsa->lsa = malloc(lsa_len); + lsa->lsa_buf_len = lsa_len; } memcpy(lsa->lsa, hdr, lsa_len); lsa->lsa_len = lsa_len; - lsa->source.type = OSPF_SOURCE_ADJACENCY; lsa->source.router_id = ospf_neighbor->router_id; lsa->seq = be32toh(hdr->seq); @@ -912,13 +971,12 @@ ospf_lsa_update_handler_rx(ospf_interface_s *ospf_interface, lsa->timestamp.tv_nsec = now.tv_sec; ospf_lsa_update_age(lsa, &now); ospf_lsa_flood(lsa); + ospf_lsa_tree_add(lsa, NULL, ospf_interface->lsa_ack_tree[lsa->type]); } - if(hb_tree_count(ospf_neighbor->lsa_ack_tree) > 0) { - ospf_lsa_ack_tx(ospf_interface, ospf_neighbor); - } - if(hb_tree_count(ospf_neighbor->lsa_update_tree) > 0) { - ospf_lsa_update_tx(ospf_interface, ospf_neighbor, false); - } + /* Send direct LSA ack. */ + ospf_lsa_ack_tx(ospf_interface, ospf_neighbor); + /* Send direct LSA update. */ + ospf_lsa_update_tx(ospf_interface, ospf_neighbor, false); } /** @@ -939,6 +997,7 @@ ospf_lsa_req_handler_rx(ospf_interface_s *ospf_interface, ospf_lsa_key_s *key; ospf_lsa_s *lsa; + uint32_t lsa_type; void **search = NULL; ospf_interface->stats.ls_req_rx++; @@ -971,24 +1030,35 @@ ospf_lsa_req_handler_rx(ospf_interface_s *ospf_interface, if(OSPF_PDU_CURSOR_LEN(pdu) < OSPFV2_LSA_REQ_HDR_LEN) { break; } - OSPF_PDU_CURSOR_INC(pdu, 3); + lsa_type = be32toh(*(uint32_t*)OSPF_PDU_CURSOR(pdu)); + OSPF_PDU_CURSOR_INC(pdu, 4); } else { if(OSPF_PDU_CURSOR_LEN(pdu) < OSPFV3_LSA_REQ_HDR_LEN) { break; } - OSPF_PDU_CURSOR_INC(pdu, 1); + lsa_type = be16toh(*(uint16_t*)OSPF_PDU_CURSOR(pdu)); + OSPF_PDU_CURSOR_INC(pdu, 2); } + if(lsa_type < OSPF_LSA_TYPE_1 || lsa_type > OSPF_LSA_TYPE_11) { + ospf_rx_error(interface, pdu, "decode (invalid LSA type)"); + break; + } + key = (ospf_lsa_key_s*)OSPF_PDU_CURSOR(pdu); OSPF_PDU_CURSOR_INC(pdu, sizeof(ospf_lsa_key_s)); - search = hb_tree_search(ospf_instance->lsdb, key); + search = hb_tree_search(ospf_instance->lsdb[lsa_type], key); if(search) { lsa = *search; if(!(lsa->seq == OSPF_LSA_SEQ_MAX && lsa->age >= OSPF_LSA_MAX_AGE)) { /* Send direct LSA update. */ - ospf_lsa_tree_add(lsa, NULL, ospf_neighbor->lsa_update_tree); + ospf_lsa_tree_add(lsa, NULL, ospf_neighbor->lsa_update_tree[lsa_type]); } - } + } else { + /* See RFC2328 BadLSReq */ + ospf_rx_error(interface, pdu, "BadLSReq"); + ospf_neigbor_state(ospf_neighbor, OSPF_NBSTATE_EXSTART); + } } } @@ -1047,7 +1117,13 @@ ospf_lsa_ack_handler_rx(ospf_interface_s *ospf_interface, hdr_a = (ospf_lsa_header_s*)OSPF_PDU_CURSOR(pdu); key = (ospf_lsa_key_s*)&hdr_a->type; OSPF_PDU_CURSOR_INC(pdu, OSPF_LSA_HDR_LEN); - search = hb_tree_search(ospf_neighbor->lsa_retry_tree, key); + + if(hdr_a->type < OSPF_LSA_TYPE_1 || hdr_a->type > OSPF_LSA_TYPE_11) { + ospf_rx_error(interface, pdu, "invalid LSA type"); + return; + } + + search = hb_tree_search(ospf_neighbor->lsa_retry_tree[hdr_a->type], key); if(search) { entry = *search; if(entry->lsa) { @@ -1058,8 +1134,7 @@ ospf_lsa_ack_handler_rx(ospf_interface_s *ospf_interface, hdr_b = &entry->hdr; } if(ospf_lsa_compare(hdr_a, hdr_b) != -1) { - hb_tree_remove(ospf_neighbor->lsa_retry_tree, key); - ospf_lsa_tree_entry_free(entry); + ospf_lsa_tree_remove(key, ospf_neighbor->lsa_retry_tree[hdr_a->type]); } } } diff --git a/code/bngblaster/src/ospf/ospf_lsa.h b/code/bngblaster/src/ospf/ospf_lsa.h index 95665d6c..4957efac 100644 --- a/code/bngblaster/src/ospf/ospf_lsa.h +++ b/code/bngblaster/src/ospf/ospf_lsa.h @@ -10,10 +10,7 @@ #define __BBL_OSPF_LSA_H__ int -ospf_lsa_id_compare(void *id1, void *id2); - -void -ospf_lsa_tree_entry_free(ospf_lsa_tree_entry_s *entry); +ospf_lsa_key_compare(void *id1, void *id2); void ospf_lsa_tree_entry_clear(void *key, void *ptr); diff --git a/code/bngblaster/src/ospf/ospf_neighbor.c b/code/bngblaster/src/ospf/ospf_neighbor.c index 9a4e146c..386f4052 100644 --- a/code/bngblaster/src/ospf/ospf_neighbor.c +++ b/code/bngblaster/src/ospf/ospf_neighbor.c @@ -8,6 +8,9 @@ */ #include "ospf.h" +extern uint8_t g_pdu_buf[]; +extern ospf_lsa_key_s g_lsa_key_zero; + protocol_error_t ospf_neighbor_dbd_tx(ospf_neighbor_s *ospf_neighbor); @@ -33,21 +36,21 @@ ospf_neighbor_dbd_tx(ospf_neighbor_s *ospf_neighbor) bbl_network_interface_s *interface = ospf_interface->interface; ospf_lsa_s *lsa; - ospf_pdu_s pdu = {0}; - uint8_t pdu_buf[OSPF_TX_BUF_LEN]; - - uint8_t options = OSPF_DBD_OPTION_E|OSPF_DBD_OPTION_L|OSPF_DBD_OPTION_O; - uint8_t flags = 0; - hb_itor *itor; bool next; + uint16_t l3_hdr_len; + uint8_t options = OSPF_DBD_OPTION_E|OSPF_DBD_OPTION_L|OSPF_DBD_OPTION_O; + uint8_t flags = 0; + uint8_t type = 0; + struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); + ospf_pdu_s pdu; ospf_pdu_init(&pdu, OSPF_PDU_DB_DESC, ospf_neighbor->version); - pdu.pdu = pdu_buf; - pdu.pdu_buf_len = OSPF_TX_BUF_LEN; + pdu.pdu = g_pdu_buf; + pdu.pdu_buf_len = OSPF_GLOBAL_PDU_BUF_LEN; /* OSPF header */ ospf_pdu_add_u8(&pdu, ospf_neighbor->version); @@ -57,10 +60,12 @@ ospf_neighbor_dbd_tx(ospf_neighbor_s *ospf_neighbor) ospf_pdu_add_u32(&pdu, ospf_instance->config->area); /* Area ID */ ospf_pdu_add_u16(&pdu, 0); /* skip checksum */ if(ospf_neighbor->version == OSPF_VERSION_2) { + l3_hdr_len = 20; /* Authentication */ ospf_pdu_add_u16(&pdu, OSPF_AUTH_NONE); ospf_pdu_zero_bytes(&pdu, OSPFV2_AUTH_DATA_LEN); } else { + l3_hdr_len = 40; ospf_pdu_add_u16(&pdu, 0); ospf_pdu_add_u32(&pdu, 0); } @@ -73,34 +78,33 @@ ospf_neighbor_dbd_tx(ospf_neighbor_s *ospf_neighbor) flags |= OSPF_DBD_FLAG_I; } else { /* Add LSA header */ - itor = hb_itor_new(ospf_instance->lsdb); - if(ospf_neighbor->dbd_lsa_start.type) { + for(type = ospf_neighbor->dbd_lsa_type_start; type < OSPF_LSA_TYPE_MAX; type++) { + itor = hb_itor_new(ospf_instance->lsdb[type]); next = hb_itor_search_ge(itor, &ospf_neighbor->dbd_lsa_start); - } else { - next = hb_itor_first(itor); - } + while(true) { + if(!next) { + ospf_neighbor->dbd_more = false; + break; + } + lsa = *hb_itor_datum(itor); + if(lsa->deleted) { + /* Ignore deleted LSA. */ + next = hb_itor_next(itor); + continue; + } + if((l3_hdr_len + pdu.pdu_len + OSPF_LLS_HDR_LEN + OSPF_LSA_HDR_LEN) > interface->mtu) { + memcpy(&ospf_neighbor->dbd_lsa_next, &lsa->key, sizeof(ospf_lsa_key_s)); + ospf_neighbor->dbd_lsa_type_next = type; + break; + } + + ospf_lsa_update_age(lsa, &now); + ospf_pdu_add_bytes(&pdu, lsa->lsa, OSPF_LSA_HDR_LEN); - while(true) { - if(!next) { - ospf_neighbor->dbd_more = false; - break; - } - lsa = *hb_itor_datum(itor); - if(lsa->deleted) { - /* Ignore deleted LSA. */ next = hb_itor_next(itor); - continue; - } - if((pdu.cur + OSPF_LLS_HDR_LEN + OSPF_LSA_HDR_LEN) - > ospf_interface->max_len) { - memcpy(&ospf_neighbor->dbd_lsa_next, &lsa->key, sizeof(ospf_lsa_key_s)); - break; } + hb_itor_free(itor); - ospf_lsa_update_age(lsa, &now); - ospf_pdu_add_bytes(&pdu, lsa->lsa, OSPF_LSA_HDR_LEN); - - next = hb_itor_next(itor); } } @@ -154,11 +158,12 @@ ospf_neigbor_retry_job(timer_s *timer) static void ospf_neighbor_clear(ospf_neighbor_s *ospf_neighbor) { - hb_tree_clear(ospf_neighbor->lsa_update_tree, ospf_lsa_tree_entry_clear); - hb_tree_clear(ospf_neighbor->lsa_retry_tree, ospf_lsa_tree_entry_clear); - hb_tree_clear(ospf_neighbor->lsa_request_tree, ospf_lsa_tree_entry_clear); - hb_tree_clear(ospf_neighbor->lsa_ack_tree, ospf_lsa_tree_entry_clear); - + for(uint8_t type=OSPF_LSA_TYPE_1; type < OSPF_LSA_TYPE_MAX; type++) { + hb_tree_clear(ospf_neighbor->lsa_update_tree[type], ospf_lsa_tree_entry_clear); + hb_tree_clear(ospf_neighbor->lsa_retry_tree[type], ospf_lsa_tree_entry_clear); + hb_tree_clear(ospf_neighbor->lsa_request_tree[type], ospf_lsa_tree_entry_clear); + hb_tree_clear(ospf_neighbor->lsa_ack_tree[type], ospf_lsa_tree_entry_clear); + } timer_del(ospf_neighbor->timer_lsa_retry); } @@ -169,7 +174,9 @@ ospf_neigbor_exstart(ospf_neighbor_s *ospf_neighbor) ospf_neighbor->dd = (rand() & 0xffff)+1; ospf_neighbor->dbd_more = true; memset(&ospf_neighbor->dbd_lsa_start, 0x0, sizeof(ospf_lsa_key_s)); - memset(&ospf_neighbor->dbd_lsa_next, 0x0, sizeof(ospf_lsa_key_s)); + ospf_neighbor->dbd_lsa_type_start = OSPF_LSA_TYPE_1; + memset(&ospf_neighbor->dbd_lsa_next, UINT8_MAX, sizeof(ospf_lsa_key_s)); + ospf_neighbor->dbd_lsa_type_next = OSPF_LSA_TYPE_MAX; ospf_neighbor_dbd_tx(ospf_neighbor); @@ -245,10 +252,12 @@ ospf_neigbor_new(ospf_interface_s *ospf_interface, ospf_pdu_s *pdu) ospf_neighbor->state = OSPF_NBSTATE_DOWN; ospf_neighbor->interface = ospf_interface; - ospf_neighbor->lsa_update_tree = hb_tree_new((dict_compare_func)ospf_lsa_id_compare); - ospf_neighbor->lsa_retry_tree = hb_tree_new((dict_compare_func)ospf_lsa_id_compare); - ospf_neighbor->lsa_request_tree = hb_tree_new((dict_compare_func)ospf_lsa_id_compare); - ospf_neighbor->lsa_ack_tree = hb_tree_new((dict_compare_func)ospf_lsa_id_compare); + for(uint8_t type=OSPF_LSA_TYPE_1; type < OSPF_LSA_TYPE_MAX; type++) { + ospf_neighbor->lsa_update_tree[type] = hb_tree_new((dict_compare_func)ospf_lsa_key_compare); + ospf_neighbor->lsa_retry_tree[type] = hb_tree_new((dict_compare_func)ospf_lsa_key_compare); + ospf_neighbor->lsa_request_tree[type] = hb_tree_new((dict_compare_func)ospf_lsa_key_compare); + ospf_neighbor->lsa_ack_tree[type] = hb_tree_new((dict_compare_func)ospf_lsa_key_compare); + } LOG(OSPF, "OSPFv%u new neighbor %s on interface %s\n", ospf_neighbor->version, @@ -375,6 +384,19 @@ ospf_neighbor_dbd_rx(ospf_interface_s *ospf_interface, return; } + if((dd == ospf_neighbor->rx.dd) && (options == ospf_neighbor->rx.options) && + (((OSPF_DBD_FLAG_I|OSPF_DBD_FLAG_M|OSPF_DBD_FLAG_MS) && flags) == + ((OSPF_DBD_FLAG_I|OSPF_DBD_FLAG_M|OSPF_DBD_FLAG_MS) && ospf_neighbor->rx.flags))) { + /* Duplicate received! */ + if(!ospf_neighbor->master) { + ospf_neighbor_dbd_tx(ospf_neighbor); + } + return; + } + ospf_neighbor->rx.dd = dd; + ospf_neighbor->rx.flags = flags; + ospf_neighbor->rx.options = options; + if(ospf_neighbor->state == OSPF_NBSTATE_EXSTART) { ospf_neighbor->options = options; if(flags & OSPF_DBD_FLAG_I && @@ -424,7 +446,10 @@ ospf_neighbor_dbd_rx(ospf_interface_s *ospf_interface, /* Next */ ospf_neighbor->dd++; memcpy(&ospf_neighbor->dbd_lsa_start, &ospf_neighbor->dbd_lsa_next, sizeof(ospf_lsa_key_s)); + ospf_neighbor->dbd_lsa_type_start = ospf_neighbor->dbd_lsa_type_next; memset(&ospf_neighbor->dbd_lsa_next, UINT8_MAX, sizeof(ospf_lsa_key_s)); + ospf_neighbor->dbd_lsa_type_next = OSPF_LSA_TYPE_MAX; + ospf_neighbor_dbd_tx(ospf_neighbor); } } else { @@ -454,14 +479,20 @@ ospf_neighbor_dbd_rx(ospf_interface_s *ospf_interface, hdr = (ospf_lsa_header_s*)OSPF_PDU_CURSOR(pdu); OSPF_PDU_CURSOR_INC(pdu, OSPF_LSA_HDR_LEN); - search = hb_tree_search(ospf_instance->lsdb, &hdr->type); + if(hdr->type < OSPF_LSA_TYPE_1 || hdr->type > OSPF_LSA_TYPE_11) { + ospf_rx_error(interface, pdu, "decode (invalid LSA type)"); + ospf_neigbor_state(ospf_neighbor, OSPF_NBSTATE_EXSTART); + return; + } + + search = hb_tree_search(ospf_instance->lsdb[hdr->type], &hdr->id); if(search) { lsa = *search; if(ospf_lsa_compare(hdr, (ospf_lsa_header_s*)lsa->lsa) != 1) { continue; } } - ospf_lsa_tree_add(NULL, hdr, ospf_neighbor->lsa_request_tree); + ospf_lsa_tree_add(NULL, hdr, ospf_neighbor->lsa_request_tree[hdr->type]); } /* Change state to loading if all DBD messages have been exchanged. */ diff --git a/code/bngblaster/src/ospf/ospf_pdu.c b/code/bngblaster/src/ospf/ospf_pdu.c index e336a618..810617a7 100644 --- a/code/bngblaster/src/ospf/ospf_pdu.c +++ b/code/bngblaster/src/ospf/ospf_pdu.c @@ -255,6 +255,7 @@ ospf_pdu_tx(ospf_pdu_s *pdu, uint8_t mac[ETH_ADDR_LEN]; eth.src = interface->mac; + eth.vlan_outer = interface->vlan; if(ospf_interface->version == OSPF_VERSION_2) { eth.type = ETH_TYPE_IPV4; eth.next = &ipv4; diff --git a/code/bngblaster/src/ospf/ospf_utils.c b/code/bngblaster/src/ospf/ospf_utils.c index e69e4a65..ae34b559 100644 --- a/code/bngblaster/src/ospf/ospf_utils.c +++ b/code/bngblaster/src/ospf/ospf_utils.c @@ -93,4 +93,5 @@ ospf_rx_error(bbl_network_interface_s *interface, ospf_pdu_s *pdu, const char *e error, interface->name); interface->stats.ospf_rx_error++; -} \ No newline at end of file +} +