*/
struct ospf_iface *ifa;
-#ifdef OSPFv2
- ifa = rt_pos_to_ifa(oa, pos);
-#else /* OSPFv3 */
- ifa = px_pos_to_ifa(oa, pos);
-#endif
+ ifa = ospf_is_v2(po) ? rt_pos_to_ifa(oa, pos) : px_pos_to_ifa(oa, pos);
+ nf.nhs = ifa ? new_nexthop(po, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL;
+ }
- nf.nhs = ifa ? new_nexthop(oa->po, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL;
+ ri_install_net(po, px, pxlen, &nf);
+}
+
+
+
+static inline void
+spfa_process_rt(struct ospf_area *oa, struct top_hash_entry *act)
+{
+ struct proto_ospf *po = oa->po;
+ struct ospf_lsa_rt *rt = act->lsa_body;
+ struct ospf_lsa_rt_walk rtl;
+ struct top_hash_entry *tmp;
+ ip_addr prefix;
+ int pxlen, i;
+
+ if (rt->options & OPT_RT_V)
+ oa->trcap = 1;
+
+ /*
+ * In OSPFv3, all routers are added to per-area routing
+ * tables. But we use it just for ASBRs and ABRs. For the
+ * purpose of the last step in SPF - prefix-LSA processing in
+ * spfa_process_prefixes(), we use information stored in LSA db.
+ */
+ if (((rt->options & OPT_RT_E) || (rt->options & OPT_RT_B))
+ && (act->lsa.rt != po->router_id))
+ {
+ orta nf = {
+ .type = RTS_OSPF,
+ .options = rt->options,
+ .metric1 = act->dist,
+ .metric2 = LSINFINITY,
+ .tag = 0,
+ .rid = act->lsa.rt,
+ .oa = oa,
+ .nhs = act->nhs
+ };
+ ri_install_rt(oa, act->lsa.rt, &nf);
}
- ri_install_net(oa->po, px, pxlen, &nf);
++ /* Errata 2078 to RFC 5340 4.8.1 - skip links from non-routing nodes */
++ if (ospf_is_v3(po) && (act != oa->rt) && !(rt->options & OPT_R))
++ break;
++
+ /* Now process Rt links */
+ for (lsa_walk_rt_init(po, act, &rtl), i = 0; lsa_walk_rt(&rtl); i++)
+ {
+ tmp = NULL;
+
+ switch (rtl.type)
+ {
+ case LSART_STUB:
+
+ /* Should not happen, LSART_STUB is not defined in OSPFv3 */
+ if (ospf_is_v3(po))
+ break;
+
+ /*
+ * RFC 2328 in 16.1. (2a) says to handle stub networks in an
+ * second phase after the SPF for an area is calculated. We get
+ * the same result by handing them here because add_network()
+ * will keep the best (not the first) found route.
+ */
+ prefix = ipa_from_u32(rtl.id & rtl.data);
+ pxlen = u32_masklen(rtl.data);
+ add_network(oa, prefix, pxlen, act->dist + rtl.metric, act, i);
+ break;
+
+ case LSART_NET:
+ tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl.id, rtl.nif);
+ break;
+
+ case LSART_VLNK:
+ case LSART_PTP:
+ tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl.id);
+ break;
+ }
+
+ add_cand(&oa->cand, tmp, act, act->dist + rtl.metric, oa, i);
+ }
}
-#ifdef OSPFv3
-static void
-process_prefixes(struct ospf_area *oa)
+static inline void
+spfa_process_net(struct ospf_area *oa, struct top_hash_entry *act)
+{
+ struct proto_ospf *po = oa->po;
+ struct ospf_lsa_net *ln = act->lsa_body;
+ struct top_hash_entry *tmp;
+ ip_addr prefix;
+ int pxlen, i, cnt;
+
+ if (ospf_is_v2(po))
+ {
+ prefix = ipa_from_u32(act->lsa.id & ln->optx);
+ pxlen = u32_masklen(ln->optx);
+ add_network(oa, prefix, pxlen, act->dist, act, -1);
+ }
+
+ cnt = lsa_net_count(&act->lsa);
+ for (i = 0; i < cnt; i++)
+ {
+ tmp = ospf_hash_find_rt(po->gr, oa->areaid, ln->routers[i]);
+ add_cand(&oa->cand, tmp, act, act->dist, oa, -1);
+ }
+}
+
+static inline void
+spfa_process_prefixes(struct ospf_area *oa)
{
struct proto_ospf *po = oa->po;
// struct proto *p = &po->proto;
if (en->lsa.age == LSA_MAXAGE)
return;
-#ifdef OSPFv3
- if (en->lsa.type == LSA_T_RT)
- {
- struct ospf_lsa_rt *rt = en->lsa_body;
- if (!(rt->options & OPT_V6))
- return;
- }
-#endif
+ if (ospf_is_v3(po) && (en->lsa_type == LSA_T_RT))
- {
- /* In OSPFv3, check V6 and R flags */
- struct ospf_lsa_rt *rt = en->lsa_body;
- if (!(rt->options & OPT_V6) || !(rt->options & OPT_R))
- return;
- }
++ {
++ /* In OSPFv3, check V6 flag */
++ struct ospf_lsa_rt *rt = en->lsa_body;
++ if (!(rt->options & OPT_V6))
++ return;
++ }
/* 16.1. (2c) */
if (en->color == INSPF)
* compatibility with some broken implementations that use
* this address as a next-hop.
*/
- add_rt2_lsa_link(po, LSART_PTP, neigh->rid, ipa_to_u32(ifa->addr->ip), ifa->cost);
- ln->data = ipa_to_u32(ifa->addr->ip);
- ln->metric = link_cost;
- ln->padding = 0;
++ add_rt2_lsa_link(po, LSART_PTP, neigh->rid, ipa_to_u32(ifa->addr->ip), link_cost);
i++;
}
break;
case OSPF_IT_NBMA:
if (bcast_net_active(ifa))
{
- add_rt2_lsa_link(po, LSART_NET, ipa_to_u32(ifa->drip), ipa_to_u32(ifa->addr->ip), ifa->cost);
- ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
- ln->type = LSART_NET;
- ln->id = ipa_to_u32(ifa->drip);
- ln->data = ipa_to_u32(ifa->addr->ip);
- ln->metric = link_cost;
- ln->padding = 0;
++ add_rt2_lsa_link(po, LSART_NET, ipa_to_u32(ifa->drip), ipa_to_u32(ifa->addr->ip), link_cost);
i++;
net_lsa = 1;
}
case OSPF_IT_VLINK:
neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
- add_rt2_lsa_link(po, LSART_VLNK, neigh->rid, ipa_to_u32(ifa->addr->ip), ifa->cost), i++;
- {
- ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
- ln->type = LSART_VLNK;
- ln->id = neigh->rid;
- ln->data = ipa_to_u32(ifa->addr->ip);
- ln->metric = link_cost;
- ln->padding = 0;
- i++;
- }
++ add_rt2_lsa_link(po, LSART_VLNK, neigh->rid, ipa_to_u32(ifa->addr->ip), link_cost), i++;
break;
default: