mirror of
https://github.com/rtbrick/bngblaster.git
synced 2024-05-06 15:54:57 +00:00
OSPF refactoring (tree per type, ...)
This commit is contained in:
@@ -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},
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
+378
-303
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user