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

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