rt.c 42 KB
Newer Older
1
/*
2 3 4 5 6
 * BIRD -- OSPF
 * 
 * (c) 2000--2004 Ondrej Filip <feela@network.cz>
 * 
 * Can be freely distributed and used under the terms of the GNU GPL.
7 8 9
 */

#include "ospf.h"
10

11 12
static void add_cand(list * l, struct top_hash_entry *en, 
		     struct top_hash_entry *par, u32 dist,
13
		     struct ospf_area *oa, int i);
14 15
static void rt_sync(struct proto_ospf *po);

16
/* In ospf_area->rtr we store paths to routers, but we use RID (and not IP address)
17
   as index, so we need to encapsulate RID to IP address */
18 19 20 21 22 23 24
#ifdef OSPFv2
#define ipa_from_rid(x) _MI(x)
#else /* OSPFv3 */
#define ipa_from_rid(x) _MI(0,0,0,x)
#endif


25
static inline void reset_ri(ort *ort)
26
{
27
  bzero(&ort->n, sizeof(orta));
28
}
29

30
void
31
ospf_rt_initort(struct fib_node *fn)
32
{
33
  ort *ri = (ort *) fn;
34 35
  reset_ri(ri);
  ri->old_rta = NULL;
36
  ri->fn.x0 = 0;
37
}
38

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
static inline int
unresolved_vlink(struct mpnh *nhs)
{
  return nhs && !nhs->iface;
}

static inline struct mpnh *
new_nexthop(struct proto_ospf *po, ip_addr gw, struct iface *iface, unsigned char weight)
{
  struct mpnh *nh = lp_alloc(po->nhpool, sizeof(struct mpnh));
  nh->gw = gw;
  nh->iface = iface;
  nh->next = NULL;
  nh->weight = weight;
  return nh;
}

static inline struct mpnh *
copy_nexthop(struct proto_ospf *po, struct mpnh *src)
{
  struct mpnh *nh = lp_alloc(po->nhpool, sizeof(struct mpnh));
  nh->gw = src->gw;
  nh->iface = src->iface;
  nh->next = NULL;
  nh->weight = src->weight;
  return nh;
}

Ondřej Filip's avatar
Ondřej Filip committed
67

68
/* If new is better return 1 */
69
static int
70
ri_better(struct proto_ospf *po, orta *new, orta *old)
71 72 73 74
{
  if (old->type == RTS_DUMMY)
    return 1;

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
  if (new->type < old->type)
    return 1;

  if (new->type > old->type)
    return 0;

  if (new->metric1 < old->metric1)
    return 1;

  if (new->metric1 > old->metric1)
    return 0;

  return 0;
}


91 92 93 94 95 96 97 98
/* Whether the ASBR or the forward address destination is preferred
   in AS external route selection according to 16.4.1. */
static inline int
epath_preferred(orta *ep)
{
  return (ep->type == RTS_OSPF) && (ep->oa->areaid != 0);
}

99 100 101 102
/* 16.4. (3), return 1 if new is better */
static int
ri_better_asbr(struct proto_ospf *po, orta *new, orta *old)
{
103 104
  if (old->type == RTS_DUMMY)
    return 1;
105 106

  if (!po->rfc1583)
107
  {
108 109 110 111 112 113 114 115
    int new_pref = epath_preferred(new);
    int old_pref = epath_preferred(old);

    if (new_pref > old_pref)
      return 1;

    if (new_pref < old_pref)
      return 0;
116
  }
Ondřej Filip's avatar
Ondřej Filip committed
117

118
  if (new->metric1 < old->metric1)
119 120
    return 1;

121
  if (new->metric1 > old->metric1)
Ondřej Filip's avatar
Ondřej Filip committed
122
    return 0;
123

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
  /* Larger area ID is preferred */
  if (new->oa->areaid > old->oa->areaid)
    return 1;

  return 0;
}

/* 16.4. (6), return 1 if new is better */
static int
ri_better_ext(struct proto_ospf *po, orta *new, orta *old)
{
  if (old->type == RTS_DUMMY)
    return 1;

  /* 16.4. (6a) */
  if (new->type < old->type)
    return 1;

  if (new->type > old->type)
    return 0;

  /* 16.4. (6b), same type */
146
  if (new->type == RTS_OSPF_EXT2)
Ondřej Filip's avatar
Ondřej Filip committed
147
  {
148 149 150 151 152
    if (new->metric2 < old->metric2)
      return 1;

    if (new->metric2 > old->metric2)
      return 0;
153
  }
Ondřej Filip's avatar
Ondřej Filip committed
154

155 156
  /* 16.4. (6c) */
  if (!po->rfc1583)
157
  {
158 159
    u32 new_pref = new->options & ORTA_PREF;
    u32 old_pref = old->options & ORTA_PREF;
Ondřej Filip's avatar
Ondřej Filip committed
160

161 162
    if (new_pref > old_pref)
      return 1;
163

164 165
    if (new_pref < old_pref)
      return 0;
166 167
  }

168
  /* 16.4. (6d) */
169 170 171 172 173 174
  if (new->metric1 < old->metric1)
    return 1;

  if (new->metric1 > old->metric1)
    return 0;

175 176
  /* RFC 3103, 2.5. (6e) - missing, is this necessary? */

177 178
  return 0;
}
179

180 181 182 183 184 185
static inline void
ri_install_net(struct proto_ospf *po, ip_addr prefix, int pxlen, orta *new)
{
  ort *old = (ort *) fib_get(&po->rtf, &prefix, pxlen);
  if (ri_better(po, new, &old->n))
    memcpy(&old->n, new, sizeof(orta));
186 187
}

188 189
static inline void
ri_install_rt(struct ospf_area *oa, u32 rid, orta *new)
190
{
191 192 193 194 195
  ip_addr addr = ipa_from_rid(rid);
  ort *old = (ort *) fib_get(&oa->rtr, &addr, MAX_PREFIX_LENGTH);
  if (ri_better(oa->po, new, &old->n))
    memcpy(&old->n, new, sizeof(orta));
}
196

197
static inline void
198
ri_install_asbr(struct proto_ospf *po, ip_addr *addr, orta *new)
199
{
200 201
  ort *old = (ort *) fib_get(&po->backbone->rtr, addr, MAX_PREFIX_LENGTH);
  if (ri_better_asbr(po, new, &old->n))
202 203
    memcpy(&old->n, new, sizeof(orta));
}
Ondřej Filip's avatar
Ondřej Filip committed
204

205
static inline void
206
ri_install_ext(struct proto_ospf *po, ip_addr prefix, int pxlen, orta *new)
207
{
208 209 210
  ort *old = (ort *) fib_get(&po->rtf, &prefix, pxlen);
  if (ri_better_ext(po, new, &old->n))
    memcpy(&old->n, new, sizeof(orta));
211 212
}

213 214
static inline struct ospf_iface *
rt_pos_to_ifa(struct ospf_area *oa, int pos)
215
{
216 217
  struct ospf_iface *ifa;
  WALK_LIST(ifa, oa->po->iface_list)
218
    if (ifa->oa == oa && pos >= ifa->rt_pos_beg && pos < ifa->rt_pos_end)
219
      return ifa;
220 221 222
  return NULL;
}

223 224 225
#ifdef OSPFv3
static inline struct ospf_iface *
px_pos_to_ifa(struct ospf_area *oa, int pos)
226
{
227 228
  struct ospf_iface *ifa;
  WALK_LIST(ifa, oa->po->iface_list)
229
    if (ifa->oa == oa && pos >= ifa->px_pos_beg && pos < ifa->px_pos_end)
230
      return ifa;
231 232 233 234
  return NULL;
}
#endif

235

236
static void
237
add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_hash_entry *en, int pos)
238
{
239 240 241 242 243 244 245 246
  orta nf = {
    .type = RTS_OSPF,
    .options = 0,
    .metric1 = metric,
    .metric2 = LSINFINITY,
    .tag = 0,
    .rid = en->lsa.rt,
    .oa = oa,
247
    .nhs = en->nhs
248
  };
249

250 251 252 253 254 255 256
  if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
  {
    log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
	oa->po->proto.name, en->lsa.type, en->lsa.id, en->lsa.rt);
    return;
  }

257 258 259 260 261 262
  if (en == oa->rt)
  {
    /* 
     * Local stub networks does not have proper iface in en->nhi
     * (because they all have common top_hash_entry en).
     * We have to find iface responsible for that stub network.
263 264
     * Configured stubnets does not have any iface. They will
     * be removed in rt_sync().
265 266
     */

267 268 269 270 271 272 273
    struct ospf_iface *ifa;
#ifdef OSPFv2
    ifa = rt_pos_to_ifa(oa, pos);
#else /* OSPFv3 */
    ifa = px_pos_to_ifa(oa, pos);
#endif

274
    nf.nhs = ifa ? new_nexthop(oa->po, IPA_NONE, ifa->iface, ifa->ecmp_weight) : NULL;
275 276
  }

277
  ri_install_net(oa->po, px, pxlen, &nf);
278 279 280 281 282 283 284
}

#ifdef OSPFv3
static void
process_prefixes(struct ospf_area *oa)
{
  struct proto_ospf *po = oa->po;
285
  // struct proto *p = &po->proto;
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
  struct top_hash_entry *en, *src;
  struct ospf_lsa_prefix *px;
  ip_addr pxa;
  int pxlen;
  u8 pxopts;
  u16 metric;
  u32 *buf;
  int i;

  WALK_SLIST(en, po->lsal)
  {
    if (en->lsa.type != LSA_T_PREFIX)
      continue;

    if (en->domain != oa->areaid)
      continue;

    if (en->lsa.age == LSA_MAXAGE)
      continue;

    px = en->lsa_body;
307 308 309 310 311 312

    /* For router prefix-LSA, we would like to find the first router-LSA */
    if (px->ref_type == LSA_T_RT)
      src = ospf_hash_find_rt(po->gr, oa->areaid, px->ref_rt);
    else
      src = ospf_hash_find(po->gr, oa->areaid, px->ref_id, px->ref_rt, px->ref_type);
313 314 315 316

    if (!src)
      continue;

317 318 319 320
    /* Reachable in SPF */
    if (src->color != INSPF)
      continue;

321 322 323 324 325 326
    if ((src->lsa.type != LSA_T_RT) && (src->lsa.type != LSA_T_NET))
      continue;

    buf = px->rest;
    for (i = 0; i < px->pxcount; i++)
      {
327
	buf = lsa_get_ipv6_prefix(buf, &pxa, &pxlen, &pxopts, &metric);
328 329 330 331

	if (pxopts & OPT_PX_NU)
	  continue;

332 333 334 335
	/* Store the first global address to use it later as a vlink endpoint */
	if ((pxopts & OPT_PX_LA) && ipa_zero(src->lb))
	  src->lb = pxa;

336
	add_network(oa, pxa, pxlen, src->dist + metric, src, i);
337 338 339 340 341
      }
  }
}
#endif

342 343 344 345

static void
ospf_rt_spfa_rtlinks(struct ospf_area *oa, struct top_hash_entry *act, struct top_hash_entry *en)
{
346
  // struct proto *p = &oa->po->proto;
347
  struct proto_ospf *po = oa->po;
348 349
  ip_addr prefix UNUSED;
  int pxlen UNUSED, i;
350 351 352 353 354 355 356 357 358 359 360 361 362 363

  struct ospf_lsa_rt *rt = en->lsa_body;
  struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1);

  for (i = 0; i < lsa_rt_count(&en->lsa); i++)
    {
      struct ospf_lsa_rt_link *rtl = rr + i;
      struct top_hash_entry *tmp = NULL;

      DBG("     Working on link: %R (type: %u)  ", rtl->id, rtl->type);
      switch (rtl->type)
	{
#ifdef OSPFv2
	case LSART_STUB:
Ondřej Zajíček's avatar
Ondřej Zajíček committed
364 365 366 367 368 369
	  /*
	   * RFC 2328 in 16.1. (2a) says to handle stub networks in an
	   * second phase after the SPF for an area is calculated. We get
	   * the same result by handing them here because add_network()
	   * will keep the best (not the first) found route.
	   */
370 371 372
	  prefix = ipa_from_u32(rtl->id & rtl->data);
	  pxlen = ipa_mklen(ipa_from_u32(rtl->data));
	  add_network(oa, prefix, pxlen, act->dist + rtl->metric, act, i);
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
	  break;
#endif

	case LSART_NET:
#ifdef OSPFv2
	  /* In OSPFv2, rtl->id is IP addres of DR, Router ID is not known */
	  tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl->id);
#else /* OSPFv3 */
	  tmp = ospf_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET);
#endif
	  break;

	case LSART_VLNK:
	case LSART_PTP:
	  tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl->id);
	  break;
389

390 391 392 393
	default:
	  log("Unknown link type in router lsa. (rid = %R)", act->lsa.id);
	  break;
	}
394

395 396 397
      if (tmp)
	DBG("Going to add cand, Mydist: %u, Req: %u\n",
	    tmp->dist, act->dist + rtl->metric);
398
      add_cand(&oa->cand, tmp, act, act->dist + rtl->metric, oa, i);
399 400 401
    }
}

402
/* RFC 2328 16.1. calculating shortest paths for an area */
403
static void
404
ospf_rt_spfa(struct ospf_area *oa)
405
{
Ondřej Filip's avatar
Ondřej Filip committed
406 407
  struct proto *p = &oa->po->proto;
  struct proto_ospf *po = oa->po;
408
  struct ospf_lsa_rt *rt;
409
  struct ospf_lsa_net *ln;
Ondřej Filip's avatar
Ondřej Filip committed
410
  struct top_hash_entry *act, *tmp;
411 412
  ip_addr prefix UNUSED;
  int pxlen UNUSED;
413
  u32 i, *rts;
Ondřej Filip's avatar
Ondřej Filip committed
414 415
  node *n;

Ondřej Filip's avatar
Ondřej Filip committed
416 417
  if (oa->rt == NULL)
    return;
418

419
  OSPF_TRACE(D_EVENTS, "Starting routing table calculation for area %R", oa->areaid);
420

421
  /* 16.1. (1) */
422
  init_list(&oa->cand);		/* Empty list of candidates */
Ondřej Filip's avatar
Ondřej Filip committed
423
  oa->trcap = 0;
424

425 426
  DBG("LSA db prepared, adding me into candidate list.\n");

Ondřej Filip's avatar
Ondřej Filip committed
427 428
  oa->rt->dist = 0;
  oa->rt->color = CANDIDATE;
429
  add_head(&oa->cand, &oa->rt->cn);
430 431
  DBG("RT LSA: rt: %R, id: %R, type: %u\n",
      oa->rt->lsa.rt, oa->rt->lsa.id, oa->rt->lsa.type);
432

Ondřej Filip's avatar
Ondřej Filip committed
433
  while (!EMPTY_LIST(oa->cand))
434
  {
Ondřej Filip's avatar
Ondřej Filip committed
435 436
    n = HEAD(oa->cand);
    act = SKIP_BACK(struct top_hash_entry, cn, n);
437 438
    rem_node(n);

439 440
    DBG("Working on LSA: rt: %R, id: %R, type: %u\n",
	act->lsa.rt, act->lsa.id, act->lsa.type);
441

Ondřej Filip's avatar
Ondřej Filip committed
442 443
    act->color = INSPF;
    switch (act->lsa.type)
444
    {
Ondřej Filip's avatar
Ondřej Filip committed
445 446
    case LSA_T_RT:
      rt = (struct ospf_lsa_rt *) act->lsa_body;
447
      if (rt->options & OPT_RT_V)
Ondřej Filip's avatar
Ondřej Filip committed
448
	oa->trcap = 1;
449

450 451 452 453 454 455
      /*
       * In OSPFv3, all routers are added to per-area routing
       * tables. But we use it just for ASBRs and ABRs. For the
       * purpose of the last step in SPF - prefix-LSA processing in
       * process_prefixes(), we use information stored in LSA db.
       */
456 457
      if (((rt->options & OPT_RT_E) || (rt->options & OPT_RT_B))
	  && (act->lsa.rt != po->router_id))
458 459 460 461 462 463 464 465 466
      {
	orta nf = {
	  .type = RTS_OSPF,
	  .options = rt->options,
	  .metric1 = act->dist,
	  .metric2 = LSINFINITY,
	  .tag = 0,
	  .rid = act->lsa.rt,
	  .oa = oa,
467
	  .nhs = act->nhs
468 469 470
	};
	ri_install_rt(oa, act->lsa.rt, &nf);
      }
471

472
#ifdef OSPFv2
473
      ospf_rt_spfa_rtlinks(oa, act, act);
474
#else /* OSPFv3 */
475 476 477
      for (tmp = ospf_hash_find_rt_first(po->gr, act->domain, act->lsa.rt);
	   tmp; tmp = ospf_hash_find_rt_next(tmp))
	ospf_rt_spfa_rtlinks(oa, act, tmp);
478
#endif
479

Ondřej Filip's avatar
Ondřej Filip committed
480 481 482
      break;
    case LSA_T_NET:
      ln = act->lsa_body;
483 484

#ifdef OSPFv2
485 486 487
      prefix = ipa_and(ipa_from_u32(act->lsa.id), ln->netmask);
      pxlen = ipa_mklen(ln->netmask);
      add_network(oa, prefix, pxlen, act->dist, act, -1);
488
#endif
489

Ondřej Filip's avatar
Ondřej Filip committed
490
      rts = (u32 *) (ln + 1);
491
      for (i = 0; i < lsa_net_count(&act->lsa); i++)
Ondřej Filip's avatar
Ondřej Filip committed
492
      {
493
	DBG("     Working on router %R ", rts[i]);
494
	tmp = ospf_hash_find_rt(po->gr, oa->areaid, rts[i]);
Ondřej Filip's avatar
Ondřej Filip committed
495 496 497 498
	if (tmp != NULL)
	  DBG("Found :-)\n");
	else
	  DBG("Not found!\n");
499
	add_cand(&oa->cand, tmp, act, act->dist, oa, -1);
Ondřej Filip's avatar
Ondřej Filip committed
500 501
      }
      break;
502
    }
503
  }
Ondřej Filip's avatar
Ondřej Filip committed
504

505 506 507
#ifdef OSPFv3
  process_prefixes(oa);
#endif
Ondřej Filip's avatar
Ondřej Filip committed
508 509 510
}

static int
511
link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par)
Ondřej Filip's avatar
Ondřej Filip committed
512 513 514 515 516
{
  u32 i, *rts;
  struct ospf_lsa_net *ln;
  struct ospf_lsa_rt *rt;
  struct ospf_lsa_rt_link *rtl, *rr;
517
  struct top_hash_entry *tmp;
518
  struct proto_ospf *po = oa->po;
Ondřej Filip's avatar
Ondřej Filip committed
519

520 521
  if (!en || !par) return 0;

Ondřej Zajíček's avatar
Ondřej Zajíček committed
522 523 524 525 526 527 528
  /* We should check whether there is a link back from en to par,
     this is used in SPF calc (RFC 2328 16.1. (2b)). According to RFC 2328
     note 23, we don't have to find the same link that is used for par
     to en, any link is enough. This we do for ptp links. For net-rt
     links, we have to find the same link to compute proper lb/lb_id,
     which may be later used as the next hop. */

529 530 531
  /* In OSPFv2, en->lb is set here. In OSPFv3, en->lb is just cleared here,
     it is set in process_prefixes() to any global addres in the area */

532
  en->lb = IPA_NONE;
533 534 535
#ifdef OSPFv3
  en->lb_id = 0;
#endif
536
  switch (en->lsa.type)
Ondřej Filip's avatar
Ondřej Filip committed
537 538
  {
    case LSA_T_RT:
539
      rt = (struct ospf_lsa_rt *) en->lsa_body;
Ondřej Filip's avatar
Ondřej Filip committed
540
      rr = (struct ospf_lsa_rt_link *) (rt + 1);
541
      for (i = 0; i < lsa_rt_count(&en->lsa); i++)
Ondřej Filip's avatar
Ondřej Filip committed
542 543 544 545 546 547 548
      {
	rtl = (rr + i);
	switch (rtl->type)
	{
	case LSART_STUB:
	  break;
	case LSART_NET:
549 550 551 552 553 554 555
#ifdef OSPFv2
	  /* In OSPFv2, rtl->id is IP addres of DR, Router ID is not known */
	  tmp = ospf_hash_find_net(po->gr, oa->areaid, rtl->id);
#else /* OSPFv3 */
	  tmp = ospf_hash_find(po->gr, oa->areaid, rtl->nif, rtl->id, LSA_T_NET);
#endif
	  if (tmp == par)
556 557
	  {
#ifdef OSPFv2
558
	    en->lb = ipa_from_u32(rtl->data);
559 560
#else /* OSPFv3 */
	    en->lb_id = rtl->lif;
561 562 563
#endif
	    return 1;
	  }
564

Ondřej Filip's avatar
Ondřej Filip committed
565 566 567
	  break;
	case LSART_VLNK:
	case LSART_PTP:
Ondřej Zajíček's avatar
Ondřej Zajíček committed
568
	  /* Not necessary the same link, see RFC 2328 [23] */
569 570
	  tmp = ospf_hash_find_rt(po->gr, oa->areaid, rtl->id);
	  if (tmp == par)
Ondřej Filip's avatar
Ondřej Filip committed
571
            return 1;
572

Ondřej Filip's avatar
Ondřej Filip committed
573 574
	  break;
	default:
575
	  log(L_WARN "Unknown link type in router lsa. (rid = %R)", en->lsa.rt);
Ondřej Filip's avatar
Ondřej Filip committed
576 577 578 579 580
	  break;
	}
      }
      break;
    case LSA_T_NET:
581
      ln = en->lsa_body;
Ondřej Filip's avatar
Ondřej Filip committed
582
      rts = (u32 *) (ln + 1);
583
      for (i = 0; i < lsa_net_count(&en->lsa); i++)
Ondřej Filip's avatar
Ondřej Filip committed
584
      {
585 586
	tmp = ospf_hash_find_rt(po->gr, oa->areaid, rts[i]);
	if (tmp == par)
Ondřej Filip's avatar
Ondřej Filip committed
587 588 589 590
          return 1;
      }
      break;
    default:
591
      bug("Unknown lsa type %x.", en->lsa.type);
Ondřej Filip's avatar
Ondřej Filip committed
592 593 594 595
  }
  return 0;
}

596 597
  
/* RFC 2328 16.2. calculating inter-area routes */
Ondřej Filip's avatar
Ondřej Filip committed
598
static void
599
ospf_rt_sum(struct ospf_area *oa)
Ondřej Filip's avatar
Ondřej Filip committed
600 601
{
  struct proto_ospf *po = oa->po;
602
  struct proto *p = &po->proto;
Ondřej Filip's avatar
Ondřej Filip committed
603
  struct top_hash_entry *en;
604 605 606 607
  ip_addr ip = IPA_NONE;
  u32 dst_rid = 0;
  u32 metric, options;
  ort *abr;
608
  int pxlen = -1, type = -1;
Ondřej Filip's avatar
Ondřej Filip committed
609

610
  OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area (area %R)", oa->areaid);
Ondřej Filip's avatar
Ondřej Filip committed
611

612
  WALK_SLIST(en, po->lsal)
Ondřej Filip's avatar
Ondřej Filip committed
613
  {
614
    if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
615
      continue;
616 617 618 619

    if (en->domain != oa->areaid)
      continue;

620
    /* 16.2. (1a) */
Ondřej Filip's avatar
Ondřej Filip committed
621 622
    if (en->lsa.age == LSA_MAXAGE)
      continue;
623

624
    /* 16.2. (2) */
625
    if (en->lsa.rt == po->router_id)
Ondřej Filip's avatar
Ondřej Filip committed
626 627
      continue;

628
    /* 16.2. (3) is handled later in ospf_rt_abr() by resetting such rt entry */
629

Ondřej Filip's avatar
Ondřej Filip committed
630 631
    if (en->lsa.type == LSA_T_SUM_NET)
    {
632 633 634
#ifdef OSPFv2
      struct ospf_lsa_sum *ls = en->lsa_body;
      ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask);
635
      pxlen = ipa_mklen(ls->netmask);
636 637
#else /* OSPFv3 */
      u8 pxopts;
638
      u16 rest;
639
      struct ospf_lsa_sum_net *ls = en->lsa_body;
640
      lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest);
641

642 643 644 645
      if (pxopts & OPT_PX_NU)
	continue;
#endif

646 647 648 649 650 651 652
      if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
      {
	log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
	    p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
	continue;
      }

653 654
      metric = ls->metric & METRIC_MASK;
      options = 0;
Ondřej Filip's avatar
Ondřej Filip committed
655 656
      type = ORT_NET;
    }
657
    else /* LSA_T_SUM_RT */
Ondřej Filip's avatar
Ondřej Filip committed
658
    {
659 660 661 662 663 664 665 666 667
#ifdef OSPFv2
      struct ospf_lsa_sum *ls = en->lsa_body;
      dst_rid = en->lsa.id;
      options = 0;
#else /* OSPFv3 */
      struct ospf_lsa_sum_rt *ls = en->lsa_body;
      dst_rid = ls->drid; 
      options = ls->options & OPTIONS_MASK;
#endif
668 669 670 671
      
      /* We don't want local router in ASBR routing table */
      if (dst_rid == po->router_id)
	continue;
672 673 674

      metric = ls->metric & METRIC_MASK;
      options |= ORTA_ASBR;
Ondřej Filip's avatar
Ondřej Filip committed
675 676
      type = ORT_ROUTER;
    }
677

678 679 680
    /* 16.2. (1b) */
    if (metric == LSINFINITY)
      continue;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
681

682 683 684 685 686
    /* 16.2. (4) */
    ip_addr abrip = ipa_from_rid(en->lsa.rt);
    abr = (ort *) fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH);
    if (!abr || !abr->n.type)
      continue;
Ondřej Filip's avatar
Ondřej Filip committed
687

688 689 690
    if (!(abr->n.options & ORTA_ABR))
      continue;

691 692 693 694
    /* This check is not mentioned in RFC 2328 */
    if (abr->n.type != RTS_OSPF)
      continue;

695 696 697 698 699 700 701 702 703
    /* 16.2. (5) */
    orta nf = {
      .type = RTS_OSPF_IA,
      .options = options,
      .metric1 = abr->n.metric1 + metric,
      .metric2 = LSINFINITY,
      .tag = 0,
      .rid = en->lsa.rt, /* ABR ID */
      .oa = oa,
704
      .nhs = abr->n.nhs
705 706 707 708 709 710
    };

    if (type == ORT_NET)
      ri_install_net(po, ip, pxlen, &nf);
    else
      ri_install_rt(oa, dst_rid, &nf);
Ondřej Filip's avatar
Ondřej Filip committed
711
  }
712
}
713 714

/* RFC 2328 16.3. examining summary-LSAs in transit areas */
Ondřej Filip's avatar
Ondřej Filip committed
715
static void
716
ospf_rt_sum_tr(struct ospf_area *oa)
Ondřej Filip's avatar
Ondřej Filip committed
717
{
718
  struct proto *p = &oa->po->proto;
Ondřej Filip's avatar
Ondřej Filip committed
719
  struct proto_ospf *po = oa->po;
720
  struct ospf_area *bb = po->backbone;
721
  ip_addr abrip;
Ondřej Filip's avatar
Ondřej Filip committed
722
  struct top_hash_entry *en;
723
  u32 dst_rid, metric;
724
  ort *re = NULL, *abr;
725

726 727

  if (!bb) return;
728

729
  WALK_SLIST(en, po->lsal)
Ondřej Filip's avatar
Ondřej Filip committed
730
  {
731 732 733 734
    if ((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
      continue;

    if (en->domain != oa->areaid)
735
      continue;
736

737
    /* 16.3 (1a) */
Ondřej Filip's avatar
Ondřej Filip committed
738 739
    if (en->lsa.age == LSA_MAXAGE)
      continue;
740

741
    /* 16.3 (2) */
742
    if (en->lsa.rt == po->router_id)
Ondřej Filip's avatar
Ondřej Filip committed
743 744 745 746
      continue;

    if (en->lsa.type == LSA_T_SUM_NET)
    {
747 748
      ip_addr ip;
      int pxlen;
749 750 751
#ifdef OSPFv2
      struct ospf_lsa_sum *ls = en->lsa_body;
      ip = ipa_and(ipa_from_u32(en->lsa.id), ls->netmask);
752
      pxlen = ipa_mklen(ls->netmask);
753 754
#else /* OSPFv3 */
      u8 pxopts;
755
      u16 rest;
756
      struct ospf_lsa_sum_net *ls = en->lsa_body;
757
      lsa_get_ipv6_prefix(ls->prefix, &ip, &pxlen, &pxopts, &rest);
758

759 760 761 762
      if (pxopts & OPT_PX_NU)
	continue;
#endif

763 764 765 766 767 768 769
      if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
      {
	log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
	    p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
	continue;
      }

770
      metric = ls->metric & METRIC_MASK;
771
      re = fib_find(&po->rtf, &ip, pxlen);
Ondřej Filip's avatar
Ondřej Filip committed
772
    }
773
    else // en->lsa.type == LSA_T_SUM_RT
Ondřej Filip's avatar
Ondřej Filip committed
774
    {
775 776 777 778 779 780 781 782 783
#ifdef OSPFv2
      struct ospf_lsa_sum *ls = en->lsa_body;
      dst_rid = en->lsa.id;
#else /* OSPFv3 */
      struct ospf_lsa_sum_rt *ls = en->lsa_body;
      dst_rid = ls->drid; 
#endif

      metric = ls->metric & METRIC_MASK;
784 785
      ip_addr ip = ipa_from_rid(dst_rid);
      re = fib_find(&bb->rtr, &ip, MAX_PREFIX_LENGTH);
Ondřej Filip's avatar
Ondřej Filip committed
786 787
    }

788 789 790
    /* 16.3 (1b) */ 
    if (metric == LSINFINITY) 
      continue; 
791

792 793 794
    /* 16.3 (3) */
    if (!re || !re->n.type)
      continue;
795

796 797
    if (re->n.oa->areaid != 0)
      continue;
798

799 800
    if ((re->n.type != RTS_OSPF) && (re->n.type != RTS_OSPF_IA))
      continue;
801

802 803 804 805 806
    /* 16.3. (4) */
    abrip = ipa_from_rid(en->lsa.rt);
    abr = fib_find(&oa->rtr, &abrip, MAX_PREFIX_LENGTH);
    if (!abr || !abr->n.type)
      continue;
807

808
    metric = abr->n.metric1 + metric; /* IAC */
Ondřej Filip's avatar
Ondřej Filip committed
809

810
    /* 16.3. (5) */
811 812
    if ((metric < re->n.metric1) || 
	((metric == re->n.metric1) && unresolved_vlink(re->n.nhs)))
Ondřej Filip's avatar
Ondřej Filip committed
813
    {
814
      /* We want to replace the next-hop even if the metric is equal
815 816 817 818 819
	 to replace a virtual next-hop through vlink with a real one.
	 Proper ECMP would merge nexthops here, but we do not do that.
	 We restrict nexthops to fit one area to simplify check
	 12.4.3 p4 in decide_sum_lsa() */

820
      re->n.metric1 = metric;
821 822
      re->n.voa = oa;
      re->n.nhs = abr->n.nhs;
Ondřej Filip's avatar
Ondřej Filip committed
823 824
    }
  }
825
}
826

827 828 829 830
/* Decide about originating or flushing summary LSAs for condended area networks */
static int
decide_anet_lsa(struct ospf_area *oa, struct area_net *anet, struct ospf_area *anet_oa)
{
831 832
  /* 12.4.3.1. - for stub/NSSA areas, originating summary routes is configurable */
  if (!oa_is_ext(oa) && !oa->ac->summary)
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
    return 0;

  if (oa == anet_oa)
    return 0;

  /* Do not condense routing info when exporting from backbone to the transit area */
  if ((anet_oa == oa->po->backbone) && oa->trcap)
    return 0;

  return (anet->active && !anet->hidden);
}

/* Decide about originating or flushing summary LSAs (12.4.3) */
static int
decide_sum_lsa(struct ospf_area *oa, ort *nf, int dest)
{
849 850
  /* 12.4.3.1. - for stub/NSSA areas, originating summary routes is configurable */
  if (!oa_is_ext(oa) && !oa->ac->summary)
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
    return 0;

  /* Invalid field - no route */
  if (!nf->n.type)
    return 0;

  /* 12.4.3 p2 */
  if (nf->n.type > RTS_OSPF_IA)
    return 0;

  /* 12.4.3 p3 */
  if ((nf->n.oa->areaid == oa->areaid))
    return 0;

  /* 12.4.3 p4 */
866
  if (nf->n.voa && (nf->n.voa->areaid == oa->areaid))
867 868 869 870 871 872 873 874 875 876 877
    return 0;

  /* 12.4.3 p5 */
  if (nf->n.metric1 >= LSINFINITY)
    return 0;

  /* 12.4.3 p6 - AS boundary router */
  if (dest == ORT_ROUTER)
  {
    /* We call decide_sum_lsa() on preferred ASBR entries, no need for 16.4. (3) */
    /* 12.4.3 p1 */
878
    return oa_is_ext(oa) && (nf->n.options & ORTA_ASBR);
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
  }

  /* 12.4.3 p7 - inter-area route */
  if (nf->n.type == RTS_OSPF_IA)
  {
    /* Inter-area routes are not repropagated into the backbone */
    return (oa != oa->po->backbone);
  }

  /* 12.4.3 p8 - intra-area route */

  /* Do not condense routing info when exporting from backbone to the transit area */
  if ((nf->n.oa == oa->po->backbone) && oa->trcap)
    return 1;

  struct area_net *anet = (struct area_net *)
    fib_route(&nf->n.oa->net_fib, nf->fn.prefix, nf->fn.pxlen);

  /* Condensed area network found */ 
  if (anet)
    return 0;

  return 1;
}

/* RFC 2328 16.7. p1 - originate or flush summary LSAs */
static inline void
check_sum_net_lsa(struct proto_ospf *po, ort *nf)
{
  struct area_net *anet = NULL;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
909
  struct ospf_area *anet_oa = NULL;
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953

  /* RT entry marked as area network */
  if (nf->fn.x0)
  {
    /* It is a default route for stub areas, handled entirely in ospf_rt_abr() */
    if (nf->fn.pxlen == 0)
      return;

    /* Find that area network */
    WALK_LIST(anet_oa, po->area_list)
    {
      anet = (struct area_net *) fib_find(&anet_oa->net_fib, &nf->fn.prefix, nf->fn.pxlen);
      if (anet)
	break;
    }
  }

  struct ospf_area *oa;
  WALK_LIST(oa, po->area_list)
  {
    if (anet && decide_anet_lsa(oa, anet, anet_oa))
      originate_sum_net_lsa(oa, &nf->fn, anet->metric);
    else if (decide_sum_lsa(oa, nf, ORT_NET))
      originate_sum_net_lsa(oa, &nf->fn, nf->n.metric1);
    else
      flush_sum_lsa(oa, &nf->fn, ORT_NET);
  }
}

static inline void
check_sum_rt_lsa(struct proto_ospf *po, ort *nf)
{
  struct ospf_area *oa;
  WALK_LIST(oa, po->area_list)
  {
    if (decide_sum_lsa(oa, nf, ORT_ROUTER))
      originate_sum_rt_lsa(oa, &nf->fn, nf->n.metric1, nf->n.options);
    else
      flush_sum_lsa(oa, &nf->fn, ORT_ROUTER);
  }
}


/* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
954
static void
955
ospf_check_vlinks(struct proto_ospf *po)
956
{
957 958 959 960 961 962 963 964 965 966
  struct proto *p = &po->proto;

  struct ospf_iface *iface;
  WALK_LIST(iface, po->iface_list)
  {
    if (iface->type == OSPF_IT_VLINK)
    {
      struct top_hash_entry *tmp;
      tmp = ospf_hash_find_rt(po->gr, iface->voa->areaid, iface->vid);

967
      if (tmp && (tmp->color == INSPF) && ipa_nonzero(tmp->lb) && tmp->nhs)
968
      {
969 970
	struct ospf_iface *nhi = ospf_iface_find(po, tmp->nhs->iface);

971
        if ((iface->state != OSPF_IS_PTP)
972
	    || (iface->vifa != nhi)
973 974 975 976
	    || !ipa_equal(iface->vip, tmp->lb))
        {
          OSPF_TRACE(D_EVENTS, "Vlink peer %R found", tmp->lsa.id);
          ospf_iface_sm(iface, ISM_DOWN);
977 978 979 980
	  iface->vifa = nhi;
          iface->iface = nhi->iface;
	  iface->addr = nhi->addr;
	  iface->sk = nhi->sk;
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
	  iface->cost = tmp->dist;
          iface->vip = tmp->lb;
          ospf_iface_sm(iface, ISM_UP);
        }
	else if ((iface->state == OSPF_IS_PTP) && (iface->cost != tmp->dist))
	{
	  iface->cost = tmp->dist;
	  schedule_rt_lsa(po->backbone);
	}
      }
      else
      {
        if (iface->state > OSPF_IS_DOWN)
        {
          OSPF_TRACE(D_EVENTS, "Vlink peer %R lost", iface->vid);
	  ospf_iface_sm(iface, ISM_DOWN);
        }
      }
    }
  }
}

/* Miscellaneous route processing that needs to be done by ABRs */
static void
ospf_rt_abr(struct proto_ospf *po)
{
  struct area_net *anet;
  ort *nf, *default_nf;

1010
  FIB_WALK(&po->rtf, nftmp)
Ondřej Filip's avatar
Ondřej Filip committed
1011
  {
1012 1013 1014 1015
    nf = (ort *) nftmp;


    /* RFC 2328 G.3 - incomplete resolution of virtual next hops */
1016 1017
    if (nf->n.type && unresolved_vlink(nf->n.nhs))
      reset_ri(nf);
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035


    /* Compute condensed area networks */
    if (nf->n.type == RTS_OSPF)
    {
      anet = (struct area_net *) fib_route(&nf->n.oa->net_fib, nf->fn.prefix, nf->fn.pxlen);
      if (anet)
      {
	if (!anet->active)
	{
	  anet->active = 1;

	  /* Get a RT entry and mark it to know that it is an area network */
	  ort *nfi = (ort *) fib_get(&po->rtf, &anet->fn.prefix, anet->fn.pxlen);
	  nfi->fn.x0 = 1; /* mark and keep persistent, to have stable UID */

	  /* 16.2. (3) */
	  if (nfi->n.type == RTS_OSPF_IA)
1036
	    reset_ri(nfi);
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
	}

	if (anet->metric < nf->n.metric1)
	  anet->metric = nf->n.metric1;
      }
    }
  }
  FIB_WALK_END;

  ip_addr addr = IPA_NONE;
  default_nf = (ort *) fib_get(&po->rtf, &addr, 0);
  default_nf->fn.x0 = 1; /* keep persistent */

  struct ospf_area *oa;
  WALK_LIST(oa, po->area_list)
  {

1054 1055 1056
    /* 12.4.3.1. - originate or flush default route for stub/NSSA areas */
    if (oa_is_stub(oa) || (oa_is_nssa(oa) && !oa->ac->summary))
      originate_sum_net_lsa(oa, &default_nf->fn, oa->ac->stub_cost);
1057 1058 1059
    else
      flush_sum_lsa(oa, &default_nf->fn, ORT_NET);

1060
    // FIXME NSSA add support for type 7 default route ?
1061 1062

    /* RFC 2328 16.4. (3) - precompute preferred ASBR entries */
1063
    if (oa_is_ext(oa))
1064
    {
1065 1066 1067 1068 1069 1070 1071
      FIB_WALK(&oa->rtr, nftmp)
      {
	nf = (ort *) nftmp;
	if (nf->n.options & ORTA_ASBR)
	  ri_install_asbr(po, &nf->fn.prefix, &nf->n);
      }
      FIB_WALK_END;
1072 1073 1074 1075 1076 1077 1078 1079
    }
  }


  /* Originate or flush ASBR summary LSAs */
  FIB_WALK(&po->backbone->rtr, nftmp)
  {
    check_sum_rt_lsa(po, (ort *) nftmp);
1080
  }
1081
  FIB_WALK_END;
1082 1083 1084 1085


  /* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
  ospf_check_vlinks(po);
1086 1087
}

1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
/* Like fib_route(), but ignores dummy rt entries */
static void *
ospf_fib_route(struct fib *f, ip_addr a, int len)
{
  ip_addr a0;
  ort *nf;

  while (len >= 0)
  {
    a0 = ipa_and(a, ipa_mkmask(len));
    nf = fib_find(f, &a0, len);
    if (nf && nf->n.type)
      return nf;
    len--;
  }
  return NULL;
}
1105 1106

/* RFC 2328 16.4. calculating external routes */
1107
static void
1108
ospf_ext_spf(struct proto_ospf *po)
1109
{
1110
  ort *nf1, *nf2;
1111 1112
  orta nfa;
  struct top_hash_entry *en;
Ondřej Filip's avatar
Ondřej Filip committed
1113
  struct proto *p = &po->proto;
1114
  struct ospf_lsa_ext *le;
1115
  int pxlen, ebit, rt_fwaddr_valid, rt_propagate;
1116
  ip_addr ip, rtid, rt_fwaddr;
1117
  u32 br_metric, rt_metric, rt_tag;
Ondřej Filip's avatar
Ondřej Filip committed
1118
  struct ospf_area *atmp;
1119
  struct mpnh* nhs = NULL;
1120

1121
  OSPF_TRACE(D_EVENTS, "Starting routing table calculation for ext routes");
1122

1123
  WALK_SLIST(en, po->lsal)
1124
  {
1125
    /* 16.4. (1) */
1126
    if ((en->lsa.type != LSA_T_EXT) && (en->lsa.type != LSA_T_NSSA))
Ondřej Filip's avatar
Ondřej Filip committed
1127
      continue;
1128

Ondřej Filip's avatar
Ondřej Filip committed
1129 1130
    if (en->lsa.age == LSA_MAXAGE)
      continue;
1131 1132

    /* 16.4. (2) */
1133
    if (en->lsa.rt == po->router_id)
Ondřej Filip's avatar
Ondřej Filip committed
1134
      continue;
1135

1136 1137
    DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n",
	p->name, en->lsa.id, en->lsa.rt, en->lsa.type);
1138

1139 1140 1141 1142 1143 1144
    le = en->lsa_body;

    rt_metric = le->metric & METRIC_MASK;
    ebit = le->metric & LSA_EXT_EBIT;

    if (rt_metric == LSINFINITY)
Ondřej Filip's avatar
Ondřej Filip committed
1145
      continue;
1146 1147

#ifdef OSPFv2
Ondřej Filip's avatar
Ondřej Filip committed
1148
    ip = ipa_and(ipa_from_u32(en->lsa.id), le->netmask);
1149 1150 1151 1152
    pxlen = ipa_mklen(le->netmask);
    rt_fwaddr = le->fwaddr;
    rt_fwaddr_valid = !ipa_equal(rt_fwaddr, IPA_NONE);
    rt_tag = le->tag;
1153
    rt_propagate = en->lsa.options & OPT_P;
1154 1155
#else /* OSPFv3 */
    u8 pxopts;
1156
    u16 rest;
1157
    u32 *buf = le->rest;
1158
    buf = lsa_get_ipv6_prefix(buf, &ip, &pxlen, &pxopts, &rest);
1159 1160 1161 1162 1163 1164

    if (pxopts & OPT_PX_NU)
      continue;

    rt_fwaddr_valid = le->metric & LSA_EXT_FBIT;
    if (rt_fwaddr_valid)
1165
      buf = lsa_get_ipv6_addr(buf, &rt_fwaddr);
1166 1167 1168 1169 1170 1171 1172
    else 
      rt_fwaddr = IPA_NONE;

    if (le->metric & LSA_EXT_TBIT)
      rt_tag = *buf++;
    else
      rt_tag = 0;
1173 1174

    rt_propagate = pxopts & OPT_PX_P;
1175 1176
#endif

1177
    if (pxlen < 0 || pxlen > MAX_PREFIX_LENGTH)
1178
    {
1179
      log(L_WARN "%s: Invalid prefix in LSA (Type: %04x, Id: %R, Rt: %R)",
Ondřej Zajíček's avatar
Ondřej Zajíček committed
1180
	  p->name, en->lsa.type, en->lsa.id, en->lsa.rt);
1181
      continue;
1182
    }
1183

1184

1185
    /* 16.4. (3) */
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
    /* If there are more areas, we already precomputed preferred ASBR
       entries in ospf_rt_abr() and stored them in the backbone
       table. For NSSA, we examine the area to which the LSA is assigned */
    if (en->lsa.type == LSA_T_EXT)
      atmp = ospf_main_area(po);
    else /* NSSA */
      atmp = ospf_find_area(po, en->domain);

    if (!atmp)
      continue;			/* Should not happen */

1197
    rtid = ipa_from_rid(en->lsa.rt);
1198
    nf1 = fib_find(&atmp->rtr, &rtid, MAX_PREFIX_LENGTH);
1199

1200
    if (!nf1 || !nf1->n.type)
1201
      continue;			/* No AS boundary router found */
1202

1203
    if (!(nf1->n.options & ORTA_ASBR))
1204
      continue;			/* It is not ASBR */
1205

1206 1207 1208 1209 1210 1211
    /* 16.4. (3) NSSA - special rule for default routes */
    /* ABR should use default only if P-bit is set and summaries are active */
    if ((en->lsa.type == LSA_T_NSSA) && ipa_zero(ip) && (pxlen == 0) &&
	(po->areano > 1) && !(rt_propagate && atmp->ac->summary))
      continue;

1212
    if (!rt_fwaddr_valid)
1213
    {
1214
      nf2 = nf1;
1215
      nhs = nf1->n.nhs;
1216
      br_metric = nf1->n.metric1;
1217
    }
1218
    else
1219
    {
1220 1221
      nf2 = ospf_fib_route(&po->rtf, rt_fwaddr, MAX_PREFIX_LENGTH);
      if (!nf2)
Ondřej Filip's avatar
Ondřej Filip committed
1222
	continue;
Ondřej Filip's avatar
Ondřej Filip committed
1223

1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
      if (en->lsa.type == LSA_T_EXT)
      {
	/* For ext routes, we accept intra-area or inter-area routes */
	if ((nf2->n.type != RTS_OSPF) && (nf2->n.type != RTS_OSPF_IA))
	  continue;
      }
      else /* NSSA */
      {
	/* For NSSA routes, we accept just intra-area in the same area */
	if ((nf2->n.type != RTS_OSPF) || (nf2->n.oa != atmp))
	  continue;
      }
Ondřej Filip's avatar
Ondřej Filip committed
1236

1237
      /* Next-hop is a part of a configured stubnet */
1238
      if (!nf2->n.nhs)
1239 1240
	continue;

1241 1242 1243 1244
      nhs = nf2->n.nhs;
      /* If gw is zero, it is a device route */
      if (ipa_zero(nhs->gw))
	nhs = new_nexthop(po, rt_fwaddr, nhs->iface, nhs->weight);
1245
      br_metric = nf2->n.metric1;
1246
    }
1247

1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260
    if (ebit)
    {
      nfa.type = RTS_OSPF_EXT2;
      nfa.metric1 = br_metric;
      nfa.metric2 = rt_metric;
    }
    else
    {
      nfa.type = RTS_OSPF_EXT1;
      nfa.metric1 = br_metric + rt_metric;
      nfa.metric2 = LSINFINITY;
    }

1261 1262 1263
    /* Mark the LSA as reachable */
    en->color = INSPF;

1264 1265 1266
    /* Whether the route is preferred in route selection according to 16.4.1 */
    nfa.options = epath_preferred(&nf2->n) ? ORTA_PREF : 0;

1267
    nfa.tag = rt_tag;
1268
    nfa.rid = en->lsa.rt;
1269
    nfa.oa = nf1->n.oa; /* undefined in RFC 2328 */
1270 1271
    nfa.voa = NULL;
    nfa.nhs = nhs;
1272 1273 1274 1275 1276

    ri_install_ext(po, ip, pxlen, &nfa);
  }
}

1277
/* Cleanup of routing tables and data */
1278 1279
void
ospf_rt_reset(struct proto_ospf *po)
1280
{
1281 1282 1283 1284
  struct ospf_area *oa;
  struct top_hash_entry *en;
  struct area_net *anet;
  ort *ri;
1285

1286 1287
  /* Reset old routing table */
  FIB_WALK(&po->rtf, nftmp)
1288
  {
1289 1290
    ri = (ort *) nftmp;
    ri->fn.x0 = 0;
1291
    reset_ri(ri);
1292 1293 1294 1295 1296 1297 1298 1299
  }
  FIB_WALK_END;

  /* Reset SPF data in LSA db */
  WALK_SLIST(en, po->lsal)
  {
    en->color = OUTSPF;
    en->dist = LSINFINITY;
1300
    en->nhs = NULL;
1301 1302 1303 1304 1305 1306 1307
    en->lb = IPA_NONE;
  }

  WALK_LIST(oa, po->area_list)
  {
    /* Reset ASBR routing tables */
    FIB_WALK(&oa->rtr, nftmp)
1308
    {
1309
      ri = (ort *) nftmp;
1310
      reset_ri(ri);
1311 1312
    }
    FIB_WALK_END;
1313

1314 1315 1316 1317
    /* Reset condensed area networks */
    if (po->areano > 1)
    {
      FIB_WALK(&oa->net_fib, nftmp)
1318
      {
1319 1320 1321
	anet = (struct area_net *) nftmp;
	anet->active = 0;
	anet->metric = 0;
1322
      }
1323
      FIB_WALK_END;
1324 1325 1326
    }
  }
}
1327