summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2010-04-11 12:22:47 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2010-04-11 12:22:47 +0200
commit6e8067609673afef9eb9e786f4e43a73a3b544f0 (patch)
tree1cdd206ace2b3c844fe72c8a99da9cf2bea30c22
parent7969ea3b41db05294c78a5e0ec0bd3c29ae8c549 (diff)
Fixes next hop calculation on NBMA and parallel PTP links.
-rw-r--r--proto/ospf/neighbor.c21
-rw-r--r--proto/ospf/neighbor.h1
-rw-r--r--proto/ospf/rt.c89
-rw-r--r--proto/ospf/topology.h3
4 files changed, 71 insertions, 43 deletions
diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c
index 69c58806..2563abd4 100644
--- a/proto/ospf/neighbor.c
+++ b/proto/ospf/neighbor.c
@@ -536,27 +536,6 @@ find_neigh(struct ospf_iface *ifa, u32 rid)
return NULL;
}
-
-/* Find a closest neighbor which is at least 2-Way */
-struct ospf_neighbor *
-find_neigh_noifa(struct proto_ospf *po, u32 rid)
-{
- struct ospf_neighbor *n = NULL, *m;
- struct ospf_iface *ifa;
-
- WALK_LIST(ifa, po->iface_list) if ((m = find_neigh(ifa, rid)) != NULL)
- {
- if (m->state >= NEIGHBOR_2WAY)
- {
- if (n == NULL)
- n = m;
- else if (m->ifa->cost < n->ifa->cost)
- n = m;
- }
- }
- return n;
-}
-
struct ospf_area *
ospf_find_area(struct proto_ospf *po, u32 aid)
{
diff --git a/proto/ospf/neighbor.h b/proto/ospf/neighbor.h
index 67f7c57c..5612eca1 100644
--- a/proto/ospf/neighbor.h
+++ b/proto/ospf/neighbor.h
@@ -14,7 +14,6 @@ struct ospf_neighbor *ospf_neighbor_new(struct ospf_iface *ifa);
void ospf_neigh_sm(struct ospf_neighbor *n, int event);
void bdr_election(struct ospf_iface *ifa);
struct ospf_neighbor *find_neigh(struct ospf_iface *ifa, u32 rid);
-struct ospf_neighbor *find_neigh_noifa(struct proto_ospf *po, u32 rid);
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
void ospf_neigh_remove(struct ospf_neighbor *n);
void ospf_sh_neigh_info(struct ospf_neighbor *n);
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index c3798e7d..6a30c687 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -477,6 +477,9 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
// FIXME lb should be properly set for vlinks */
en->lb = IPA_NONE;
+#ifdef OSPFv3
+ en->lb_id = 0;
+#endif
switch (en->lsa.type)
{
case LSA_T_RT:
@@ -500,6 +503,8 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
{
#ifdef OSPFv2
en->lb = ipa_from_u32(rtl->data);
+#else /* OSPFv3 */
+ en->lb_id = rtl->lif;
#endif
return 1;
}
@@ -1099,14 +1104,15 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
struct top_hash_entry *par)
{
// struct proto *p = &oa->po->proto;
- struct ospf_neighbor *neigh;
+ struct ospf_neighbor *neigh, *m;
struct proto_ospf *po = oa->po;
struct ospf_iface *ifa;
/* 16.1.1. The next hop calculation */
DBG(" Next hop called.\n");
- if (ipa_equal(par->nh, IPA_NONE))
+ if (ipa_zero(par->nh))
{
+ u32 rid = en->lsa.rt;
DBG(" Next hop calculating for id: %R rt: %R type: %u\n",
en->lsa.id, en->lsa.rt, en->lsa.type);
@@ -1130,32 +1136,73 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
return 0;
}
- /*
- * Remaining cases - local neighbours.
- * There are two problems with this code:
- * 1) we use IP address from HELLO packet
- * and not the one from LSA (router or link).
- * This may break NBMA networks
- * 2) we use find_neigh_noifa() and does not
- * take into account associated iface.
- * This breaks neighbors connected by more links.
- */
-
- if ((en->lsa.type == LSA_T_RT) &&
- ((par == oa->rt) || (par->lsa.type == LSA_T_NET)))
+ /* The second case - ptp or ptmp neighbor */
+ if ((en->lsa.type == LSA_T_RT) && (par == oa->rt))
{
- if ((neigh = find_neigh_noifa(po, en->lsa.rt)) != NULL)
+ /*
+ * We don't know which iface was used to reach this neighbor
+ * (there might be more parallel ifaces) so we will find
+ * the best PTP iface with given fully adjacent neighbor.
+ */
+ neigh = NULL;
+ WALK_LIST(ifa, po->iface_list)
+ if (ifa->type == OSPF_IT_PTP)
{
- en->nh = neigh->ip;
- en->nhi = neigh->ifa;
- return 1;
+ m = find_neigh(ifa, rid);
+ if (m && (m->state == NEIGHBOR_FULL))
+ {
+ if (!neigh || (m->ifa->cost < neigh->ifa->cost))
+ neigh = m;
+ }
}
- return 0;
+
+ if (!neigh)
+ return 0;
+
+ en->nh = neigh->ip;
+ en->nhi = neigh->ifa;
+ return 1;
}
+ /* The third case - bcast or nbma neighbor */
+ if ((en->lsa.type == LSA_T_RT) && (par->lsa.type == LSA_T_NET))
+ {
+ /* par->nhi should be defined from parent's calc_next_hop() */
+ if (!par->nhi)
+ goto bad;
+
+#ifdef OSPFv2
+ /*
+ * In this case, next-hop is the same as link-back, which is
+ * already computed in link_back().
+ */
+ if (ipa_zero(en->lb))
+ goto bad;
+
+ en->nh = en->lb;
+ en->nhi = par->nhi;
+ return 1;
+
+#else /* OSPFv3 */
+ /*
+ * Next-hop is taken from lladdr field of Link-LSA, en->lb_id
+ * is computed in link_back().
+ */
+ struct top_hash_entry *llsa;
+ llsa = ospf_hash_find(po->gr, par->nhi->iface->index, en->lb_id, rid, LSA_T_LINK);
+
+ if (!llsa)
+ return 0;
+
+ en->nh = llsa->lladdr;
+ en->nhi = par->nhi;
+ return 1;
+#endif
+ }
+
+ bad:
/* Probably bug or some race condition, we log it */
log(L_ERR "Unexpected case in next hop calculation");
-
return 0;
}
diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h
index f6ba0198..16d4c78f 100644
--- a/proto/ospf/topology.h
+++ b/proto/ospf/topology.h
@@ -23,6 +23,9 @@ struct top_hash_entry
ip_addr nh; /* Next hop */
ip_addr lb; /* Link back */
struct ospf_iface *nhi; /* Next hop interface */
+#ifdef OSPFv3
+ u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */
+#endif
u32 dist; /* Distance from the root */
u16 ini_age;
u8 color;