112 lines
3.4 KiB
Diff
112 lines
3.4 KiB
Diff
# UNDF: UNDF-2026-000000075
|
|
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
|
|
index a1b2c43..7f3e2d1 100644
|
|
--- a/ospfd/ospf_spf.c
|
|
+++ b/ospfd/ospf_spf.c
|
|
@@ -6,6 +6,8 @@
|
|
#include <zebra.h>
|
|
|
|
#include "monotime.h"
|
|
+#include "hash.h"
|
|
+#include "jhash.h"
|
|
#include "frrevent.h"
|
|
#include "memory.h"
|
|
#include "hash.h"
|
|
@@ -178,12 +180,43 @@ static struct vertex *ospf_vertex_new(struct ospf_area *area,
|
|
new->children = list_new();
|
|
new->parents = list_new();
|
|
new->parents->del = (void (*)(void *))vertex_parent_free;
|
|
new->parents->cmp = vertex_parent_cmp;
|
|
new->lsa_p = lsa;
|
|
+ /* CWE-407 fix: allocate O(1) hash set for children membership. */
|
|
+ new->children_index = hash_create(ospf_vertex_hash,
|
|
+ ospf_vertex_cmp_fn, NULL);
|
|
|
|
lsa->stat = new;
|
|
|
|
listnode_add(area->spf_vertex_list, new);
|
|
|
|
@@ -208,6 +251,10 @@ void ospf_vertex_free(void *data)
|
|
if (v->children)
|
|
list_delete(&v->children);
|
|
|
|
+ if (v->children_index) {
|
|
+ hash_clean(v->children_index, NULL);
|
|
+ hash_free(v->children_index);
|
|
+ v->children_index = NULL;
|
|
+ }
|
|
+
|
|
if (v->parents)
|
|
list_delete(&v->parents);
|
|
|
|
@@ -261,16 +308,36 @@ static void ospf_vertex_dump(const char *msg, struct vertex *v,
|
|
}
|
|
|
|
|
|
+/* Hash/compare callbacks for the children_index hash set. */
|
|
+static unsigned int ospf_vertex_hash(const void *data)
|
|
+{
|
|
+ const struct vertex *v = data;
|
|
+ return jhash_1word(v->id.s_addr, 0);
|
|
+}
|
|
+
|
|
+static bool ospf_vertex_cmp_fn(const void *a, const void *b)
|
|
+{
|
|
+ const struct vertex *va = a, *vb = b;
|
|
+ return va->id.s_addr == vb->id.s_addr;
|
|
+}
|
|
+
|
|
/* Add a vertex to the list of children in each of its parents. */
|
|
static void ospf_vertex_add_parent(struct vertex *v)
|
|
{
|
|
struct vertex_parent *vp;
|
|
struct listnode *node;
|
|
|
|
assert(v && v->parents);
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) {
|
|
assert(vp->parent && vp->parent->children);
|
|
+ assert(vp->parent->children_index);
|
|
|
|
- /* No need to add two links from the same parent. */
|
|
- if (listnode_lookup(vp->parent->children, v) == NULL)
|
|
- listnode_add(vp->parent->children, v);
|
|
+ /*
|
|
+ * CWE-407 fix: was listnode_lookup(vp->parent->children, v)
|
|
+ * which is O(C) per call — O(V²) total in hub-spoke topology
|
|
+ * where every vertex shares the same parent hub and C grows
|
|
+ * linearly with the number of spokes already added.
|
|
+ *
|
|
+ * Replace with O(1) hash_lookup on children_index.
|
|
+ */
|
|
+ if (hash_lookup(vp->parent->children_index, v) == NULL) {
|
|
+ listnode_add(vp->parent->children, v);
|
|
+ hash_get(vp->parent->children_index, v,
|
|
+ hash_alloc_intern);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h
|
|
index 8c4d231..a3b1e09 100644
|
|
--- a/ospfd/ospf_spf.h
|
|
+++ b/ospfd/ospf_spf.h
|
|
@@ -21,12 +21,19 @@ PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue);
|
|
/* A router or network in an area */
|
|
struct vertex {
|
|
struct vertex_pqueue_item pqi;
|
|
uint8_t flags;
|
|
uint8_t type; /* copied from LSA header */
|
|
struct in_addr id; /* copied from LSA header */
|
|
struct ospf_lsa *lsa_p;
|
|
struct lsa_header *lsa; /* Router or Network LSA */
|
|
uint32_t distance; /* from root to this vertex */
|
|
struct list *parents; /* list of parents in SPF tree */
|
|
struct list *children; /* list of children in SPF tree*/
|
|
+ /* CWE-407 fix: O(1) membership set mirroring children list.
|
|
+ * Replaces listnode_lookup(children, v) — O(C) — in
|
|
+ * ospf_vertex_add_parent() with hash_lookup — O(1).
|
|
+ * In a hub-spoke topology with V spokes, this reduces the total
|
|
+ * membership-check cost from O(V²) to O(V). */
|
|
+ struct hash *children_index;
|
|
};
|