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;