diff options
Diffstat (limited to 'proto')
-rw-r--r-- | proto/ospf/rt.c | 106 |
1 files changed, 61 insertions, 45 deletions
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index b589459b..5c0b3fa2 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -146,6 +146,46 @@ ri_install(struct proto_ospf *po, ip_addr prefix, int pxlen, int dest, } } +#ifdef OSPFv2 + +static struct ospf_iface * +find_stub_src(struct ospf_area *oa, ip_addr px, int pxlen) +{ + struct ospf_iface *iff; + struct ifa *addr; + + WALK_LIST(iff, oa->po->iface_list) + if ((iff->type != OSPF_IT_VLINK) && + (iff->oa == oa) && + ipa_equal(iff->addr->px, px) && + (iff->addr->pxlen == pxlen)) + return iff; + + return NULL; +} + +#else /* OSPFv3 */ + +static struct ospf_iface * +find_stub_src(struct ospf_area *oa, ip_addr px, int pxlen) +{ + struct ospf_iface *iff; + struct ifa *a; + + WALK_LIST(iff, oa->po->iface_list) + if ((iff->type != OSPF_IT_VLINK) && + (iff->oa == oa)) + WALK_LIST(a, iff->iface->addrs) + if (ipa_equal(a->prefix, px) && + (a->pxlen == pxlen) && + !(a->flags & IA_SECONDARY)) + return iff; + + return NULL; +} + +#endif + static void add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_hash_entry *en) { @@ -161,7 +201,21 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_ nf.ifa = en->nhi; nf.rid = en->lsa.rt; - /* FIXME check nf.ifa on stubs */ + if (en == oa->rt) + { + /* + * Local stub networks does not have proper iface in en->nhi + * (because they all have common top_hash_entry en). + * We have to find iface responsible for that stub network. + * Some stubnets does not have any iface. Ignore them. + */ + + nf.ifa = find_stub_src(oa, px, pxlen); + + if (!nf.ifa) + return; + } + ri_install(oa->po, px, pxlen, ORT_NET, &nf, NULL); } @@ -243,45 +297,10 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to { #ifdef OSPFv2 case LSART_STUB: - /* - * This violates rfc2328! But it is mostly harmless. - */ - DBG("\n"); - - orta nf; - nf.type = RTS_OSPF; - nf.options = 0; - nf.metric1 = act->dist + rtl->metric; - nf.metric2 = LSINFINITY; - nf.tag = 0; - nf.oa = oa; - nf.ar = act; - nf.nh = act->nh; - nf.ifa = act->nhi; - nf.rid = act->lsa.rt; - - if (act == oa->rt) - { - struct ospf_iface *iff; - - WALK_LIST(iff, po->iface_list) /* Try to find corresponding interface */ - { - // FIXME this is broken - if (iff->iface && (iff->type != OSPF_IT_VLINK) && - (rtl->id == (ipa_to_u32(ipa_mkmask(iff->addr->pxlen)) - & ipa_to_u32(iff->addr->prefix)))) /* No VLINK and IP must match */ - { - nf.ifa = iff; - break; - } - } - } - - if (!nf.ifa) - continue; - - ri_install(po, ipa_from_u32(rtl->id), - ipa_mklen(ipa_from_u32(rtl->data)), ORT_NET, &nf, NULL); + /* This violates RFC 2328! But it is mostly harmless. */ + add_network(oa, ipa_from_u32(rtl->id), + ipa_mklen(ipa_from_u32(rtl->data)), + act->dist + rtl->metric, act); break; #endif @@ -292,21 +311,18 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to #else /* OSPFv3 */ tmp = ospf_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET); #endif - if (tmp == NULL) - DBG("Not found!\n"); - else - DBG("Found. :-)\n"); break; case LSART_VLNK: case LSART_PTP: tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl->id); - DBG("PTP found.\n"); break; + default: log("Unknown link type in router lsa. (rid = %R)", act->lsa.id); break; } + if (tmp) DBG("Going to add cand, Mydist: %u, Req: %u\n", tmp->dist, act->dist + rtl->metric); |