OSPF refactoring (tree per type, ...)

This commit is contained in:
Christian Giese
2023-07-24 21:33:38 +00:00
parent c3c203bab3
commit 0129a1fefe
13 changed files with 607 additions and 376 deletions
+1
View File
@@ -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},
+1 -1
View File
@@ -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;
+7 -1
View File
@@ -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",
+1 -1
View File
@@ -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();
+104
View File
@@ -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;
}
+3
View File
@@ -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
+28 -18
View File
@@ -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;
+6 -4
View File
@@ -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
View File
@@ -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]);
}
}
}
+1 -4
View File
@@ -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);
+74 -43
View File
@@ -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. */
+1
View File
@@ -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;
+2 -1
View File
@@ -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++;
}
}