From e7b4948cbd3e4cacf4fe0f774b44d1f74029ea6d Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 28 Dec 2010 01:43:07 +0100 Subject: [PATCH] A simplification of the next-hop calculation. Thanks to Joakim Tjernlund for the idea. --- proto/ospf/iface.c | 7 +++ proto/ospf/ospf.h | 5 ++ proto/ospf/rt.c | 128 +++++++++++++++--------------------------- proto/ospf/topology.c | 21 ++++++- 4 files changed, 76 insertions(+), 85 deletions(-) diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 05442dfe..e7c9e72d 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -197,6 +197,13 @@ ospf_iface_down(struct ospf_iface *ifa) ifa->cost = 0; ifa->vip = IPA_NONE; } + + ifa->rt_pos_beg = 0; + ifa->rt_pos_end = 0; +#ifdef OSPFv3 + ifa->px_pos_beg = 0; + ifa->px_pos_end = 0; +#endif } diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index e260dc08..75ffb6de 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -195,8 +195,13 @@ struct ospf_iface ip_addr bdrip; /* Backup DR */ u32 drid; u32 bdrid; + s16 rt_pos_beg; /* Position of iface in Router-LSA, begin, inclusive */ + s16 rt_pos_end; /* Position of iface in Router-LSA, end, exclusive */ #ifdef OSPFv3 + s16 px_pos_beg; /* Position of iface in Rt Prefix-LSA, begin, inclusive */ + s16 px_pos_end; /* Position of iface in Rt Prefix-LSA, end, exclusive */ + u32 dr_iface_id; /* if drid is valid, this is iface_id of DR (for connecting network) */ u8 instance_id; /* Used to differentiate between more OSPF instances on one interface */ diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 953a679a..2f9fe493 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -10,7 +10,7 @@ static void add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, u32 dist, - struct ospf_area *oa, struct ospf_lsa_rt_link *rtl); + struct ospf_area *oa, int i); static void rt_sync(struct proto_ospf *po); /* In ospf_area->rtr we store paths to routers, but we use RID (and not IP address) @@ -208,48 +208,31 @@ ri_install_ext(struct proto_ospf *po, ip_addr prefix, int pxlen, orta *new) memcpy(&old->n, new, sizeof(orta)); } - -#ifdef OSPFv2 - -static struct ospf_iface * -find_stub_src(struct ospf_area *oa, ip_addr px, int pxlen) +static inline struct ospf_iface * +rt_pos_to_ifa(struct ospf_area *oa, int pos) { - struct ospf_iface *iff; - - WALK_LIST(iff, oa->po->iface_list) - if ((iff->type != OSPF_IT_VLINK) && - (iff->oa == oa) && - ipa_equal(iff->addr->prefix, px) && - (iff->addr->pxlen == pxlen)) - return iff; - + struct ospf_iface *ifa; + WALK_LIST(ifa, oa->po->iface_list) + if (pos >= ifa->rt_pos_beg && pos < ifa->rt_pos_end) + return ifa; return NULL; } -#else /* OSPFv3 */ - -static struct ospf_iface * -find_stub_src(struct ospf_area *oa, ip_addr px, int pxlen) +#ifdef OSPFv3 +static inline struct ospf_iface * +px_pos_to_ifa(struct ospf_area *oa, int pos) { - 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; - + struct ospf_iface *ifa; + WALK_LIST(ifa, oa->po->iface_list) + if (pos >= ifa->px_pos_beg && pos < ifa->px_pos_end) + return ifa; return NULL; } - #endif + static void -add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_hash_entry *en) +add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_hash_entry *en, int pos) { orta nf = { .type = RTS_OSPF, @@ -272,7 +255,13 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_ * be removed in rt_sync(). */ - struct ospf_iface *ifa = find_stub_src(oa, px, pxlen); + struct ospf_iface *ifa; +#ifdef OSPFv2 + ifa = rt_pos_to_ifa(oa, pos); +#else /* OSPFv3 */ + ifa = px_pos_to_ifa(oa, pos); +#endif + nf.nhs = ifa ? new_nexthop(oa->po, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL; } @@ -335,7 +324,7 @@ process_prefixes(struct ospf_area *oa) if ((pxopts & OPT_PX_LA) && ipa_zero(src->lb)) src->lb = pxa; - add_network(oa, pxa, pxlen, src->dist + metric, src); + add_network(oa, pxa, pxlen, src->dist + metric, src, i); } } } @@ -347,7 +336,7 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to { // struct proto *p = &oa->po->proto; struct proto_ospf *po = oa->po; - u32 i; + int i; struct ospf_lsa_rt *rt = en->lsa_body; struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1); @@ -370,7 +359,7 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to */ add_network(oa, ipa_from_u32(rtl->id), ipa_mklen(ipa_from_u32(rtl->data)), - act->dist + rtl->metric, act); + act->dist + rtl->metric, act, i); break; #endif @@ -396,7 +385,7 @@ ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct to if (tmp) DBG("Going to add cand, Mydist: %u, Req: %u\n", tmp->dist, act->dist + rtl->metric); - add_cand(&oa->cand, tmp, act, act->dist + rtl->metric, oa, rtl); + add_cand(&oa->cand, tmp, act, act->dist + rtl->metric, oa, i); } } @@ -482,7 +471,7 @@ ospf_rt_spfa(struct ospf_area *oa) #ifdef OSPFv2 add_network(oa, ipa_and(ipa_from_u32(act->lsa.id), ln->netmask), - ipa_mklen(ln->netmask), act->dist, act); + ipa_mklen(ln->netmask), act->dist, act, -1); #endif rts = (u32 *) (ln + 1); @@ -494,7 +483,7 @@ ospf_rt_spfa(struct ospf_area *oa) DBG("Found :-)\n"); else DBG("Not found!\n"); - add_cand(&oa->cand, tmp, act, act->dist, oa, NULL); + add_cand(&oa->cand, tmp, act, act->dist, oa, -1); } break; } @@ -1326,31 +1315,6 @@ ospf_rt_spf(struct proto_ospf *po) } -static inline int -match_dr(struct ospf_iface *ifa, struct top_hash_entry *en) -{ -#ifdef OSPFv2 - return (ifa->drid == en->lsa.rt) && (ipa_to_u32(ifa->drip) == en->lsa.id); -#else /* OSPFv3 */ - return (ifa->drid == en->lsa.rt) && (ifa->dr_iface_id == en->lsa.id); -#endif -} - - -static inline int -match_rtlink(struct ospf_iface *ifa, struct ospf_lsa_rt_link *rtl) -{ -#ifdef OSPFv2 - return ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP)) && - (ifa->cost == rtl->metric) && - (((ifa->addr->flags & IA_UNNUMBERED) ? ifa->iface->index : - ipa_to_u32(ifa->addr->ip)) == rtl->data); -#else /* OSPFv3 */ - return ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP)) && - (ifa->cost == rtl->metric) && (ifa->iface->index == rtl->lif); -#endif -} - static inline int inherit_nexthops(struct mpnh *pn) { @@ -1360,7 +1324,7 @@ inherit_nexthops(struct mpnh *pn) static struct mpnh * calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, - struct top_hash_entry *par, struct ospf_lsa_rt_link *rtl) + struct top_hash_entry *par, int pos) { // struct proto *p = &oa->po->proto; struct proto_ospf *po = oa->po; @@ -1386,28 +1350,28 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, /* The first case - local network */ if ((en->lsa.type == LSA_T_NET) && (par == oa->rt)) { - WALK_LIST(ifa, po->iface_list) - if (match_dr(ifa, en)) - return new_nexthop(po, IPA_NONE, ifa->iface, ifa->ecmp_weight); + ifa = rt_pos_to_ifa(oa, pos); + if (!ifa) + return NULL; - return NULL; + return new_nexthop(po, IPA_NONE, ifa->iface, ifa->ecmp_weight); } /* The second case - ptp or ptmp neighbor */ if ((en->lsa.type == LSA_T_RT) && (par == oa->rt)) { - if (rtl->type == LSART_VLNK) + ifa = rt_pos_to_ifa(oa, pos); + if (!ifa) + return NULL; + + if (ifa->type == OSPF_IT_VLINK) return new_nexthop(po, IPA_NONE, NULL, 0); - WALK_LIST(ifa, po->iface_list) - if (match_rtlink(ifa, rtl)) - { - struct ospf_neighbor *m = find_neigh(ifa, rid); - if (m && (m->state == NEIGHBOR_FULL)) - return new_nexthop(po, m->ip, ifa->iface, ifa->ecmp_weight); - } - - return NULL; + struct ospf_neighbor *m = find_neigh(ifa, rid); + if (!m || (m->state != NEIGHBOR_FULL)) + return NULL; + + return new_nexthop(po, m->ip, ifa->iface, ifa->ecmp_weight); } /* The third case - bcast or nbma neighbor */ @@ -1532,7 +1496,7 @@ merge_nexthops(struct proto_ospf *po, struct top_hash_entry *en, /* Add LSA into list of candidates in Dijkstra's algorithm */ static void add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, - u32 dist, struct ospf_area *oa, struct ospf_lsa_rt_link *rtl) + u32 dist, struct ospf_area *oa, int pos) { struct proto_ospf *po = oa->po; node *prev, *n; @@ -1566,7 +1530,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, if (!link_back(oa, en, par)) return; - struct mpnh *nhs = calc_next_hop(oa, en, par, rtl); + struct mpnh *nhs = calc_next_hop(oa, en, par, pos); if (!nhs) { log(L_WARN "Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)", diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index dc6cd1dc..9e693e13 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -241,6 +241,8 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) continue; + ifa->rt_pos_beg = i; + /* RFC2328 - 12.4.1.1-4 */ switch (ifa->type) { @@ -294,6 +296,8 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) break; } + ifa->rt_pos_end = i; + /* Now we will originate stub area if there is no primary */ if (net_lsa || (ifa->type == OSPF_IT_VLINK) || @@ -321,6 +325,8 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) ln->padding = 0; } i++; + + ifa->rt_pos_end = i; } struct ospf_stubnet_config *sn; @@ -367,6 +373,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) struct proto_ospf *po = oa->po; struct ospf_iface *ifa; int bitv = 0; + int i = 0; struct ospf_lsa_rt *rt; struct ospf_neighbor *neigh; @@ -396,6 +403,8 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) continue; + ifa->rt_pos_beg = i; + /* RFC5340 - 4.4.3.2 */ switch (ifa->type) { @@ -403,25 +412,27 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) case OSPF_IT_PTMP: WALK_LIST(neigh, ifa->neigh_list) if (neigh->state == NEIGHBOR_FULL) - add_lsa_rt_link(po, ifa, LSART_PTP, neigh->iface_id, neigh->rid); + add_lsa_rt_link(po, ifa, LSART_PTP, neigh->iface_id, neigh->rid), i++; break; case OSPF_IT_BCAST: case OSPF_IT_NBMA: if (bcast_net_active(ifa)) - add_lsa_rt_link(po, ifa, LSART_NET, ifa->dr_iface_id, ifa->drid); + add_lsa_rt_link(po, ifa, LSART_NET, ifa->dr_iface_id, ifa->drid), i++; break; 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_lsa_rt_link(po, ifa, LSART_VLNK, neigh->iface_id, neigh->rid); + add_lsa_rt_link(po, ifa, LSART_VLNK, neigh->iface_id, neigh->rid), i++; break; default: log("Unknown interface type %s", ifa->iface->name); break; } + + ifa->rt_pos_end = i; } if (bitv) @@ -1184,6 +1195,8 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) continue; + ifa->px_pos_beg = i; + if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA)) net_lsa = bcast_net_active(ifa); @@ -1215,6 +1228,8 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) (a->pxlen == MAX_PREFIX_LENGTH)) host_addr = 1; } + + ifa->px_pos_end = i; } /* If there are some configured vlinks, add some global address,