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