Annotation of embedaddon/bird/proto/ospf/rt.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *     BIRD -- OSPF
        !             3:  *
        !             4:  *     (c) 2000--2004 Ondrej Filip <feela@network.cz>
        !             5:  *     (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
        !             6:  *     (c) 2009--2014 CZ.NIC z.s.p.o.
        !             7:  *
        !             8:  *     Can be freely distributed and used under the terms of the GNU GPL.
        !             9:  */
        !            10: 
        !            11: #include "ospf.h"
        !            12: 
        !            13: static void add_cand(list * l, struct top_hash_entry *en,
        !            14:                     struct top_hash_entry *par, u32 dist,
        !            15:                     struct ospf_area *oa, int i);
        !            16: static void rt_sync(struct ospf_proto *p);
        !            17: 
        !            18: 
        !            19: static inline void reset_ri(ort *ort)
        !            20: {
        !            21:   bzero(&ort->n, sizeof(orta));
        !            22: }
        !            23: 
        !            24: void
        !            25: ospf_rt_initort(struct fib_node *fn)
        !            26: {
        !            27:   ort *ri = (ort *) fn;
        !            28:   reset_ri(ri);
        !            29:   ri->old_rta = NULL;
        !            30:   ri->fn.flags = 0;
        !            31: }
        !            32: 
        !            33: static inline int
        !            34: nh_is_vlink(struct mpnh *nhs)
        !            35: {
        !            36:   return !nhs->iface;
        !            37: }
        !            38: 
        !            39: static inline int
        !            40: unresolved_vlink(ort *ort)
        !            41: {
        !            42:   return ort->n.nhs && nh_is_vlink(ort->n.nhs);
        !            43: }
        !            44: 
        !            45: static inline struct mpnh *
        !            46: new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight)
        !            47: {
        !            48:   struct mpnh *nh = lp_alloc(p->nhpool, sizeof(struct mpnh));
        !            49:   nh->gw = gw;
        !            50:   nh->iface = iface;
        !            51:   nh->next = NULL;
        !            52:   nh->weight = weight;
        !            53:   return nh;
        !            54: }
        !            55: 
        !            56: /* Returns true if there are device nexthops in n */
        !            57: static inline int
        !            58: has_device_nexthops(const struct mpnh *n)
        !            59: {
        !            60:   for (; n; n = n->next)
        !            61:     if (ipa_zero(n->gw))
        !            62:       return 1;
        !            63: 
        !            64:   return 0;
        !            65: }
        !            66: 
        !            67: /* Replace device nexthops with nexthops to gw */
        !            68: static struct mpnh *
        !            69: fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw)
        !            70: {
        !            71:   struct mpnh *root1 = NULL;
        !            72:   struct mpnh *root2 = NULL;
        !            73:   struct mpnh **nn1 = &root1;
        !            74:   struct mpnh **nn2 = &root2;
        !            75: 
        !            76:   if (!p->ecmp)
        !            77:     return new_nexthop(p, gw, n->iface, n->weight);
        !            78: 
        !            79:   /* This is a bit tricky. We cannot just copy the list and update n->gw,
        !            80:      because the list should stay sorted, so we create two lists, one with new
        !            81:      gateways and one with old ones, and then merge them. */
        !            82: 
        !            83:   for (; n; n = n->next)
        !            84:   {
        !            85:     struct mpnh *nn = new_nexthop(p, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight);
        !            86: 
        !            87:     if (ipa_zero(n->gw))
        !            88:     {
        !            89:       *nn1 = nn;
        !            90:       nn1 = &(nn->next);
        !            91:     }
        !            92:     else
        !            93:     {
        !            94:       *nn2 = nn;
        !            95:       nn2 = &(nn->next);
        !            96:     }
        !            97:   }
        !            98: 
        !            99:   return mpnh_merge(root1, root2, 1, 1, p->ecmp, p->nhpool);
        !           100: }
        !           101: 
        !           102: 
        !           103: /* Whether the ASBR or the forward address destination is preferred
        !           104:    in AS external route selection according to 16.4.1. */
        !           105: static inline int
        !           106: epath_preferred(const orta *ep)
        !           107: {
        !           108:   return (ep->type == RTS_OSPF) && (ep->oa->areaid != 0);
        !           109: }
        !           110: 
        !           111: /* Whether the ext route has ASBR/next_hop marked as preferred. */
        !           112: static inline int
        !           113: orta_pref(const orta *nf)
        !           114: {
        !           115:   return !!(nf->options & ORTA_PREF);
        !           116: }
        !           117: 
        !           118: /* Classify orta entries according to RFC 3101 2.5 (6e) priorities:
        !           119:    Type-7 LSA with P-bit, Type-5 LSA, Type-7 LSA without P-bit */
        !           120: static int
        !           121: orta_prio(const orta *nf)
        !           122: {
        !           123:   /* RFC 3103 2.5 (6e) priorities */
        !           124:   u32 opts = nf->options & (ORTA_NSSA | ORTA_PROP);
        !           125: 
        !           126:   /* A Type-7 LSA with the P-bit set */
        !           127:   if (opts == (ORTA_NSSA | ORTA_PROP))
        !           128:     return 2;
        !           129: 
        !           130:   /* A Type-5 LSA */
        !           131:   if (opts == 0)
        !           132:     return 1;
        !           133: 
        !           134:   return 0;
        !           135: }
        !           136: 
        !           137: /* Whether the route is better according to RFC 3101 2.5 (6e):
        !           138:    Prioritize Type-7 LSA with P-bit, then Type-5 LSA, then higher router ID */
        !           139: static int
        !           140: orta_prefer_lsa(const orta *new, const orta *old)
        !           141: {
        !           142:   int pn = orta_prio(new);
        !           143:   int po = orta_prio(old);
        !           144: 
        !           145:   return (pn > po) || ((pn == po) && (new->en->lsa.rt > old->en->lsa.rt));
        !           146: }
        !           147: 
        !           148: /*
        !           149:  * Compare an existing routing table entry with a new one. Applicable for
        !           150:  * intra-area routes, inter-area routes and router entries. Returns integer
        !           151:  * <, = or > than 0 if the new orta is less, equal or more preferred than
        !           152:  * the old orta.
        !           153:  */
        !           154: static int
        !           155: orta_compare(const struct ospf_proto *p, const orta *new, const orta *old)
        !           156: {
        !           157:   int r;
        !           158: 
        !           159:   if (old->type == RTS_DUMMY)
        !           160:     return 1;
        !           161: 
        !           162:   /* Prefer intra-area to inter-area to externals */
        !           163:   r = ((int) old->type) - ((int) new->type);
        !           164:   if (r) return r;
        !           165: 
        !           166:   /* Prefer lowest type 1 metric */
        !           167:   r = ((int) old->metric1) - ((int) new->metric1);
        !           168:   if (r) return r;
        !           169: 
        !           170: 
        !           171:   /* Rest is BIRD-specific */
        !           172: 
        !           173:   /* Area-wide routes should not mix next-hops from different areas.
        !           174:      This generally should not happen unless there is some misconfiguration. */
        !           175:   if (new->oa->areaid != old->oa->areaid)
        !           176:     return (new->oa->areaid > old->oa->areaid) ? 1 : -1;
        !           177: 
        !           178:   /* Prefer routes for configured stubnets (!nhs) to regular routes to dummy
        !           179:      vlink nexthops. We intentionally return -1 if both are stubnets or vlinks. */
        !           180:   if (!old->nhs)
        !           181:     return -1;
        !           182:   if (!new->nhs)
        !           183:     return 1;
        !           184:   if (nh_is_vlink(new->nhs))
        !           185:     return -1;
        !           186:   if (nh_is_vlink(old->nhs))
        !           187:     return 1;
        !           188: 
        !           189: 
        !           190:   if (p->ecmp)
        !           191:     return 0;
        !           192: 
        !           193:   /* Prefer routes with higher Router ID, just to be more deterministic */
        !           194:   if (new->rid > old->rid)
        !           195:     return 1;
        !           196: 
        !           197:   return -1;
        !           198: }
        !           199: 
        !           200: /*
        !           201:  * Compare ASBR routing table entry with a new one, used for precompute ASBRs
        !           202:  * for AS external route selection (RFC 2328 16.4 (3)), Returns integer < or >
        !           203:  * than 0 if the new ASBR is less or more preferred than the old ASBR.
        !           204:  */
        !           205: static int
        !           206: orta_compare_asbr(const struct ospf_proto *p, const orta *new, const orta *old)
        !           207: {
        !           208:   int r;
        !           209: 
        !           210:   if (old->type == RTS_DUMMY)
        !           211:     return 1;
        !           212: 
        !           213:   if (!p->rfc1583)
        !           214:   {
        !           215:     r = epath_preferred(new) - epath_preferred(old);
        !           216:     if (r) return r;
        !           217:   }
        !           218: 
        !           219:   r = ((int) old->metric1) - ((int) new->metric1);
        !           220:   if (r) return r;
        !           221: 
        !           222:   /* Larger area ID is preferred */
        !           223:   if (new->oa->areaid > old->oa->areaid)
        !           224:     return 1;
        !           225: 
        !           226:   /* There is just one ASBR of that RID per area, so tie is not possible */
        !           227:   return -1;
        !           228: }
        !           229: 
        !           230: /*
        !           231:  * Compare a routing table entry with a new one, for AS external routes
        !           232:  * (RFC 2328 16.4) and NSSA routes (RFC 3103 2.5), Returns integer <, = or >
        !           233:  * than 0 if the new orta is less, equal or more preferred than the old orta.
        !           234:  */
        !           235: static int
        !           236: orta_compare_ext(const struct ospf_proto *p, const orta *new, const orta *old)
        !           237: {
        !           238:   int r;
        !           239: 
        !           240:   if (old->type == RTS_DUMMY)
        !           241:     return 1;
        !           242: 
        !           243:   /* 16.4 (6a) - prefer routes with lower type */
        !           244:   r = ((int) old->type) - ((int) new->type);
        !           245:   if (r) return r;
        !           246: 
        !           247:   /* 16.4 (6b) - prefer routes with lower type 2 metric */
        !           248:   if (new->type == RTS_OSPF_EXT2)
        !           249:   {
        !           250:     r = ((int) old->metric2) - ((int) new->metric2);
        !           251:     if (r) return r;
        !           252:   }
        !           253: 
        !           254:   /* 16.4 (6c) - if not RFC1583, prefer routes with preferred ASBR/next_hop */
        !           255:   if (!p->rfc1583)
        !           256:   {
        !           257:     r = orta_pref(new) - orta_pref(old);
        !           258:     if (r) return r;
        !           259:   }
        !           260: 
        !           261:   /* 16.4 (6d) - prefer routes with lower type 1 metric */
        !           262:   r = ((int) old->metric1) - ((int) new->metric1);
        !           263:   if (r) return r;
        !           264: 
        !           265: 
        !           266:   if (p->ecmp && p->merge_external)
        !           267:     return 0;
        !           268: 
        !           269:   /*
        !           270:    * RFC 3101 2.5 (6e) - prioritize Type-7 LSA with P-bit, then Type-5 LSA, then
        !           271:    * LSA with higher router ID. Although this should apply just to functionally
        !           272:    * equivalent LSAs (i.e. ones with the same non-zero forwarding address), we
        !           273:    * use it also to disambiguate otherwise equally preferred nexthops.
        !           274:    */
        !           275:   if (orta_prefer_lsa(new, old))
        !           276:     return 1;
        !           277: 
        !           278:   return -1;
        !           279: }
        !           280: 
        !           281: 
        !           282: static inline void
        !           283: ort_replace(ort *o, const orta *new)
        !           284: {
        !           285:   memcpy(&o->n, new, sizeof(orta));
        !           286: }
        !           287: 
        !           288: static void
        !           289: ort_merge(struct ospf_proto *p, ort *o, const orta *new)
        !           290: {
        !           291:   orta *old = &o->n;
        !           292: 
        !           293:   if (old->nhs != new->nhs)
        !           294:   {
        !           295:     old->nhs = mpnh_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
        !           296:                          p->ecmp, p->nhpool);
        !           297:     old->nhs_reuse = 1;
        !           298:   }
        !           299: 
        !           300:   if (old->rid < new->rid)
        !           301:     old->rid = new->rid;
        !           302: }
        !           303: 
        !           304: static void
        !           305: ort_merge_ext(struct ospf_proto *p, ort *o, const orta *new)
        !           306: {
        !           307:   orta *old = &o->n;
        !           308: 
        !           309:   if (old->nhs != new->nhs)
        !           310:   {
        !           311:     old->nhs = mpnh_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
        !           312:                          p->ecmp, p->nhpool);
        !           313:     old->nhs_reuse = 1;
        !           314:   }
        !           315: 
        !           316:   if (old->tag != new->tag)
        !           317:     old->tag = 0;
        !           318: 
        !           319:   /*
        !           320:    * Even with multipath, we store only one LSA in orta.en for the purpose of
        !           321:    * NSSA/ext translation. Therefore, we apply procedures from RFC 3101 2.5 (6e)
        !           322:    * to all chosen LSAs for given network, not just to functionally equivalent
        !           323:    * ones (i.e. ones with the same non-zero forwarding address).
        !           324:    */
        !           325:   if (orta_prefer_lsa(new, old))
        !           326:   {
        !           327:     old->options = new->options;
        !           328:     old->rid = new->rid;
        !           329:     old->oa = new->oa;
        !           330:     old->en = new->en;
        !           331:   }
        !           332: }
        !           333: 
        !           334: 
        !           335: 
        !           336: static inline void
        !           337: ri_install_net(struct ospf_proto *p, ip_addr prefix, int pxlen, const orta *new)
        !           338: {
        !           339:   ort *old = (ort *) fib_get(&p->rtf, &prefix, pxlen);
        !           340:   int cmp = orta_compare(p, new, &old->n);
        !           341: 
        !           342:   if (cmp > 0)
        !           343:     ort_replace(old, new);
        !           344:   else if (cmp == 0)
        !           345:     ort_merge(p, old, new);
        !           346: }
        !           347: 
        !           348: static inline void
        !           349: ri_install_rt(struct ospf_area *oa, u32 rid, const orta *new)
        !           350: {
        !           351:   ip_addr addr = ipa_from_rid(rid);
        !           352:   ort *old = (ort *) fib_get(&oa->rtr, &addr, MAX_PREFIX_LENGTH);
        !           353:   int cmp = orta_compare(oa->po, new, &old->n);
        !           354: 
        !           355:   if (cmp > 0)
        !           356:     ort_replace(old, new);
        !           357:   else if (cmp == 0)
        !           358:     ort_merge(oa->po, old, new);
        !           359: }
        !           360: 
        !           361: static inline void
        !           362: ri_install_asbr(struct ospf_proto *p, ip_addr *addr, const orta *new)
        !           363: {
        !           364:   ort *old = (ort *) fib_get(&p->backbone->rtr, addr, MAX_PREFIX_LENGTH);
        !           365:   if (orta_compare_asbr(p, new, &old->n) > 0)
        !           366:     ort_replace(old, new);
        !           367: }
        !           368: 
        !           369: static inline void
        !           370: ri_install_ext(struct ospf_proto *p, ip_addr prefix, int pxlen, const orta *new)
        !           371: {
        !           372:   ort *old = (ort *) fib_get(&p->rtf, &prefix, pxlen);
        !           373:   int cmp = orta_compare_ext(p, new, &old->n);
        !           374: 
        !           375:   if (cmp > 0)
        !           376:     ort_replace(old, new);
        !           377:   else if (cmp == 0)
        !           378:     ort_merge_ext(p, old, new);
        !           379: }
        !           380: 
        !           381: static inline struct ospf_iface *
        !           382: rt_pos_to_ifa(struct ospf_area *oa, int pos)
        !           383: {
        !           384:   struct ospf_iface *ifa;
        !           385: 
        !           386:   WALK_LIST(ifa, oa->po->iface_list)
        !           387:     if (ifa->oa == oa && pos >= ifa->rt_pos_beg && pos < ifa->rt_pos_end)
        !           388:       return ifa;
        !           389: 
        !           390:   return NULL;
        !           391: }
        !           392: 
        !           393: static inline struct ospf_iface *
        !           394: px_pos_to_ifa(struct ospf_area *oa, int pos)
        !           395: {
        !           396:   struct ospf_iface *ifa;
        !           397: 
        !           398:   WALK_LIST(ifa, oa->po->iface_list)
        !           399:     if (ifa->oa == oa && pos >= ifa->px_pos_beg && pos < ifa->px_pos_end)
        !           400:       return ifa;
        !           401: 
        !           402:   return NULL;
        !           403: }
        !           404: 
        !           405: 
        !           406: static void
        !           407: add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_hash_entry *en, int pos)
        !           408: {
        !           409:   struct ospf_proto *p = oa->po;
        !           410: 
        !           411:   orta nf = {
        !           412:     .type = RTS_OSPF,
        !           413:     .options = 0,
        !           414:     .metric1 = metric,
        !           415:     .metric2 = LSINFINITY,
        !           416:     .tag = 0,
        !           417:     .rid = en->lsa.rt,
        !           418:     .oa = oa,
        !           419:     .nhs = en->nhs
        !           420:   };
        !           421: 
        !           422:   if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
        !           423:   {
        !           424:     log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
        !           425:        p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
        !           426:     return;
        !           427:   }
        !           428: 
        !           429:   if (en == oa->rt)
        !           430:   {
        !           431:     /*
        !           432:      * Local stub networks do not have proper iface in en->nhi (because they all
        !           433:      * have common top_hash_entry en). We have to find iface responsible for
        !           434:      * that stub network. Configured stubnets do not have any iface. They will
        !           435:      * be removed in rt_sync().
        !           436:      */
        !           437: 
        !           438:     struct ospf_iface *ifa;
        !           439:     ifa = ospf_is_v2(p) ? rt_pos_to_ifa(oa, pos) : px_pos_to_ifa(oa, pos);
        !           440:     nf.nhs = ifa ? new_nexthop(p, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL;
        !           441:   }
        !           442: 
        !           443:   ri_install_net(p, px, pxlen, &nf);
        !           444: }
        !           445: 
        !           446: 
        !           447: 
        !           448: static inline void
        !           449: spfa_process_rt(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entry *act)
        !           450: {
        !           451:   struct ospf_lsa_rt *rt = act->lsa_body;
        !           452:   struct ospf_lsa_rt_walk rtl;
        !           453:   struct top_hash_entry *tmp;
        !           454:   ip_addr prefix;
        !           455:   int pxlen, i;
        !           456: 
        !           457:   if (rt->options & OPT_RT_V)
        !           458:     oa->trcap = 1;
        !           459: 
        !           460:   /*
        !           461:    * In OSPFv3, all routers are added to per-area routing
        !           462:    * tables. But we use it just for ASBRs and ABRs. For the
        !           463:    * purpose of the last step in SPF - prefix-LSA processing in
        !           464:    * spfa_process_prefixes(), we use information stored in LSA db.
        !           465:    */
        !           466:   if (((rt->options & OPT_RT_E) || (rt->options & OPT_RT_B))
        !           467:       && (act->lsa.rt != p->router_id))
        !           468:   {
        !           469:     orta nf = {
        !           470:       .type = RTS_OSPF,
        !           471:       .options = rt->options,
        !           472:       .metric1 = act->dist,
        !           473:       .metric2 = LSINFINITY,
        !           474:       .tag = 0,
        !           475:       .rid = act->lsa.rt,
        !           476:       .oa = oa,
        !           477:       .nhs = act->nhs
        !           478:     };
        !           479:     ri_install_rt(oa, act->lsa.rt, &nf);
        !           480:   }
        !           481: 
        !           482:   /* Errata 2078 to RFC 5340 4.8.1 - skip links from non-routing nodes */
        !           483:   if (ospf_is_v3(p) && (act != oa->rt) && !(rt->options & OPT_R))
        !           484:     return;
        !           485: 
        !           486:   /* Now process Rt links */
        !           487:   for (lsa_walk_rt_init(p, act, &rtl), i = 0; lsa_walk_rt(&rtl); i++)
        !           488:   {
        !           489:     tmp = NULL;
        !           490: 
        !           491:     switch (rtl.type)
        !           492:     {
        !           493:     case LSART_STUB:
        !           494: 
        !           495:       /* Should not happen, LSART_STUB is not defined in OSPFv3 */
        !           496:       if (ospf_is_v3(p))
        !           497:        break;
        !           498: 
        !           499:       /*
        !           500:        * RFC 2328 in 16.1. (2a) says to handle stub networks in an
        !           501:        * second phase after the SPF for an area is calculated. We get
        !           502:        * the same result by handing them here because add_network()
        !           503:        * will keep the best (not the first) found route.
        !           504:        */
        !           505:       prefix = ipa_from_u32(rtl.id & rtl.data);
        !           506:       pxlen = u32_masklen(rtl.data);
        !           507:       add_network(oa, prefix, pxlen, act->dist + rtl.metric, act, i);
        !           508:       break;
        !           509: 
        !           510:     case LSART_NET:
        !           511:       tmp = ospf_hash_find_net(p->gr, oa->areaid, rtl.id, rtl.nif);
        !           512:       break;
        !           513: 
        !           514:     case LSART_VLNK:
        !           515:     case LSART_PTP:
        !           516:       tmp = ospf_hash_find_rt(p->gr, oa->areaid, rtl.id);
        !           517:       break;
        !           518:     }
        !           519: 
        !           520:     add_cand(&oa->cand, tmp, act, act->dist + rtl.metric, oa, i);
        !           521:   }
        !           522: }
        !           523: 
        !           524: static inline void
        !           525: spfa_process_net(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entry *act)
        !           526: {
        !           527:   struct ospf_lsa_net *ln = act->lsa_body;
        !           528:   struct top_hash_entry *tmp;
        !           529:   ip_addr prefix;
        !           530:   int pxlen, i, cnt;
        !           531: 
        !           532:   if (ospf_is_v2(p))
        !           533:   {
        !           534:     prefix = ipa_from_u32(act->lsa.id & ln->optx);
        !           535:     pxlen = u32_masklen(ln->optx);
        !           536:     add_network(oa, prefix, pxlen, act->dist, act, -1);
        !           537:   }
        !           538: 
        !           539:   cnt = lsa_net_count(&act->lsa);
        !           540:   for (i = 0; i < cnt; i++)
        !           541:   {
        !           542:     tmp = ospf_hash_find_rt(p->gr, oa->areaid, ln->routers[i]);
        !           543:     add_cand(&oa->cand, tmp, act, act->dist, oa, -1);
        !           544:   }
        !           545: }
        !           546: 
        !           547: static inline void
        !           548: spfa_process_prefixes(struct ospf_proto *p, struct ospf_area *oa)
        !           549: {
        !           550:   struct top_hash_entry *en, *src;
        !           551:   struct ospf_lsa_prefix *px;
        !           552:   ip_addr pxa;
        !           553:   int pxlen;
        !           554:   u8 pxopts;
        !           555:   u16 metric;
        !           556:   u32 *buf;
        !           557:   int i;
        !           558: 
        !           559:   WALK_SLIST(en, p->lsal)
        !           560:   {
        !           561:     if (en->lsa_type != LSA_T_PREFIX)
        !           562:       continue;
        !           563: 
        !           564:     if (en->domain != oa->areaid)
        !           565:       continue;
        !           566: 
        !           567:     if (en->lsa.age == LSA_MAXAGE)
        !           568:       continue;
        !           569: 
        !           570:     px = en->lsa_body;
        !           571: 
        !           572:     /* For router prefix-LSA, we would like to find the first router-LSA */
        !           573:     if (px->ref_type == LSA_T_RT)
        !           574:       src = ospf_hash_find_rt(p->gr, oa->areaid, px->ref_rt);
        !           575:     else
        !           576:       src = ospf_hash_find(p->gr, oa->areaid, px->ref_id, px->ref_rt, px->ref_type);
        !           577: 
        !           578:     if (!src)
        !           579:       continue;
        !           580: 
        !           581:     /* Reachable in SPF */
        !           582:     if (src->color != INSPF)
        !           583:       continue;
        !           584: 
        !           585:     if ((src->lsa_type != LSA_T_RT) && (src->lsa_type != LSA_T_NET))
        !           586:       continue;
        !           587: 
        !           588:     buf = px->rest;
        !           589:     for (i = 0; i < px->pxcount; i++)
        !           590:       {
        !           591:        buf = lsa_get_ipv6_prefix(buf, &pxa, &pxlen, &pxopts, &metric);
        !           592: 
        !           593:        if (pxopts & OPT_PX_NU)
        !           594:          continue;
        !           595: 
        !           596:        /* Store the first global address to use it later as a vlink endpoint */
        !           597:        if ((pxopts & OPT_PX_LA) && ipa_zero(src->lb))
        !           598:          src->lb = pxa;
        !           599: 
        !           600:        add_network(oa, pxa, pxlen, src->dist + metric, src, i);
        !           601:       }
        !           602:   }
        !           603: }
        !           604: 
        !           605: /* RFC 2328 16.1. calculating shortest paths for an area */
        !           606: static void
        !           607: ospf_rt_spfa(struct ospf_area *oa)
        !           608: {
        !           609:   struct ospf_proto *p = oa->po;
        !           610:   struct top_hash_entry *act;
        !           611:   node *n;
        !           612: 
        !           613:   if (oa->rt == NULL)
        !           614:     return;
        !           615:   if (oa->rt->lsa.age == LSA_MAXAGE)
        !           616:     return;
        !           617: 
        !           618:   OSPF_TRACE(D_EVENTS, "Starting routing table calculation for area %R", oa->areaid);
        !           619: 
        !           620:   /* 16.1. (1) */
        !           621:   init_list(&oa->cand);                /* Empty list of candidates */
        !           622:   oa->trcap = 0;
        !           623: 
        !           624:   DBG("LSA db prepared, adding me into candidate list.\n");
        !           625: 
        !           626:   oa->rt->dist = 0;
        !           627:   oa->rt->color = CANDIDATE;
        !           628:   add_head(&oa->cand, &oa->rt->cn);
        !           629:   DBG("RT LSA: rt: %R, id: %R, type: %u\n",
        !           630:       oa->rt->lsa.rt, oa->rt->lsa.id, oa->rt->lsa_type);
        !           631: 
        !           632:   while (!EMPTY_LIST(oa->cand))
        !           633:   {
        !           634:     n = HEAD(oa->cand);
        !           635:     act = SKIP_BACK(struct top_hash_entry, cn, n);
        !           636:     rem_node(n);
        !           637: 
        !           638:     DBG("Working on LSA: rt: %R, id: %R, type: %u\n",
        !           639:        act->lsa.rt, act->lsa.id, act->lsa_type);
        !           640: 
        !           641:     act->color = INSPF;
        !           642:     switch (act->lsa_type)
        !           643:     {
        !           644:     case LSA_T_RT:
        !           645:       spfa_process_rt(p, oa, act);
        !           646:       break;
        !           647: 
        !           648:     case LSA_T_NET:
        !           649:       spfa_process_net(p, oa, act);
        !           650:       break;
        !           651: 
        !           652:     default:
        !           653:       log(L_WARN "%s: Unknown LSA type in SPF: %d", p->p.name, act->lsa_type);
        !           654:     }
        !           655:   }
        !           656: 
        !           657:   if (ospf_is_v3(p))
        !           658:     spfa_process_prefixes(p, oa);
        !           659: }
        !           660: 
        !           661: static int
        !           662: link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par)
        !           663: {
        !           664:   struct ospf_proto *p = oa->po;
        !           665:   struct ospf_lsa_rt_walk rtl;
        !           666:   struct top_hash_entry *tmp;
        !           667:   struct ospf_lsa_net *ln;
        !           668:   u32 i, cnt;
        !           669: 
        !           670:   if (!en || !par) return 0;
        !           671: 
        !           672:   /* We should check whether there is a link back from en to par,
        !           673:      this is used in SPF calc (RFC 2328 16.1. (2b)). According to RFC 2328
        !           674:      note 23, we don't have to find the same link that is used for par
        !           675:      to en, any link is enough. This we do for ptp links. For net-rt
        !           676:      links, we have to find the same link to compute proper lb/lb_id,
        !           677:      which may be later used as the next hop. */
        !           678: 
        !           679:   /* In OSPFv2, en->lb is set here. In OSPFv3, en->lb is just cleared here,
        !           680:      it is set in process_prefixes() to any global address in the area */
        !           681: 
        !           682:   en->lb = IPA_NONE;
        !           683:   en->lb_id = 0;
        !           684: 
        !           685:   switch (en->lsa_type)
        !           686:   {
        !           687:   case LSA_T_RT:
        !           688:     lsa_walk_rt_init(p, en, &rtl);
        !           689:     while (lsa_walk_rt(&rtl))
        !           690:     {
        !           691:       switch (rtl.type)
        !           692:       {
        !           693:       case LSART_STUB:
        !           694:        break;
        !           695: 
        !           696:       case LSART_NET:
        !           697:        tmp = ospf_hash_find_net(p->gr, oa->areaid, rtl.id, rtl.nif);
        !           698:        if (tmp == par)
        !           699:        {
        !           700:          if (ospf_is_v2(p))
        !           701:            en->lb = ipa_from_u32(rtl.data);
        !           702:          else
        !           703:            en->lb_id = rtl.lif;
        !           704: 
        !           705:          return 1;
        !           706:        }
        !           707:        break;
        !           708: 
        !           709:       case LSART_VLNK:
        !           710:       case LSART_PTP:
        !           711:        /* Not necessary the same link, see RFC 2328 [23] */
        !           712:        tmp = ospf_hash_find_rt(p->gr, oa->areaid, rtl.id);
        !           713:        if (tmp == par)
        !           714:          return 1;
        !           715:        break;
        !           716:       }
        !           717:     }
        !           718:     break;
        !           719: 
        !           720:   case LSA_T_NET:
        !           721:     ln = en->lsa_body;
        !           722:     cnt = lsa_net_count(&en->lsa);
        !           723:     for (i = 0; i < cnt; i++)
        !           724:     {
        !           725:       tmp = ospf_hash_find_rt(p->gr, oa->areaid, ln->routers[i]);
        !           726:       if (tmp == par)
        !           727:        return 1;
        !           728:     }
        !           729:     break;
        !           730: 
        !           731:   default:
        !           732:     log(L_WARN "%s: Unknown LSA type in SPF: %d", p->p.name, en->lsa_type);
        !           733:   }
        !           734:   return 0;
        !           735: }
        !           736: 
        !           737: 
        !           738: /* RFC 2328 16.2. calculating inter-area routes */
        !           739: static void
        !           740: ospf_rt_sum(struct ospf_area *oa)
        !           741: {
        !           742:   struct ospf_proto *p = oa->po;
        !           743:   struct top_hash_entry *en;
        !           744:   ip_addr ip, abrip;
        !           745:   u32 dst_rid, metric, options;
        !           746:   ort *abr;
        !           747:   int pxlen = -1, type = -1;
        !           748:   u8 pxopts;
        !           749: 
        !           750: 
        !           751:   OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid);
        !           752: 
        !           753:   WALK_SLIST(en, p->lsal)
        !           754:   {
        !           755:     if ((en->lsa_type != LSA_T_SUM_RT) && (en->lsa_type != LSA_T_SUM_NET))
        !           756:       continue;
        !           757: 
        !           758:     if (en->domain != oa->areaid)
        !           759:       continue;
        !           760: 
        !           761:     /* 16.2. (1a) */
        !           762:     if (en->lsa.age == LSA_MAXAGE)
        !           763:       continue;
        !           764: 
        !           765:     /* 16.2. (2) */
        !           766:     if (en->lsa.rt == p->router_id)
        !           767:       continue;
        !           768: 
        !           769:     /* 16.2. (3) is handled later in ospf_rt_abr() by resetting such rt entry */
        !           770: 
        !           771:     if (en->lsa_type == LSA_T_SUM_NET)
        !           772:     {
        !           773:       lsa_parse_sum_net(en, ospf_is_v2(p), &ip, &pxlen, &pxopts, &metric);
        !           774: 
        !           775:       if (pxopts & OPT_PX_NU)
        !           776:        continue;
        !           777: 
        !           778:       if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
        !           779:       {
        !           780:        log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
        !           781:            p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
        !           782:        continue;
        !           783:       }
        !           784: 
        !           785:       options = 0;
        !           786:       type = ORT_NET;
        !           787:     }
        !           788:     else /* LSA_T_SUM_RT */
        !           789:     {
        !           790:       lsa_parse_sum_rt(en, ospf_is_v2(p), &dst_rid, &metric, &options);
        !           791: 
        !           792:       /* We don't want local router in ASBR routing table */
        !           793:       if (dst_rid == p->router_id)
        !           794:        continue;
        !           795: 
        !           796:       options |= ORTA_ASBR;
        !           797:       type = ORT_ROUTER;
        !           798:     }
        !           799: 
        !           800:     /* 16.2. (1b) */
        !           801:     if (metric == LSINFINITY)
        !           802:       continue;
        !           803: 
        !           804:     /* 16.2. (4) */
        !           805:     abrip = ipa_from_rid(en->lsa.rt);
        !           806:     abr = (ort *) fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH);
        !           807:     if (!abr || !abr->n.type)
        !           808:       continue;
        !           809: 
        !           810:     if (!(abr->n.options & ORTA_ABR))
        !           811:       continue;
        !           812: 
        !           813:     /* This check is not mentioned in RFC 2328 */
        !           814:     if (abr->n.type != RTS_OSPF)
        !           815:       continue;
        !           816: 
        !           817:     /* 16.2. (5) */
        !           818:     orta nf = {
        !           819:       .type = RTS_OSPF_IA,
        !           820:       .options = options,
        !           821:       .metric1 = abr->n.metric1 + metric,
        !           822:       .metric2 = LSINFINITY,
        !           823:       .tag = 0,
        !           824:       .rid = en->lsa.rt, /* ABR ID */
        !           825:       .oa = oa,
        !           826:       .nhs = abr->n.nhs
        !           827:     };
        !           828: 
        !           829:     if (type == ORT_NET)
        !           830:       ri_install_net(p, ip, pxlen, &nf);
        !           831:     else
        !           832:       ri_install_rt(oa, dst_rid, &nf);
        !           833:   }
        !           834: }
        !           835: 
        !           836: /* RFC 2328 16.3. examining summary-LSAs in transit areas */
        !           837: static void
        !           838: ospf_rt_sum_tr(struct ospf_area *oa)
        !           839: {
        !           840:   struct ospf_proto *p = oa->po;
        !           841:   struct ospf_area *bb = p->backbone;
        !           842:   struct top_hash_entry *en;
        !           843:   ort *re, *abr;
        !           844:   ip_addr ip, abrip;
        !           845:   u32 dst_rid, metric, options;
        !           846:   int pxlen;
        !           847:   u8 pxopts;
        !           848: 
        !           849: 
        !           850:   if (!bb)
        !           851:     return;
        !           852: 
        !           853:   WALK_SLIST(en, p->lsal)
        !           854:   {
        !           855:     if ((en->lsa_type != LSA_T_SUM_RT) && (en->lsa_type != LSA_T_SUM_NET))
        !           856:       continue;
        !           857: 
        !           858:     if (en->domain != oa->areaid)
        !           859:       continue;
        !           860: 
        !           861:     /* 16.3 (1a) */
        !           862:     if (en->lsa.age == LSA_MAXAGE)
        !           863:       continue;
        !           864: 
        !           865:     /* 16.3 (2) */
        !           866:     if (en->lsa.rt == p->router_id)
        !           867:       continue;
        !           868: 
        !           869:     if (en->lsa_type == LSA_T_SUM_NET)
        !           870:     {
        !           871:       lsa_parse_sum_net(en, ospf_is_v2(p), &ip, &pxlen, &pxopts, &metric);
        !           872: 
        !           873:       if (pxopts & OPT_PX_NU)
        !           874:        continue;
        !           875: 
        !           876:       if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
        !           877:       {
        !           878:        log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
        !           879:            p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
        !           880:        continue;
        !           881:       }
        !           882: 
        !           883:       re = fib_find(&p->rtf, &ip, pxlen);
        !           884:     }
        !           885:     else // en->lsa_type == LSA_T_SUM_RT
        !           886:     {
        !           887:       lsa_parse_sum_rt(en, ospf_is_v2(p), &dst_rid, &metric, &options);
        !           888: 
        !           889:       ip = ipa_from_rid(dst_rid);
        !           890:       re = fib_find(&bb->rtr, &ip, MAX_PREFIX_LENGTH);
        !           891:     }
        !           892: 
        !           893:     /* 16.3 (1b) */
        !           894:     if (metric == LSINFINITY)
        !           895:       continue;
        !           896: 
        !           897:     /* 16.3 (3) */
        !           898:     if (!re || !re->n.type)
        !           899:       continue;
        !           900: 
        !           901:     if (re->n.oa->areaid != 0)
        !           902:       continue;
        !           903: 
        !           904:     if ((re->n.type != RTS_OSPF) && (re->n.type != RTS_OSPF_IA))
        !           905:       continue;
        !           906: 
        !           907:     /* 16.3. (4) */
        !           908:     abrip = ipa_from_rid(en->lsa.rt);
        !           909:     abr = fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH);
        !           910:     if (!abr || !abr->n.type)
        !           911:       continue;
        !           912: 
        !           913:     metric = abr->n.metric1 + metric; /* IAC */
        !           914: 
        !           915:     /* 16.3. (5) */
        !           916:     if ((metric < re->n.metric1) ||
        !           917:        ((metric == re->n.metric1) && unresolved_vlink(re)))
        !           918:     {
        !           919:       /* We want to replace the next-hop even if the metric is equal
        !           920:         to replace a virtual next-hop through vlink with a real one.
        !           921:         Proper ECMP would merge nexthops here, but we do not do that.
        !           922:         We restrict nexthops to fit one area to simplify check
        !           923:         12.4.3 p4 in decide_sum_lsa() */
        !           924: 
        !           925:       re->n.metric1 = metric;
        !           926:       re->n.voa = oa;
        !           927:       re->n.nhs = abr->n.nhs;
        !           928:     }
        !           929:   }
        !           930: }
        !           931: 
        !           932: /* Decide about originating or flushing summary LSAs for condensed area networks */
        !           933: static int
        !           934: decide_anet_lsa(struct ospf_area *oa, struct area_net *anet, struct ospf_area *anet_oa)
        !           935: {
        !           936:   /* 12.4.3.1. - for stub/NSSA areas, originating summary routes is configurable */
        !           937:   if (!oa_is_ext(oa) && !oa->ac->summary)
        !           938:     return 0;
        !           939: 
        !           940:   if (oa == anet_oa)
        !           941:     return 0;
        !           942: 
        !           943:   /* Do not condense routing info when exporting from backbone to the transit area */
        !           944:   if ((anet_oa == oa->po->backbone) && oa->trcap)
        !           945:     return 0;
        !           946: 
        !           947:   return (anet->active && !anet->hidden);
        !           948: }
        !           949: 
        !           950: /* Decide about originating or flushing summary LSAs (12.4.3) */
        !           951: static int
        !           952: decide_sum_lsa(struct ospf_area *oa, ort *nf, int dest)
        !           953: {
        !           954:   /* 12.4.3.1. - for stub/NSSA areas, originating summary routes is configurable */
        !           955:   if (!oa_is_ext(oa) && !oa->ac->summary)
        !           956:     return 0;
        !           957: 
        !           958:   /* Invalid field - no route */
        !           959:   if (!nf->n.type)
        !           960:     return 0;
        !           961: 
        !           962:   /* 12.4.3 p2 */
        !           963:   if (nf->n.type > RTS_OSPF_IA)
        !           964:     return 0;
        !           965: 
        !           966:   /* 12.4.3 p3 */
        !           967:   if ((nf->n.oa->areaid == oa->areaid))
        !           968:     return 0;
        !           969: 
        !           970:   /* 12.4.3 p4 */
        !           971:   if (nf->n.voa && (nf->n.voa->areaid == oa->areaid))
        !           972:     return 0;
        !           973: 
        !           974:   /* 12.4.3 p5 */
        !           975:   if (nf->n.metric1 >= LSINFINITY)
        !           976:     return 0;
        !           977: 
        !           978:   /* 12.4.3 p6 - AS boundary router */
        !           979:   if (dest == ORT_ROUTER)
        !           980:   {
        !           981:     /* We call decide_sum_lsa() on preferred ASBR entries, no need for 16.4. (3) */
        !           982:     /* 12.4.3 p1 */
        !           983:     return oa_is_ext(oa) && (nf->n.options & ORTA_ASBR);
        !           984:   }
        !           985: 
        !           986:   /* 12.4.3 p7 - inter-area route */
        !           987:   if (nf->n.type == RTS_OSPF_IA)
        !           988:   {
        !           989:     /* Inter-area routes are not repropagated into the backbone */
        !           990:     return (oa != oa->po->backbone);
        !           991:   }
        !           992: 
        !           993:   /* 12.4.3 p8 - intra-area route */
        !           994: 
        !           995:   /* Do not condense routing info when exporting from backbone to the transit area */
        !           996:   if ((nf->n.oa == oa->po->backbone) && oa->trcap)
        !           997:     return 1;
        !           998: 
        !           999:   struct area_net *anet = (struct area_net *)
        !          1000:     fib_route(&nf->n.oa->net_fib, nf->fn.prefix, nf->fn.pxlen);
        !          1001: 
        !          1002:   /* Condensed area network found */
        !          1003:   if (anet)
        !          1004:     return 0;
        !          1005: 
        !          1006:   return 1;
        !          1007: }
        !          1008: 
        !          1009: /* RFC 2328 16.7. p1 - originate or flush summary LSAs */
        !          1010: static inline void
        !          1011: check_sum_net_lsa(struct ospf_proto *p, ort *nf)
        !          1012: {
        !          1013:   struct area_net *anet = NULL;
        !          1014:   struct ospf_area *anet_oa = NULL;
        !          1015: 
        !          1016:   if (nf->area_net)
        !          1017:   {
        !          1018:     /* It is a default route for stub areas, handled entirely in ospf_rt_abr() */
        !          1019:     if (nf->fn.pxlen == 0)
        !          1020:       return;
        !          1021: 
        !          1022:     /* Find that area network */
        !          1023:     WALK_LIST(anet_oa, p->area_list)
        !          1024:     {
        !          1025:       anet = (struct area_net *) fib_find(&anet_oa->net_fib, &nf->fn.prefix, nf->fn.pxlen);
        !          1026:       if (anet)
        !          1027:        break;
        !          1028:     }
        !          1029:   }
        !          1030: 
        !          1031:   struct ospf_area *oa;
        !          1032:   WALK_LIST(oa, p->area_list)
        !          1033:   {
        !          1034:     if (anet && decide_anet_lsa(oa, anet, anet_oa))
        !          1035:       ospf_originate_sum_net_lsa(p, oa, nf, anet->metric);
        !          1036:     else if (decide_sum_lsa(oa, nf, ORT_NET))
        !          1037:       ospf_originate_sum_net_lsa(p, oa, nf, nf->n.metric1);
        !          1038:   }
        !          1039: }
        !          1040: 
        !          1041: static inline void
        !          1042: check_sum_rt_lsa(struct ospf_proto *p, ort *nf)
        !          1043: {
        !          1044:   struct ospf_area *oa;
        !          1045:   WALK_LIST(oa, p->area_list)
        !          1046:     if (decide_sum_lsa(oa, nf, ORT_ROUTER))
        !          1047:       ospf_originate_sum_rt_lsa(p, oa, nf, nf->n.metric1, nf->n.options);
        !          1048: }
        !          1049: 
        !          1050: static inline int
        !          1051: decide_nssa_lsa(struct ospf_proto *p UNUSED4 UNUSED6, ort *nf, struct ospf_lsa_ext_local *rt)
        !          1052: {
        !          1053:   struct ospf_area *oa = nf->n.oa;
        !          1054:   struct top_hash_entry *en = nf->n.en;
        !          1055: 
        !          1056:   if (!rt_is_nssa(nf) || !oa->translate)
        !          1057:     return 0;
        !          1058: 
        !          1059:   /* Condensed area network found */
        !          1060:   if (fib_route(&oa->enet_fib, nf->fn.prefix, nf->fn.pxlen))
        !          1061:     return 0;
        !          1062: 
        !          1063:   if (!en || (en->lsa_type != LSA_T_NSSA))
        !          1064:     return 0;
        !          1065: 
        !          1066:   /* We do not store needed data in struct orta, we have to parse the LSA */
        !          1067:   lsa_parse_ext(en, ospf_is_v2(p), rt);
        !          1068: 
        !          1069:   if (rt->pxopts & OPT_PX_NU)
        !          1070:     return 0;
        !          1071: 
        !          1072:   if (!rt->propagate || ipa_zero(rt->fwaddr))
        !          1073:     return 0;
        !          1074: 
        !          1075:   return 1;
        !          1076: }
        !          1077: 
        !          1078: /* RFC 3103 3.2 - translating Type-7 LSAs into Type-5 LSAs */
        !          1079: static inline void
        !          1080: check_nssa_lsa(struct ospf_proto *p, ort *nf)
        !          1081: {
        !          1082:   struct area_net *anet = NULL;
        !          1083:   struct ospf_area *oa = NULL;
        !          1084:   struct ospf_lsa_ext_local rt;
        !          1085: 
        !          1086:   /* Do not translate LSA if there is already the external LSA from route export */
        !          1087:   if (nf->external_rte)
        !          1088:     return;
        !          1089: 
        !          1090:   if (nf->area_net)
        !          1091:   {
        !          1092:     /* Find that area network */
        !          1093:     WALK_LIST(oa, p->area_list)
        !          1094:     {
        !          1095:       anet = (struct area_net *) fib_find(&oa->enet_fib, &nf->fn.prefix, nf->fn.pxlen);
        !          1096:       if (anet)
        !          1097:        break;
        !          1098:     }
        !          1099:   }
        !          1100: 
        !          1101:   /* RFC 3103 3.2 (3) - originate the aggregated address range */
        !          1102:   if (anet && anet->active && !anet->hidden && oa->translate)
        !          1103:     ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, anet->metric,
        !          1104:                           (anet->metric & LSA_EXT3_EBIT), IPA_NONE, anet->tag, 0);
        !          1105: 
        !          1106:   /* RFC 3103 3.2 (2) - originate the same network */
        !          1107:   else if (decide_nssa_lsa(p, nf, &rt))
        !          1108:     ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, rt.metric, rt.ebit, rt.fwaddr, rt.tag, 0);
        !          1109: }
        !          1110: 
        !          1111: /* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
        !          1112: static void
        !          1113: ospf_check_vlinks(struct ospf_proto *p)
        !          1114: {
        !          1115:   struct ospf_iface *ifa;
        !          1116:   WALK_LIST(ifa, p->iface_list)
        !          1117:   {
        !          1118:     if (ifa->type == OSPF_IT_VLINK)
        !          1119:     {
        !          1120:       struct top_hash_entry *tmp;
        !          1121:       tmp = ospf_hash_find_rt(p->gr, ifa->voa->areaid, ifa->vid);
        !          1122: 
        !          1123:       if (tmp && (tmp->color == INSPF) && ipa_nonzero(tmp->lb) && tmp->nhs)
        !          1124:       {
        !          1125:        struct ospf_iface *nhi = ospf_iface_find(p, tmp->nhs->iface);
        !          1126: 
        !          1127:        if ((ifa->state != OSPF_IS_PTP)
        !          1128:            || (ifa->vifa != nhi)
        !          1129:            || !ipa_equal(ifa->vip, tmp->lb))
        !          1130:        {
        !          1131:          OSPF_TRACE(D_EVENTS, "Vlink peer %R found", ifa->vid);
        !          1132:          ospf_iface_sm(ifa, ISM_DOWN);
        !          1133:          ifa->vifa = nhi;
        !          1134:          ifa->addr = nhi->addr;
        !          1135:          ifa->cost = tmp->dist;
        !          1136:          ifa->vip = tmp->lb;
        !          1137:          ospf_iface_sm(ifa, ISM_UP);
        !          1138:        }
        !          1139:        else if ((ifa->state == OSPF_IS_PTP) && (ifa->cost != tmp->dist))
        !          1140:        {
        !          1141:          ifa->cost = tmp->dist;
        !          1142: 
        !          1143:          /* RFC 2328 12.4 Event 8 - vlink state change */
        !          1144:          ospf_notify_rt_lsa(ifa->oa);
        !          1145:        }
        !          1146:       }
        !          1147:       else
        !          1148:       {
        !          1149:        if (ifa->state > OSPF_IS_DOWN)
        !          1150:        {
        !          1151:          OSPF_TRACE(D_EVENTS, "Vlink peer %R lost", ifa->vid);
        !          1152:          ospf_iface_sm(ifa, ISM_DOWN);
        !          1153:        }
        !          1154:       }
        !          1155:     }
        !          1156:   }
        !          1157: }
        !          1158: 
        !          1159: 
        !          1160: /* Miscellaneous route processing that needs to be done by ABRs */
        !          1161: static void
        !          1162: ospf_rt_abr1(struct ospf_proto *p)
        !          1163: {
        !          1164:   struct area_net *anet;
        !          1165:   ort *nf, *default_nf;
        !          1166: 
        !          1167:   /* RFC 2328 G.3 - incomplete resolution of virtual next hops - routers */
        !          1168:   FIB_WALK(&p->backbone->rtr, nftmp)
        !          1169:   {
        !          1170:     nf = (ort *) nftmp;
        !          1171: 
        !          1172:     if (nf->n.type && unresolved_vlink(nf))
        !          1173:       reset_ri(nf);
        !          1174:   }
        !          1175:   FIB_WALK_END;
        !          1176: 
        !          1177: 
        !          1178:   FIB_WALK(&p->rtf, nftmp)
        !          1179:   {
        !          1180:     nf = (ort *) nftmp;
        !          1181: 
        !          1182: 
        !          1183:     /* RFC 2328 G.3 - incomplete resolution of virtual next hops - networks */
        !          1184:     if (nf->n.type && unresolved_vlink(nf))
        !          1185:       reset_ri(nf);
        !          1186: 
        !          1187: 
        !          1188:     /* Compute condensed area networks */
        !          1189:     if (nf->n.type == RTS_OSPF)
        !          1190:     {
        !          1191:       anet = (struct area_net *) fib_route(&nf->n.oa->net_fib, nf->fn.prefix, nf->fn.pxlen);
        !          1192:       if (anet)
        !          1193:       {
        !          1194:        if (!anet->active)
        !          1195:        {
        !          1196:          anet->active = 1;
        !          1197: 
        !          1198:          /* Get a RT entry and mark it to know that it is an area network */
        !          1199:          ort *nfi = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen);
        !          1200:          nfi->area_net = 1;
        !          1201: 
        !          1202:          /* 16.2. (3) */
        !          1203:          if (nfi->n.type == RTS_OSPF_IA)
        !          1204:            reset_ri(nfi);
        !          1205:        }
        !          1206: 
        !          1207:        if (anet->metric < nf->n.metric1)
        !          1208:          anet->metric = nf->n.metric1;
        !          1209:       }
        !          1210:     }
        !          1211:   }
        !          1212:   FIB_WALK_END;
        !          1213: 
        !          1214:   ip_addr addr = IPA_NONE;
        !          1215:   default_nf = (ort *) fib_get(&p->rtf, &addr, 0);
        !          1216:   default_nf->area_net = 1;
        !          1217: 
        !          1218:   struct ospf_area *oa;
        !          1219:   WALK_LIST(oa, p->area_list)
        !          1220:   {
        !          1221: 
        !          1222:     /* 12.4.3.1. - originate or flush default route for stub/NSSA areas */
        !          1223:     if (oa_is_stub(oa) || (oa_is_nssa(oa) && !oa->ac->summary))
        !          1224:       ospf_originate_sum_net_lsa(p, oa, default_nf, oa->ac->default_cost);
        !          1225: 
        !          1226:     /*
        !          1227:      * Originate type-7 default route for NSSA areas
        !          1228:      *
        !          1229:      * Because type-7 default LSAs are originated by ABRs, they do not
        !          1230:      * collide with other type-7 LSAs (as ABRs generate type-5 LSAs
        !          1231:      * for both external route export or external-NSSA translation),
        !          1232:      * so we use 0 for the src arg.
        !          1233:      */
        !          1234: 
        !          1235:     if (oa_is_nssa(oa) && oa->ac->default_nssa)
        !          1236:       ospf_originate_ext_lsa(p, oa, default_nf, LSA_M_RTCALC, oa->ac->default_cost,
        !          1237:                             (oa->ac->default_cost & LSA_EXT3_EBIT), IPA_NONE, 0, 0);
        !          1238: 
        !          1239:     /* RFC 2328 16.4. (3) - precompute preferred ASBR entries */
        !          1240:     if (oa_is_ext(oa))
        !          1241:     {
        !          1242:       FIB_WALK(&oa->rtr, nftmp)
        !          1243:       {
        !          1244:        nf = (ort *) nftmp;
        !          1245:        if (nf->n.options & ORTA_ASBR)
        !          1246:          ri_install_asbr(p, &nf->fn.prefix, &nf->n);
        !          1247:       }
        !          1248:       FIB_WALK_END;
        !          1249:     }
        !          1250:   }
        !          1251: 
        !          1252: 
        !          1253:   /* Originate or flush ASBR summary LSAs */
        !          1254:   FIB_WALK(&p->backbone->rtr, nftmp)
        !          1255:   {
        !          1256:     check_sum_rt_lsa(p, (ort *) nftmp);
        !          1257:   }
        !          1258:   FIB_WALK_END;
        !          1259: 
        !          1260: 
        !          1261:   /* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
        !          1262:   ospf_check_vlinks(p);
        !          1263: }
        !          1264: 
        !          1265: 
        !          1266: static void
        !          1267: translator_timer_hook(timer *timer)
        !          1268: {
        !          1269:   struct ospf_area *oa = timer->data;
        !          1270: 
        !          1271:   if (oa->translate != TRANS_WAIT)
        !          1272:     return;
        !          1273: 
        !          1274:   oa->translate = TRANS_OFF;
        !          1275:   ospf_schedule_rtcalc(oa->po);
        !          1276: }
        !          1277: 
        !          1278: static void
        !          1279: ospf_rt_abr2(struct ospf_proto *p)
        !          1280: {
        !          1281:   struct ospf_area *oa;
        !          1282:   struct top_hash_entry *en;
        !          1283:   ort *nf, *nf2;
        !          1284: 
        !          1285: 
        !          1286:   /* RFC 3103 3.1 - type-7 translator election */
        !          1287:   struct ospf_area *bb = p->backbone;
        !          1288:   WALK_LIST(oa, p->area_list)
        !          1289:     if (oa_is_nssa(oa))
        !          1290:     {
        !          1291:       int translate = 1;
        !          1292: 
        !          1293:       if (oa->ac->translator)
        !          1294:        goto decided;
        !          1295: 
        !          1296:       FIB_WALK(&oa->rtr, nftmp)
        !          1297:       {
        !          1298:        nf = (ort *) nftmp;
        !          1299:        if (!nf->n.type || !(nf->n.options & ORTA_ABR))
        !          1300:          continue;
        !          1301: 
        !          1302:        nf2 = fib_find(&bb->rtr, &nf->fn.prefix, MAX_PREFIX_LENGTH);
        !          1303:        if (!nf2 || !nf2->n.type || !(nf2->n.options & ORTA_ABR))
        !          1304:          continue;
        !          1305: 
        !          1306:        en = ospf_hash_find_rt(p->gr, oa->areaid, nf->n.rid);
        !          1307:        if (!en || (en->color != INSPF))
        !          1308:          continue;
        !          1309: 
        !          1310:        struct ospf_lsa_rt *rt = en->lsa_body;
        !          1311:        /* There is better candidate - Nt-bit or higher Router ID */
        !          1312:        if ((rt->options & OPT_RT_NT) || (p->router_id < nf->n.rid))
        !          1313:        {
        !          1314:          translate = 0;
        !          1315:          goto decided;
        !          1316:        }
        !          1317:       }
        !          1318:       FIB_WALK_END;
        !          1319: 
        !          1320:     decided:
        !          1321:       if (translate && (oa->translate != TRANS_ON))
        !          1322:       {
        !          1323:        if (oa->translate == TRANS_WAIT)
        !          1324:          tm_stop(oa->translator_timer);
        !          1325: 
        !          1326:        oa->translate = TRANS_ON;
        !          1327:       }
        !          1328: 
        !          1329:       if (!translate && (oa->translate == TRANS_ON))
        !          1330:       {
        !          1331:        if (oa->translator_timer == NULL)
        !          1332:          oa->translator_timer = tm_new_set(p->p.pool, translator_timer_hook, oa, 0, 0);
        !          1333: 
        !          1334:        /* Schedule the end of translation */
        !          1335:        tm_start(oa->translator_timer, oa->ac->transint);
        !          1336:        oa->translate = TRANS_WAIT;
        !          1337:       }
        !          1338:     }
        !          1339: 
        !          1340: 
        !          1341:   /* Compute condensed external networks */
        !          1342:   FIB_WALK(&p->rtf, nftmp)
        !          1343:   {
        !          1344:     nf = (ort *) nftmp;
        !          1345:     if (rt_is_nssa(nf) && (nf->n.options & ORTA_PROP))
        !          1346:     {
        !          1347:       struct area_net *anet = (struct area_net *)
        !          1348:        fib_route(&nf->n.oa->enet_fib, nf->fn.prefix, nf->fn.pxlen);
        !          1349: 
        !          1350:       if (anet)
        !          1351:       {
        !          1352:        if (!anet->active)
        !          1353:        {
        !          1354:          anet->active = 1;
        !          1355: 
        !          1356:          /* Get a RT entry and mark it to know that it is an area network */
        !          1357:          nf2 = (ort *) fib_get(&p->rtf, &anet->fn.prefix, anet->fn.pxlen);
        !          1358:          nf2->area_net = 1;
        !          1359:        }
        !          1360: 
        !          1361:        u32 metric = (nf->n.type == RTS_OSPF_EXT1) ?
        !          1362:          nf->n.metric1 : ((nf->n.metric2 + 1) | LSA_EXT3_EBIT);
        !          1363: 
        !          1364:        if (anet->metric < metric)
        !          1365:          anet->metric = metric;
        !          1366:       }
        !          1367:     }
        !          1368:   }
        !          1369:   FIB_WALK_END;
        !          1370: 
        !          1371: 
        !          1372:   FIB_WALK(&p->rtf, nftmp)
        !          1373:   {
        !          1374:     nf = (ort *) nftmp;
        !          1375: 
        !          1376:     check_sum_net_lsa(p, nf);
        !          1377:     check_nssa_lsa(p, nf);
        !          1378:   }
        !          1379:   FIB_WALK_END;
        !          1380: }
        !          1381: 
        !          1382: 
        !          1383: /* Like fib_route(), but ignores dummy rt entries */
        !          1384: static void *
        !          1385: ospf_fib_route(struct fib *f, ip_addr a, int len)
        !          1386: {
        !          1387:   ip_addr a0;
        !          1388:   ort *nf;
        !          1389: 
        !          1390:   while (len >= 0)
        !          1391:   {
        !          1392:     a0 = ipa_and(a, ipa_mkmask(len));
        !          1393:     nf = fib_find(f, &a0, len);
        !          1394:     if (nf && nf->n.type)
        !          1395:       return nf;
        !          1396:     len--;
        !          1397:   }
        !          1398:   return NULL;
        !          1399: }
        !          1400: 
        !          1401: /* RFC 2328 16.4. calculating external routes */
        !          1402: static void
        !          1403: ospf_ext_spf(struct ospf_proto *p)
        !          1404: {
        !          1405:   struct top_hash_entry *en;
        !          1406:   struct ospf_lsa_ext_local rt;
        !          1407:   ort *nf1, *nf2;
        !          1408:   ip_addr rtid;
        !          1409:   u32 br_metric;
        !          1410:   struct ospf_area *atmp;
        !          1411: 
        !          1412:   OSPF_TRACE(D_EVENTS, "Starting routing table calculation for ext routes");
        !          1413: 
        !          1414:   WALK_SLIST(en, p->lsal)
        !          1415:   {
        !          1416:     orta nfa = {};
        !          1417: 
        !          1418:     /* 16.4. (1) */
        !          1419:     if ((en->lsa_type != LSA_T_EXT) && (en->lsa_type != LSA_T_NSSA))
        !          1420:       continue;
        !          1421: 
        !          1422:     if (en->lsa.age == LSA_MAXAGE)
        !          1423:       continue;
        !          1424: 
        !          1425:     /* 16.4. (2) */
        !          1426:     if (en->lsa.rt == p->router_id)
        !          1427:       continue;
        !          1428: 
        !          1429:     DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n",
        !          1430:        p->p.name, en->lsa.id, en->lsa.rt, en->lsa_type);
        !          1431: 
        !          1432:     lsa_parse_ext(en, ospf_is_v2(p), &rt);
        !          1433: 
        !          1434:     if (rt.metric == LSINFINITY)
        !          1435:       continue;
        !          1436: 
        !          1437:     if (rt.pxopts & OPT_PX_NU)
        !          1438:       continue;
        !          1439: 
        !          1440:     if (rt.pxlen < 0 || rt.pxlen > MAX_PREFIX_LENGTH)
        !          1441:     {
        !          1442:       log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
        !          1443:          p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
        !          1444:       continue;
        !          1445:     }
        !          1446: 
        !          1447: 
        !          1448:     /* 16.4. (3) */
        !          1449:     /* If there are more areas, we already precomputed preferred ASBR
        !          1450:        entries in ospf_rt_abr1() and stored them in the backbone
        !          1451:        table. For NSSA, we examine the area to which the LSA is assigned */
        !          1452:     if (en->lsa_type == LSA_T_EXT)
        !          1453:       atmp = ospf_main_area(p);
        !          1454:     else /* NSSA */
        !          1455:       atmp = ospf_find_area(p, en->domain);
        !          1456: 
        !          1457:     if (!atmp)
        !          1458:       continue;                        /* Should not happen */
        !          1459: 
        !          1460:     rtid = ipa_from_rid(en->lsa.rt);
        !          1461:     nf1 = fib_find(&atmp->rtr, &rtid, MAX_PREFIX_LENGTH);
        !          1462: 
        !          1463:     if (!nf1 || !nf1->n.type)
        !          1464:       continue;                        /* No AS boundary router found */
        !          1465: 
        !          1466:     if (!(nf1->n.options & ORTA_ASBR))
        !          1467:       continue;                        /* It is not ASBR */
        !          1468: 
        !          1469:     /* 16.4. (3) NSSA - special rule for default routes */
        !          1470:     /* ABR should use default only if P-bit is set and summaries are active */
        !          1471:     if ((en->lsa_type == LSA_T_NSSA) && ipa_zero(rt.ip) && (rt.pxlen == 0) &&
        !          1472:        (p->areano > 1) && !(rt.propagate && atmp->ac->summary))
        !          1473:       continue;
        !          1474: 
        !          1475:     if (!rt.fbit)
        !          1476:     {
        !          1477:       nf2 = nf1;
        !          1478:       nfa.nhs = nf1->n.nhs;
        !          1479:       br_metric = nf1->n.metric1;
        !          1480:     }
        !          1481:     else
        !          1482:     {
        !          1483:       nf2 = ospf_fib_route(&p->rtf, rt.fwaddr, MAX_PREFIX_LENGTH);
        !          1484:       if (!nf2)
        !          1485:        continue;
        !          1486: 
        !          1487:       if (en->lsa_type == LSA_T_EXT)
        !          1488:       {
        !          1489:        /* For ext routes, we accept intra-area or inter-area routes */
        !          1490:        if ((nf2->n.type != RTS_OSPF) && (nf2->n.type != RTS_OSPF_IA))
        !          1491:          continue;
        !          1492:       }
        !          1493:       else /* NSSA */
        !          1494:       {
        !          1495:        /* For NSSA routes, we accept just intra-area in the same area */
        !          1496:        if ((nf2->n.type != RTS_OSPF) || (nf2->n.oa != atmp))
        !          1497:          continue;
        !          1498:       }
        !          1499: 
        !          1500:       /* Next-hop is a part of a configured stubnet */
        !          1501:       if (!nf2->n.nhs)
        !          1502:        continue;
        !          1503: 
        !          1504:       nfa.nhs = nf2->n.nhs;
        !          1505:       br_metric = nf2->n.metric1;
        !          1506: 
        !          1507:       /* Replace device nexthops with nexthops to forwarding address from LSA */
        !          1508:       if (has_device_nexthops(nfa.nhs))
        !          1509:       {
        !          1510:        nfa.nhs = fix_device_nexthops(p, nfa.nhs, rt.fwaddr);
        !          1511:        nfa.nhs_reuse = 1;
        !          1512:       }
        !          1513:     }
        !          1514: 
        !          1515:     if (rt.ebit)
        !          1516:     {
        !          1517:       nfa.type = RTS_OSPF_EXT2;
        !          1518:       nfa.metric1 = br_metric;
        !          1519:       nfa.metric2 = rt.metric;
        !          1520:     }
        !          1521:     else
        !          1522:     {
        !          1523:       nfa.type = RTS_OSPF_EXT1;
        !          1524:       nfa.metric1 = br_metric + rt.metric;
        !          1525:       nfa.metric2 = LSINFINITY;
        !          1526:     }
        !          1527: 
        !          1528:     /* Mark the LSA as reachable */
        !          1529:     en->color = INSPF;
        !          1530: 
        !          1531:     /* Whether the route is preferred in route selection according to 16.4.1 */
        !          1532:     nfa.options = epath_preferred(&nf2->n) ? ORTA_PREF : 0;
        !          1533:     if (en->lsa_type == LSA_T_NSSA)
        !          1534:     {
        !          1535:       nfa.options |= ORTA_NSSA;
        !          1536:       if (rt.propagate)
        !          1537:        nfa.options |= ORTA_PROP;
        !          1538:     }
        !          1539: 
        !          1540:     nfa.tag = rt.tag;
        !          1541:     nfa.rid = en->lsa.rt;
        !          1542:     nfa.oa = atmp; /* undefined in RFC 2328 */
        !          1543:     nfa.en = en; /* store LSA for later (NSSA processing) */
        !          1544: 
        !          1545:     ri_install_ext(p, rt.ip, rt.pxlen, &nfa);
        !          1546:   }
        !          1547: }
        !          1548: 
        !          1549: /* Cleanup of routing tables and data */
        !          1550: void
        !          1551: ospf_rt_reset(struct ospf_proto *p)
        !          1552: {
        !          1553:   struct ospf_area *oa;
        !          1554:   struct top_hash_entry *en;
        !          1555:   struct area_net *anet;
        !          1556:   ort *ri;
        !          1557: 
        !          1558:   /* Reset old routing table */
        !          1559:   FIB_WALK(&p->rtf, nftmp)
        !          1560:   {
        !          1561:     ri = (ort *) nftmp;
        !          1562:     ri->area_net = 0;
        !          1563:     ri->keep = 0;
        !          1564:     reset_ri(ri);
        !          1565:   }
        !          1566:   FIB_WALK_END;
        !          1567: 
        !          1568:   /* Reset SPF data in LSA db */
        !          1569:   WALK_SLIST(en, p->lsal)
        !          1570:   {
        !          1571:     en->color = OUTSPF;
        !          1572:     en->dist = LSINFINITY;
        !          1573:     en->nhs = NULL;
        !          1574:     en->lb = IPA_NONE;
        !          1575: 
        !          1576:     if (en->mode == LSA_M_RTCALC)
        !          1577:       en->mode = LSA_M_STALE;
        !          1578:   }
        !          1579: 
        !          1580:   WALK_LIST(oa, p->area_list)
        !          1581:   {
        !          1582:     /* Reset ASBR routing tables */
        !          1583:     FIB_WALK(&oa->rtr, nftmp)
        !          1584:     {
        !          1585:       ri = (ort *) nftmp;
        !          1586:       reset_ri(ri);
        !          1587:     }
        !          1588:     FIB_WALK_END;
        !          1589: 
        !          1590:     /* Reset condensed area networks */
        !          1591:     if (p->areano > 1)
        !          1592:     {
        !          1593:       FIB_WALK(&oa->net_fib, nftmp)
        !          1594:       {
        !          1595:        anet = (struct area_net *) nftmp;
        !          1596:        anet->active = 0;
        !          1597:        anet->metric = 0;
        !          1598:       }
        !          1599:       FIB_WALK_END;
        !          1600: 
        !          1601:       FIB_WALK(&oa->enet_fib, nftmp)
        !          1602:       {
        !          1603:        anet = (struct area_net *) nftmp;
        !          1604:        anet->active = 0;
        !          1605:        anet->metric = 0;
        !          1606:       }
        !          1607:       FIB_WALK_END;
        !          1608:     }
        !          1609:   }
        !          1610: }
        !          1611: 
        !          1612: /**
        !          1613:  * ospf_rt_spf - calculate internal routes
        !          1614:  * @p: OSPF protocol instance
        !          1615:  *
        !          1616:  * Calculation of internal paths in an area is described in 16.1 of RFC 2328.
        !          1617:  * It's based on Dijkstra's shortest path tree algorithms.
        !          1618:  * This function is invoked from ospf_disp().
        !          1619:  */
        !          1620: void
        !          1621: ospf_rt_spf(struct ospf_proto *p)
        !          1622: {
        !          1623:   struct ospf_area *oa;
        !          1624: 
        !          1625:   if (p->areano == 0)
        !          1626:     return;
        !          1627: 
        !          1628:   OSPF_TRACE(D_EVENTS, "Starting routing table calculation");
        !          1629: 
        !          1630:   /* 16. (1) */
        !          1631:   ospf_rt_reset(p);
        !          1632: 
        !          1633:   /* 16. (2) */
        !          1634:   WALK_LIST(oa, p->area_list)
        !          1635:     ospf_rt_spfa(oa);
        !          1636: 
        !          1637:   /* 16. (3) */
        !          1638:   ospf_rt_sum(ospf_main_area(p));
        !          1639: 
        !          1640:   /* 16. (4) */
        !          1641:   WALK_LIST(oa, p->area_list)
        !          1642:     if (oa->trcap && (oa->areaid != 0))
        !          1643:       ospf_rt_sum_tr(oa);
        !          1644: 
        !          1645:   if (p->areano > 1)
        !          1646:     ospf_rt_abr1(p);
        !          1647: 
        !          1648:   /* 16. (5) */
        !          1649:   ospf_ext_spf(p);
        !          1650: 
        !          1651:   if (p->areano > 1)
        !          1652:     ospf_rt_abr2(p);
        !          1653: 
        !          1654:   rt_sync(p);
        !          1655:   lp_flush(p->nhpool);
        !          1656: 
        !          1657:   p->calcrt = 0;
        !          1658: }
        !          1659: 
        !          1660: 
        !          1661: static inline int
        !          1662: inherit_nexthops(struct mpnh *pn)
        !          1663: {
        !          1664:   /* Proper nexthops (with defined GW) or dummy vlink nexthops (without iface) */
        !          1665:   return pn && (ipa_nonzero(pn->gw) || !pn->iface);
        !          1666: }
        !          1667: 
        !          1668: static struct mpnh *
        !          1669: calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
        !          1670:              struct top_hash_entry *par, int pos)
        !          1671: {
        !          1672:   struct ospf_proto *p = oa->po;
        !          1673:   struct mpnh *pn = par->nhs;
        !          1674:   struct ospf_iface *ifa;
        !          1675:   u32 rid = en->lsa.rt;
        !          1676: 
        !          1677:   /* 16.1.1. The next hop calculation */
        !          1678:   DBG("     Next hop calculating for id: %R rt: %R type: %u\n",
        !          1679:       en->lsa.id, en->lsa.rt, en->lsa_type);
        !          1680: 
        !          1681:   /* Usually, we inherit parent nexthops */
        !          1682:   if (inherit_nexthops(pn))
        !          1683:     return pn;
        !          1684: 
        !          1685:   /*
        !          1686:    * There are three cases:
        !          1687:    * 1) en is a local network (and par is root)
        !          1688:    * 2) en is a ptp or ptmp neighbor (and par is root)
        !          1689:    * 3) en is a bcast or nbma neighbor (and par is local network)
        !          1690:    */
        !          1691: 
        !          1692:   /* The first case - local network */
        !          1693:   if ((en->lsa_type == LSA_T_NET) && (par == oa->rt))
        !          1694:   {
        !          1695:     ifa = rt_pos_to_ifa(oa, pos);
        !          1696:     if (!ifa)
        !          1697:       return NULL;
        !          1698: 
        !          1699:     return new_nexthop(p, IPA_NONE, ifa->iface, ifa->ecmp_weight);
        !          1700:   }
        !          1701: 
        !          1702:   /* The second case - ptp or ptmp neighbor */
        !          1703:   if ((en->lsa_type == LSA_T_RT) && (par == oa->rt))
        !          1704:   {
        !          1705:     ifa = rt_pos_to_ifa(oa, pos);
        !          1706:     if (!ifa)
        !          1707:       return NULL;
        !          1708: 
        !          1709:     if (ifa->type == OSPF_IT_VLINK)
        !          1710:       return new_nexthop(p, IPA_NONE, NULL, 0);
        !          1711: 
        !          1712:     struct ospf_neighbor *m = find_neigh(ifa, rid);
        !          1713:     if (!m || (m->state != NEIGHBOR_FULL))
        !          1714:       return NULL;
        !          1715: 
        !          1716:     return new_nexthop(p, m->ip, ifa->iface, ifa->ecmp_weight);
        !          1717:   }
        !          1718: 
        !          1719:   /* The third case - bcast or nbma neighbor */
        !          1720:   if ((en->lsa_type == LSA_T_RT) && (par->lsa_type == LSA_T_NET))
        !          1721:   {
        !          1722:     /* par->nhi should be defined from parent's calc_next_hop() */
        !          1723:     if (!pn)
        !          1724:       goto bad;
        !          1725: 
        !          1726:     if (ospf_is_v2(p))
        !          1727:     {
        !          1728:       /*
        !          1729:        * In this case, next-hop is the same as link-back, which is
        !          1730:        * already computed in link_back().
        !          1731:        */
        !          1732:       if (ipa_zero(en->lb))
        !          1733:        goto bad;
        !          1734: 
        !          1735:       return new_nexthop(p, en->lb, pn->iface, pn->weight);
        !          1736:     }
        !          1737:     else /* OSPFv3 */
        !          1738:     {
        !          1739:       /*
        !          1740:        * Next-hop is taken from lladdr field of Link-LSA, en->lb_id
        !          1741:        * is computed in link_back().
        !          1742:        */
        !          1743:       struct top_hash_entry *lhe;
        !          1744:       lhe = ospf_hash_find(p->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK);
        !          1745: 
        !          1746:       if (!lhe)
        !          1747:        return NULL;
        !          1748: 
        !          1749:       struct ospf_lsa_link *llsa = lhe->lsa_body;
        !          1750: 
        !          1751:       if (ip6_zero(llsa->lladdr))
        !          1752:        return NULL;
        !          1753: 
        !          1754:       return new_nexthop(p, ipa_from_ip6(llsa->lladdr), pn->iface, pn->weight);
        !          1755:     }
        !          1756:   }
        !          1757: 
        !          1758:  bad:
        !          1759:   /* Probably bug or some race condition, we log it */
        !          1760:   log(L_ERR "%s: Unexpected case in next hop calculation", p->p.name);
        !          1761:   return NULL;
        !          1762: }
        !          1763: 
        !          1764: 
        !          1765: /* Add LSA into list of candidates in Dijkstra's algorithm */
        !          1766: static void
        !          1767: add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
        !          1768:         u32 dist, struct ospf_area *oa, int pos)
        !          1769: {
        !          1770:   struct ospf_proto *p = oa->po;
        !          1771:   node *prev, *n;
        !          1772:   int added = 0;
        !          1773:   struct top_hash_entry *act;
        !          1774: 
        !          1775:   /* 16.1. (2b) */
        !          1776:   if (en == NULL)
        !          1777:     return;
        !          1778:   if (en->lsa.age == LSA_MAXAGE)
        !          1779:     return;
        !          1780: 
        !          1781:   if (ospf_is_v3(p) && (en->lsa_type == LSA_T_RT))
        !          1782:   {
        !          1783:     /* In OSPFv3, check V6 flag */
        !          1784:     struct ospf_lsa_rt *rt = en->lsa_body;
        !          1785:     if (!(rt->options & OPT_V6))
        !          1786:       return;
        !          1787:   }
        !          1788: 
        !          1789:   /* 16.1. (2c) */
        !          1790:   if (en->color == INSPF)
        !          1791:     return;
        !          1792: 
        !          1793:   /* 16.1. (2d), also checks that dist < LSINFINITY */
        !          1794:   if (dist > en->dist)
        !          1795:     return;
        !          1796: 
        !          1797:   /* We should check whether there is a reverse link from en to par, */
        !          1798:   if (!link_back(oa, en, par))
        !          1799:     return;
        !          1800: 
        !          1801:   struct mpnh *nhs = calc_next_hop(oa, en, par, pos);
        !          1802:   if (!nhs)
        !          1803:   {
        !          1804:     log(L_WARN "%s: Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)",
        !          1805:        p->p.name, en->lsa_type, en->lsa.id, en->lsa.rt);
        !          1806:     return;
        !          1807:   }
        !          1808: 
        !          1809:   /* If en->dist > 0, we know that en->color == CANDIDATE and en->nhs is defined. */
        !          1810:   if ((dist == en->dist) && !nh_is_vlink(en->nhs))
        !          1811:   {
        !          1812:     /*
        !          1813:      * For multipath, we should merge nexthops. We merge regular nexthops only.
        !          1814:      * Dummy vlink nexthops are less preferred and handled as a special case.
        !          1815:      *
        !          1816:      * During merging, new nexthops (nhs) can be reused if they are not
        !          1817:      * inherited from the parent (i.e. they are allocated in calc_next_hop()).
        !          1818:      * Current nexthops (en->nhs) can be reused if they weren't inherited in
        !          1819:      * previous steps (that is stored in nhs_reuse, i.e. created by merging or
        !          1820:      * allocated in calc_next_hop()).
        !          1821:      *
        !          1822:      * Generally, a node first inherits shared nexthops from its parent and
        !          1823:      * later possibly gets reusable (private) copy during merging. This is more
        !          1824:      * or less same for both top_hash_entry nodes and orta nodes.
        !          1825:      *
        !          1826:      * Note that when a child inherits a private nexthop from its parent, it
        !          1827:      * should make the nexthop shared for both parent and child, while we only
        !          1828:      * update nhs_reuse for the child node. This makes nhs_reuse field for the
        !          1829:      * parent technically incorrect, but it is not a problem as parent's nhs
        !          1830:      * will not be modified (and nhs_reuse examined) afterwards.
        !          1831:      */
        !          1832: 
        !          1833:     /* Keep old ones */
        !          1834:     if (!p->ecmp || nh_is_vlink(nhs) || (nhs == en->nhs))
        !          1835:       return;
        !          1836: 
        !          1837:     /* Merge old and new */
        !          1838:     int new_reuse = (par->nhs != nhs);
        !          1839:     en->nhs = mpnh_merge(en->nhs, nhs, en->nhs_reuse, new_reuse, p->ecmp, p->nhpool);
        !          1840:     en->nhs_reuse = 1;
        !          1841:     return;
        !          1842:   }
        !          1843: 
        !          1844:   DBG("     Adding candidate: rt: %R, id: %R, type: %u\n",
        !          1845:       en->lsa.rt, en->lsa.id, en->lsa_type);
        !          1846: 
        !          1847:   if (en->color == CANDIDATE)
        !          1848:   {                            /* We found a shorter path */
        !          1849:     rem_node(&en->cn);
        !          1850:   }
        !          1851:   en->nhs = nhs;
        !          1852:   en->dist = dist;
        !          1853:   en->color = CANDIDATE;
        !          1854:   en->nhs_reuse = (par->nhs != nhs);
        !          1855: 
        !          1856:   prev = NULL;
        !          1857: 
        !          1858:   if (EMPTY_LIST(*l))
        !          1859:   {
        !          1860:     add_head(l, &en->cn);
        !          1861:   }
        !          1862:   else
        !          1863:   {
        !          1864:     WALK_LIST(n, *l)
        !          1865:     {
        !          1866:       act = SKIP_BACK(struct top_hash_entry, cn, n);
        !          1867:       if ((act->dist > dist) ||
        !          1868:          ((act->dist == dist) && (act->lsa_type == LSA_T_RT)))
        !          1869:       {
        !          1870:        if (prev == NULL)
        !          1871:          add_head(l, &en->cn);
        !          1872:        else
        !          1873:          insert_node(&en->cn, prev);
        !          1874:        added = 1;
        !          1875:        break;
        !          1876:       }
        !          1877:       prev = n;
        !          1878:     }
        !          1879: 
        !          1880:     if (!added)
        !          1881:     {
        !          1882:       add_tail(l, &en->cn);
        !          1883:     }
        !          1884:   }
        !          1885: }
        !          1886: 
        !          1887: static inline int
        !          1888: ort_changed(ort *nf, rta *nr)
        !          1889: {
        !          1890:   rta *or = nf->old_rta;
        !          1891:   return !or ||
        !          1892:     (nf->n.metric1 != nf->old_metric1) || (nf->n.metric2 != nf->old_metric2) ||
        !          1893:     (nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid) ||
        !          1894:     (nr->source != or->source) || (nr->dest != or->dest) ||
        !          1895:     (nr->iface != or->iface) || !ipa_equal(nr->gw, or->gw) ||
        !          1896:     !mpnh_same(nr->nexthops, or->nexthops);
        !          1897: }
        !          1898: 
        !          1899: static void
        !          1900: rt_sync(struct ospf_proto *p)
        !          1901: {
        !          1902:   struct top_hash_entry *en;
        !          1903:   struct fib_iterator fit;
        !          1904:   struct fib *fib = &p->rtf;
        !          1905:   ort *nf;
        !          1906:   struct ospf_area *oa;
        !          1907: 
        !          1908:   /* This is used for forced reload of routes */
        !          1909:   int reload = (p->calcrt == 2);
        !          1910: 
        !          1911:   OSPF_TRACE(D_EVENTS, "Starting routing table synchronisation");
        !          1912: 
        !          1913:   DBG("Now syncing my rt table with nest's\n");
        !          1914:   FIB_ITERATE_INIT(&fit, fib);
        !          1915: again1:
        !          1916:   FIB_ITERATE_START(fib, &fit, nftmp)
        !          1917:   {
        !          1918:     nf = (ort *) nftmp;
        !          1919: 
        !          1920:     /* Sanity check of next-hop addresses, failure should not happen */
        !          1921:     if (nf->n.type)
        !          1922:     {
        !          1923:       struct mpnh *nh;
        !          1924:       for (nh = nf->n.nhs; nh; nh = nh->next)
        !          1925:        if (ipa_nonzero(nh->gw))
        !          1926:        {
        !          1927:          neighbor *ng = neigh_find2(&p->p, &nh->gw, nh->iface, 0);
        !          1928:          if (!ng || (ng->scope == SCOPE_HOST))
        !          1929:            { reset_ri(nf); break; }
        !          1930:        }
        !          1931:     }
        !          1932: 
        !          1933:     /* Remove configured stubnets but keep the entries */
        !          1934:     if (nf->n.type && !nf->n.nhs)
        !          1935:     {
        !          1936:       reset_ri(nf);
        !          1937:       nf->keep = 1;
        !          1938:     }
        !          1939: 
        !          1940:     if (nf->n.type) /* Add the route */
        !          1941:     {
        !          1942:       rta a0 = {
        !          1943:        .src = p->p.main_source,
        !          1944:        .source = nf->n.type,
        !          1945:        .scope = SCOPE_UNIVERSE,
        !          1946:        .cast = RTC_UNICAST
        !          1947:       };
        !          1948: 
        !          1949:       if (nf->n.nhs->next)
        !          1950:       {
        !          1951:        a0.dest = RTD_MULTIPATH;
        !          1952:        a0.nexthops = nf->n.nhs;
        !          1953:       }
        !          1954:       else if (ipa_nonzero(nf->n.nhs->gw))
        !          1955:       {
        !          1956:        a0.dest = RTD_ROUTER;
        !          1957:        a0.iface = nf->n.nhs->iface;
        !          1958:        a0.gw = nf->n.nhs->gw;
        !          1959:       }
        !          1960:       else
        !          1961:       {
        !          1962:        a0.dest = RTD_DEVICE;
        !          1963:        a0.iface = nf->n.nhs->iface;
        !          1964:       }
        !          1965: 
        !          1966:       if (reload || ort_changed(nf, &a0))
        !          1967:       {
        !          1968:        net *ne = net_get(p->p.table, nf->fn.prefix, nf->fn.pxlen);
        !          1969:        rta *a = rta_lookup(&a0);
        !          1970:        rte *e = rte_get_temp(a);
        !          1971: 
        !          1972:        rta_free(nf->old_rta);
        !          1973:        nf->old_rta = rta_clone(a);
        !          1974:        e->u.ospf.metric1 = nf->old_metric1 = nf->n.metric1;
        !          1975:        e->u.ospf.metric2 = nf->old_metric2 = nf->n.metric2;
        !          1976:        e->u.ospf.tag = nf->old_tag = nf->n.tag;
        !          1977:        e->u.ospf.router_id = nf->old_rid = nf->n.rid;
        !          1978:        e->pflags = 0;
        !          1979:        e->net = ne;
        !          1980:        e->pref = p->p.preference;
        !          1981: 
        !          1982:        DBG("Mod rte type %d - %I/%d via %I on iface %s, met %d\n",
        !          1983:            a0.source, nf->fn.prefix, nf->fn.pxlen, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1);
        !          1984:        rte_update(&p->p, ne, e);
        !          1985:       }
        !          1986:     }
        !          1987:     else if (nf->old_rta)
        !          1988:     {
        !          1989:       /* Remove the route */
        !          1990:       rta_free(nf->old_rta);
        !          1991:       nf->old_rta = NULL;
        !          1992: 
        !          1993:       net *ne = net_get(p->p.table, nf->fn.prefix, nf->fn.pxlen);
        !          1994:       rte_update(&p->p, ne, NULL);
        !          1995:     }
        !          1996: 
        !          1997:     /* Remove unused rt entry, some special entries are persistent */
        !          1998:     if (!nf->n.type && !nf->external_rte && !nf->area_net && !nf->keep)
        !          1999:     {
        !          2000:       FIB_ITERATE_PUT(&fit, nftmp);
        !          2001:       fib_delete(fib, nftmp);
        !          2002:       goto again1;
        !          2003:     }
        !          2004:   }
        !          2005:   FIB_ITERATE_END(nftmp);
        !          2006: 
        !          2007: 
        !          2008:   WALK_LIST(oa, p->area_list)
        !          2009:   {
        !          2010:     /* Cleanup ASBR hash tables */
        !          2011:     FIB_ITERATE_INIT(&fit, &oa->rtr);
        !          2012: again2:
        !          2013:     FIB_ITERATE_START(&oa->rtr, &fit, nftmp)
        !          2014:     {
        !          2015:       nf = (ort *) nftmp;
        !          2016: 
        !          2017:       if (!nf->n.type)
        !          2018:       {
        !          2019:        FIB_ITERATE_PUT(&fit, nftmp);
        !          2020:        fib_delete(&oa->rtr, nftmp);
        !          2021:        goto again2;
        !          2022:       }
        !          2023:     }
        !          2024:     FIB_ITERATE_END(nftmp);
        !          2025:   }
        !          2026: 
        !          2027:   /* Cleanup stale LSAs */
        !          2028:   WALK_SLIST(en, p->lsal)
        !          2029:     if (en->mode == LSA_M_STALE)
        !          2030:       ospf_flush_lsa(p, en);
        !          2031: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>