java-topology/defects/frrouting/patch/frrouting-0002-ospf-spf-vertex-parent-hashset.patch

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;
};