summaryrefslogtreecommitdiff
path: root/proto/ospf/topology.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/topology.c')
-rw-r--r--proto/ospf/topology.c84
1 files changed, 71 insertions, 13 deletions
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 47d8367e..182f644a 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -1303,15 +1303,19 @@ static inline unsigned
ospf_top_hash(struct top_graph *f, u32 domain, u32 lsaid, u32 rtrid, u32 type)
{
/* In OSPFv2, we don't know Router ID when looking for network LSAs.
- dirty patch to make rt table calculation work. */
+ In OSPFv3, we don't know LSA ID when looking for router LSAs.
+ In both cases, there is (usually) just one (or small number)
+ appropriate LSA, so we just clear unknown part of key. */
- return (ospf_top_hash_u32(lsaid) + type +
+ return (
#ifdef OSPFv2
((type == LSA_T_NET) ? 0 : ospf_top_hash_u32(rtrid)) +
+ ospf_top_hash_u32(lsaid) +
#else /* OSPFv3 */
ospf_top_hash_u32(rtrid) +
+ ((type == LSA_T_RT) ? 0 : ospf_top_hash_u32(lsaid)) +
#endif
- domain) & f->hash_mask;
+ type + domain) & f->hash_mask;
/*
return (ospf_top_hash_u32(lsaid) + ospf_top_hash_u32(rtrid) +
@@ -1423,28 +1427,82 @@ struct top_hash_entry *
ospf_hash_find(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
{
struct top_hash_entry *e;
-
e = f->hash_table[ospf_top_hash(f, domain, lsa, rtr, type)];
+ while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr || e->domain != domain))
+ e = e->next;
+
+ return e;
+}
+
+
#ifdef OSPFv2
- /* dirty patch to make rt table calculation work. */
- if (type == LSA_T_NET)
- {
- while (e && (e->lsa.id != lsa || e->lsa.type != LSA_T_NET || e->domain != domain))
- e = e->next;
- return e;
- }
+/* In OSPFv2, sometimes we don't know Router ID when looking for network LSAs.
+ There should be just one, so we find any match. */
+struct top_hash_entry *
+ospf_hash_find_net(struct top_graph *f, u32 domain, u32 lsa)
+{
+ struct top_hash_entry *e;
+ e = f->hash_table[ospf_top_hash(f, domain, lsa, 0, LSA_T_NET)];
+
+ while (e && (e->lsa.id != lsa || e->lsa.type != LSA_T_NET || e->domain != domain))
+ e = e->next;
+
+ return e;
+}
#endif
- while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr || e->domain != domain))
- e = e->next;
+#ifdef OSPFv3
+
+/* In OSPFv3, usually we don't know LSA ID when looking for router
+ LSAs. We return matching LSA with smallest LSA ID. */
+struct top_hash_entry *
+ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr)
+{
+ struct top_hash_entry *rv = NULL;
+ struct top_hash_entry *e;
+ e = f->hash_table[ospf_top_hash(f, domain, 0, rtr, LSA_T_RT)];
+
+ while (e)
+ {
+ if (e->lsa.rt == rtr && e->lsa.type == LSA_T_RT && e->domain == domain)
+ if (!rv || e->lsa.id < rv->lsa.id)
+ rv = e;
+ e = e->next;
+ }
+
+ return rv;
+}
+
+static inline struct top_hash_entry *
+find_matching_rt(struct top_hash_entry *e, u32 domain, u32 rtr)
+{
+ while (e && (e->lsa.rt != rtr || e->lsa.type != LSA_T_RT || e->domain != domain))
+ e = e->next;
return e;
}
struct top_hash_entry *
+ospf_hash_find_rt_first(struct top_graph *f, u32 domain, u32 rtr)
+{
+ struct top_hash_entry *e;
+ e = f->hash_table[ospf_top_hash(f, domain, 0, rtr, LSA_T_RT)];
+ return find_matching_rt(e, domain, rtr);
+}
+
+struct top_hash_entry *
+ospf_hash_find_rt_next(struct top_hash_entry *e)
+{
+ return find_matching_rt(e->next, e->domain, e->lsa.rt);
+}
+
+#endif
+
+
+struct top_hash_entry *
ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
{
struct top_hash_entry **ee;