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

#include "ospf.h"

11
char *ospf_is[] = { "down", "loop", "waiting", "ptp", "drother",
Ondřej Filip's avatar
Ondřej Filip committed
12 13
  "backup", "dr"
};
Ondřej Filip's avatar
Ondřej Filip committed
14

Ondřej Filip's avatar
Ondřej Filip committed
15 16 17
char *ospf_ism[] = { "interface up", "wait timer fired", "backup seen",
  "neighbor change", "loop indicated", "unloop indicated", "interface down"
};
Ondřej Filip's avatar
Ondřej Filip committed
18

19
char *ospf_it[] = { "broadcast", "nbma", "ptp", "ptmp", "virtual link" };
20

21
static void
Ondřej Filip's avatar
Ondřej Filip committed
22
poll_timer_hook(timer * timer)
23
{
24
  ospf_hello_send(timer->data, OHS_POLL, NULL);
25 26
}

27
static void
Ondřej Filip's avatar
Ondřej Filip committed
28
hello_timer_hook(timer * timer)
29
{
30
  ospf_hello_send(timer->data, OHS_HELLO, NULL);
31 32
}

33
static void
Ondřej Filip's avatar
Ondřej Filip committed
34
wait_timer_hook(timer * timer)
35
{
Ondřej Filip's avatar
Ondřej Filip committed
36
  struct ospf_iface *ifa = (struct ospf_iface *) timer->data;
37
  struct proto *p = &ifa->oa->po->proto;
38

Ondřej Filip's avatar
Ondřej Filip committed
39 40
  OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->iface->name);
  ospf_iface_sm(ifa, ISM_WAITF);
41 42
}

43 44
static void ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa);

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
u32
rxbufsize(struct ospf_iface *ifa)
{
  switch(ifa->rxbuf)
  {
    case OSPF_RXBUF_NORMAL:
      return (ifa->iface->mtu * 2);
      break;
    case OSPF_RXBUF_LARGE:
      return OSPF_MAX_PKT_SIZE;
      break;
    default:
      return ifa->rxbuf;
      break;
  }
}

62 63 64 65 66 67 68 69 70 71
struct nbma_node *
find_nbma_node_in(list *nnl, ip_addr ip)
{
  struct nbma_node *nn;
  WALK_LIST(nn, *nnl)
    if (ipa_equal(nn->ip, ip))
      return nn;
  return NULL;
}

72
static int
73
ospf_sk_open(struct ospf_iface *ifa)
74
{
75
  sock *sk = sk_new(ifa->pool);
76 77
  sk->type = SK_IP;
  sk->dport = OSPF_PROTO;
78
  sk->saddr = IPA_NONE;
79

80 81
  sk->tos = ifa->cf->tx_tos;
  sk->priority = ifa->cf->tx_priority;
82 83 84 85 86
  sk->rx_hook = ospf_rx_hook;
  sk->tx_hook = ospf_tx_hook;
  sk->err_hook = ospf_err_hook;
  sk->iface = ifa->iface;
  sk->rbsize = rxbufsize(ifa);
87
  sk->tbsize = rxbufsize(ifa);
88
  sk->data = (void *) ifa;
89
  sk->flags = SKF_LADDR_RX | (ifa->check_ttl ? SKF_TTL_RX : 0);
90
  sk->ttl = ifa->cf->ttl_security ? 255 : -1;
91 92

  if (sk_open(sk) != 0)
93 94
    goto err;

95 96
#ifdef OSPFv3
  /* 12 is an offset of the checksum in an OSPF packet */
97
  if (sk_set_ipv6_checksum(sk, 12) < 0)
98 99 100
    goto err;
#endif

Ondřej Zajíček's avatar
Ondřej Zajíček committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
  /*
   * For OSPFv2: When sending a packet, it is important to have a
   * proper source address. We expect that when we send one-hop
   * unicast packets, OS chooses a source address according to the
   * destination address (to be in the same prefix). We also expect
   * that when we send multicast packets, OS uses the source address
   * from sk->saddr registered to OS by sk_setup_multicast(). This
   * behavior is needed to implement multiple virtual ifaces (struct
   * ospf_iface) on one physical iface and is signalized by
   * CONFIG_MC_PROPER_SRC.
   *
   * If this behavior is not available (for example on BSD), we create
   * non-stub iface just for the primary IP address (see
   * ospf_iface_stubby()) and we expect OS to use primary IP address
   * as a source address for both unicast and multicast packets.
   *
   * FIXME: the primary IP address is currently just the
   * lexicographically smallest address on an interface, it should be
   * signalized by sysdep code which one is really the primary.
   */

122
  sk->saddr = ifa->addr->ip;
123
  if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))
124
  {
125 126 127 128 129 130 131 132 133 134
    if (ifa->cf->real_bcast)
    {
      ifa->all_routers = ifa->addr->brd;

      if (sk_set_broadcast(sk, 1) < 0)
        goto err;
    }
    else
    {
      ifa->all_routers = AllSPFRouters;
135
      sk->ttl = ifa->cf->ttl_security ? 255 : 1;
136

137 138
      if (sk_setup_multicast(sk) < 0)
        goto err;
139

140 141 142
      if (sk_join_group(sk, ifa->all_routers) < 0)
        goto err;
    }
143
  }
144

145 146 147
  ifa->sk = sk;
  ifa->sk_dr = 0;
  return 1;
148 149

 err:
150 151 152 153 154 155 156 157 158 159 160 161 162
  rfree(sk);
  return 0;
}

static inline void
ospf_sk_join_dr(struct ospf_iface *ifa)
{
  if (ifa->sk_dr)
    return;

  sk_join_group(ifa->sk, AllDRouters);
  ifa->sk_dr = 1;
}
163

164 165 166 167 168 169 170 171 172 173
static inline void
ospf_sk_leave_dr(struct ospf_iface *ifa)
{
  if (!ifa->sk_dr)
    return;

  sk_leave_group(ifa->sk, AllDRouters);
  ifa->sk_dr = 0;
}

Ondřej Filip's avatar
Ondřej Filip committed
174 175
static void
ospf_iface_down(struct ospf_iface *ifa)
176
{
Ondřej Filip's avatar
Ondřej Filip committed
177
  struct ospf_neighbor *n, *nx;
178 179
  struct proto_ospf *po = ifa->oa->po;
  struct proto *p = &po->proto;
Ondřej Filip's avatar
Ondřej Filip committed
180
  struct ospf_iface *iff;
181

182 183
  if (ifa->type != OSPF_IT_VLINK)
  {
184 185 186 187 188 189 190
#ifdef OSPFv2
    OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
	       ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
#else
    OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
	       ifa->iface->name, ifa->instance_id, ifa->oa->areaid);
#endif
191 192

    /* First of all kill all the related vlinks */
193 194
    WALK_LIST(iff, po->iface_list)
    {
195
      if ((iff->type == OSPF_IT_VLINK) && (iff->vifa == ifa))
196
	ospf_iface_sm(iff, ISM_DOWN);
197 198 199
    }
  }

Ondřej Filip's avatar
Ondřej Filip committed
200
  WALK_LIST_DELSAFE(n, nx, ifa->neigh_list)
201
  {
Martin Mareš's avatar
Martin Mareš committed
202
    OSPF_TRACE(D_EVENTS, "Removing neighbor %I", n->ip);
203 204
    ospf_neigh_remove(n);
  }
205

206 207 208 209 210 211 212 213 214
  if (ifa->hello_timer)
    tm_stop(ifa->hello_timer);

  if (ifa->poll_timer)
    tm_stop(ifa->poll_timer);

  if (ifa->wait_timer)
    tm_stop(ifa->wait_timer);

215
  if (ifa->type == OSPF_IT_VLINK)
Ondřej Filip's avatar
Ondřej Filip committed
216
  {
217
    ifa->vifa = NULL;
Ondřej Filip's avatar
Ondřej Filip committed
218
    ifa->iface = NULL;
219 220
    ifa->addr = NULL;
    ifa->sk = NULL;
221
    ifa->cost = 0;
222
    ifa->vip = IPA_NONE;
Ondřej Filip's avatar
Ondřej Filip committed
223
  }
224 225 226 227 228 229 230

  ifa->rt_pos_beg = 0;
  ifa->rt_pos_end = 0;
#ifdef OSPFv3
  ifa->px_pos_beg = 0;
  ifa->px_pos_end = 0;
#endif
231 232 233
}


234
void
235 236
ospf_iface_remove(struct ospf_iface *ifa)
{
237 238 239 240
  struct proto *p = &ifa->oa->po->proto;
  if (ifa->type == OSPF_IT_VLINK)
    OSPF_TRACE(D_EVENTS, "Removing vlink to %R via area %R", ifa->vid, ifa->voa->areaid);

241 242 243 244 245
  ospf_iface_sm(ifa, ISM_DOWN);
  rem_node(NODE ifa);
  rfree(ifa->pool);
}

246 247 248 249
void
ospf_iface_shutdown(struct ospf_iface *ifa)
{
  if (ifa->state > OSPF_IS_DOWN)
250
    ospf_hello_send(ifa, OHS_SHUTDOWN, NULL);
251 252
}

253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
/**
 * ospf_iface_chstate - handle changes of interface state
 * @ifa: OSPF interface
 * @state: new state
 *
 * Many actions must be taken according to interface state changes. New network
 * LSAs must be originated, flushed, new multicast sockets to listen for messages for
 * %ALLDROUTERS have to be opened, etc.
 */
void
ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
{
  struct proto_ospf *po = ifa->oa->po;
  struct proto *p = &po->proto;
  u8 oldstate = ifa->state;

  if (oldstate == state)
    return;

  ifa->state = state;

  if (ifa->type == OSPF_IT_VLINK)
    OSPF_TRACE(D_EVENTS, "Changing state of virtual link %R from %s to %s",
	       ifa->vid, ospf_is[oldstate], ospf_is[state]);
Ondřej Filip's avatar
Ondřej Filip committed
277
  else
278 279 280
    OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
	       ifa->iface->name, ospf_is[oldstate], ospf_is[state]);

281
  if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk)
282 283 284 285 286 287 288 289
  {
    if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))
      ospf_sk_join_dr(ifa);
    else
      ospf_sk_leave_dr(ifa);
  }

  if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL))
Ondřej Filip's avatar
Ondřej Filip committed
290
  {
291 292 293 294 295 296 297
    ifa->net_lsa->lsa.age = LSA_MAXAGE;
    if (state >= OSPF_IS_WAITING)
      ospf_lsupd_flush_nlsa(po, ifa->net_lsa);

    if (can_flush_lsa(po))
      flush_lsa(ifa->net_lsa, po);
    ifa->net_lsa = NULL;
Ondřej Filip's avatar
Ondřej Filip committed
298
  }
299 300 301 302 303 304

  if ((oldstate > OSPF_IS_LOOP) && (state <= OSPF_IS_LOOP))
    ospf_iface_down(ifa);

  schedule_rt_lsa(ifa->oa);
  // FIXME flushling of link LSA
305 306
}

Ondřej Filip's avatar
Ondřej Filip committed
307
/**
Ondřej Filip's avatar
Ondřej Filip committed
308
 * ospf_iface_sm - OSPF interface state machine
Ondřej Filip's avatar
Ondřej Filip committed
309 310 311
 * @ifa: OSPF interface
 * @event: event comming to state machine
 *
312 313 314 315 316
 * This fully respects 9.3 of RFC 2328 except we have slightly
 * different handling of %DOWN and %LOOP state. We remove intefaces
 * that are %DOWN. %DOWN state is used when an interface is waiting
 * for a lock. %LOOP state is used when an interface does not have a
 * link.
Ondřej Filip's avatar
Ondřej Filip committed
317
 */
318
void
Ondřej Filip's avatar
Ondřej Filip committed
319
ospf_iface_sm(struct ospf_iface *ifa, int event)
320
{
Ondrej Filip's avatar
Ondrej Filip committed
321 322
  DBG("SM on %s %s. Event is '%s'\n", (ifa->type == OSPF_IT_VLINK) ? "vlink" : "iface",
    ifa->iface ? ifa->iface->name : "(none)" , ospf_ism[event]);
323

Ondřej Filip's avatar
Ondřej Filip committed
324
  switch (event)
325
  {
Ondřej Filip's avatar
Ondřej Filip committed
326
  case ISM_UP:
327
    if (ifa->state <= OSPF_IS_LOOP)
Ondřej Filip's avatar
Ondřej Filip committed
328 329
    {
      /* Now, nothing should be adjacent */
330
      if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP) || (ifa->type == OSPF_IT_VLINK))
331
      {
Ondřej Filip's avatar
Ondřej Filip committed
332
	ospf_iface_chstate(ifa, OSPF_IS_PTP);
333
      }
Ondřej Filip's avatar
Ondřej Filip committed
334
      else
335
      {
Ondřej Filip's avatar
Ondřej Filip committed
336 337 338 339 340
	if (ifa->priority == 0)
	  ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
	else
	{
	  ospf_iface_chstate(ifa, OSPF_IS_WAITING);
341 342
	  if (ifa->wait_timer)
	    tm_start(ifa->wait_timer, ifa->waitint);
Ondřej Filip's avatar
Ondřej Filip committed
343
	}
344
      }
345

346 347
      if (ifa->hello_timer)
	tm_start(ifa->hello_timer, ifa->helloint);
348 349 350 351

      if (ifa->poll_timer)
	tm_start(ifa->poll_timer, ifa->pollint);

352
      ospf_hello_send(ifa, OHS_HELLO, NULL);
353
      schedule_link_lsa(ifa);
Ondřej Filip's avatar
Ondřej Filip committed
354 355
    }
    break;
356

Ondřej Filip's avatar
Ondřej Filip committed
357 358 359 360 361 362 363
  case ISM_BACKS:
  case ISM_WAITF:
    if (ifa->state == OSPF_IS_WAITING)
    {
      bdr_election(ifa);
    }
    break;
364

Ondřej Filip's avatar
Ondřej Filip committed
365 366 367 368 369
  case ISM_NEICH:
    if ((ifa->state == OSPF_IS_DROTHER) || (ifa->state == OSPF_IS_DR) ||
	(ifa->state == OSPF_IS_BACKUP))
    {
      bdr_election(ifa);
370
      schedule_rt_lsa(ifa->oa);
Ondřej Filip's avatar
Ondřej Filip committed
371 372
    }
    break;
373

374
  case ISM_LOOP:
375
    if ((ifa->state > OSPF_IS_LOOP) && ifa->check_link)
376
      ospf_iface_chstate(ifa, OSPF_IS_LOOP);
Ondřej Filip's avatar
Ondřej Filip committed
377
    break;
378

Ondřej Filip's avatar
Ondřej Filip committed
379
  case ISM_UNLOOP:
380 381 382 383 384 385
    /* Immediate go UP */
    if (ifa->state == OSPF_IS_LOOP)
      ospf_iface_sm(ifa, ISM_UP);
    break;

  case ISM_DOWN:
Ondřej Filip's avatar
Ondřej Filip committed
386 387
    ospf_iface_chstate(ifa, OSPF_IS_DOWN);
    break;
388

Ondřej Filip's avatar
Ondřej Filip committed
389 390 391
  default:
    bug("OSPF_I_SM - Unknown event?");
    break;
392
  }
Ondřej Filip's avatar
Ondřej Filip committed
393

394 395
}

396
static u8
397
ospf_iface_classify_int(struct iface *ifa, struct ifa *addr)
398
{
399
  if (ipa_nonzero(addr->opposite))
400
    return (ifa->flags & IF_MULTICAST) ? OSPF_IT_PTP :  OSPF_IT_PTMP;
401

Ondřej Filip's avatar
Ondřej Filip committed
402 403 404 405 406
  if ((ifa->flags & (IF_MULTIACCESS | IF_MULTICAST)) ==
      (IF_MULTIACCESS | IF_MULTICAST))
    return OSPF_IT_BCAST;

  if ((ifa->flags & (IF_MULTIACCESS | IF_MULTICAST)) == IF_MULTIACCESS)
407
    return OSPF_IT_NBMA;
Ondřej Filip's avatar
Ondřej Filip committed
408

409 410 411
  return OSPF_IT_PTP;
}

412 413 414 415 416 417 418
static inline u8
ospf_iface_classify(u8 type, struct ifa *addr)
{
  return (type != OSPF_IT_UNDEF) ? type : ospf_iface_classify_int(addr->iface, addr);
}


Ondřej Filip's avatar
Ondřej Filip committed
419 420
struct ospf_iface *
ospf_iface_find(struct proto_ospf *p, struct iface *what)
421 422 423
{
  struct ospf_iface *i;

424
  WALK_LIST(i, p->iface_list) if ((i->iface == what) && (i->type != OSPF_IT_VLINK))
Ondřej Filip's avatar
Ondřej Filip committed
425
    return i;
426 427 428
  return NULL;
}

Ondřej Filip's avatar
Ondřej Filip committed
429 430 431 432
static void
ospf_iface_add(struct object_lock *lock)
{
  struct ospf_iface *ifa = lock->data;
433
  struct proto_ospf *po = ifa->oa->po;
Ondřej Filip's avatar
Ondřej Filip committed
434 435
  struct proto *p = &po->proto;

436 437
  /* Open socket if interface is not stub */
  if (! ifa->stub && ! ospf_sk_open(ifa))
438 439 440
  {
    log(L_ERR "%s: Socket open failed on interface %s, declaring as stub", p->name, ifa->iface->name);
    ifa->ioprob = OSPF_I_SK;
Ondřej Filip's avatar
Ondřej Filip committed
441 442 443
    ifa->stub = 1;
  }

444 445 446 447 448 449 450 451 452 453 454
  if (! ifa->stub)
  {
    ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);

    if (ifa->type == OSPF_IT_NBMA)
      ifa->poll_timer = tm_new_set(ifa->pool, poll_timer_hook, ifa, 0, ifa->pollint);

    if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
      ifa->wait_timer = tm_new_set(ifa->pool, wait_timer_hook, ifa, 0, 0);
  }

455
  /* Do iface UP, unless there is no link and we use link detection */
456
  ospf_iface_sm(ifa, (ifa->check_link && !(ifa->iface->flags & IF_LINK_UP)) ? ISM_LOOP : ISM_UP);
Ondřej Filip's avatar
Ondřej Filip committed
457 458
}

459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
static inline void
add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
{
  struct nbma_node *n = mb_alloc(ifa->pool, sizeof(struct nbma_node));
  add_tail(&ifa->nbma_list, NODE n);
  n->ip = src->ip;
  n->eligible = src->eligible;
  n->found = found;
}

static int
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
{
  if (! addr)
    return 0;

475 476 477 478
  /* a host/loopback address */
  if (addr->flags & IA_HOST)
    return 1;

479 480 481 482 483 484 485 486 487 488 489 490 491
  /*
   * We cannot properly support multiple OSPF ifaces on real iface
   * with multiple prefixes, therefore we force OSPF ifaces with
   * non-primary IP prefixes to be stub.
   */
#if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
  if (! (addr->flags & IA_PRIMARY))
    return 1;
#endif

  return ip->stub;
}

Ondřej Filip's avatar
Ondřej Filip committed
492
void
493
ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
Ondřej Filip's avatar
Ondřej Filip committed
494
{
495 496 497 498
  struct proto *p = &oa->po->proto;
  struct iface *iface = addr ? addr->iface : NULL;
  struct pool *pool;

Ondřej Filip's avatar
Ondřej Filip committed
499
  struct ospf_iface *ifa;
500
  struct nbma_node *nb;
Ondřej Filip's avatar
Ondřej Filip committed
501 502
  struct object_lock *lock;

503 504 505 506 507 508 509 510 511 512 513 514
  if (ip->type == OSPF_IT_VLINK)
    OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
  else
  {
#ifdef OSPFv2
    OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
	       iface->name, addr->prefix, addr->pxlen, oa->areaid);
#else
    OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
	       iface->name, ip->instance_id, oa->areaid);
#endif
  }
515

516
  pool = rp_new(p->pool, "OSPF Interface");
517
  ifa = mb_allocz(pool, sizeof(struct ospf_iface));
Ondřej Filip's avatar
Ondřej Filip committed
518
  ifa->iface = iface;
519
  ifa->addr = addr;
520 521
  ifa->oa = oa;
  ifa->cf = ip;
522
  ifa->pool = pool;
Ondřej Filip's avatar
Ondřej Filip committed
523 524 525 526 527 528 529 530 531

  ifa->cost = ip->cost;
  ifa->rxmtint = ip->rxmtint;
  ifa->inftransdelay = ip->inftransdelay;
  ifa->priority = ip->priority;
  ifa->helloint = ip->helloint;
  ifa->pollint = ip->pollint;
  ifa->strictnbma = ip->strictnbma;
  ifa->waitint = ip->waitint;
532
  ifa->deadint = ip->deadint;
533
  ifa->stub = ospf_iface_stubby(ip, addr);
534 535
  ifa->ioprob = OSPF_I_OK;
  ifa->rxbuf = ip->rxbuf;
536
  ifa->check_link = ip->check_link;
537
  ifa->ecmp_weight = ip->ecmp_weight;
538
  ifa->check_ttl = (ip->ttl_security == 1);
539 540

#ifdef OSPFv2
Ondřej Filip's avatar
Ondřej Filip committed
541
  ifa->autype = ip->autype;
542
  ifa->passwords = ip->passwords;
543
  ifa->ptp_netmask = addr ? !(addr->flags & IA_PEER) : 0;
544 545
  if (ip->ptp_netmask < 2)
    ifa->ptp_netmask = ip->ptp_netmask;
546 547 548 549 550 551
#endif

#ifdef OSPFv3
  ifa->instance_id = ip->instance_id;
#endif

552
  ifa->type = ospf_iface_classify(ip->type, addr);
553

554 555
  /* Check validity of interface type */
  int old_type = ifa->type;
556
  u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST;
557

558
#ifdef OSPFv2
559
  if ((ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
560
    ifa->type = OSPF_IT_PTP;
561

562
  if ((ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
563
    ifa->type = OSPF_IT_PTMP;
564 565
#endif

566
  if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag))
567 568
    ifa->type = OSPF_IT_NBMA;

569
  if ((ifa->type == OSPF_IT_PTP) && !(iface->flags & if_multi_flag))
570 571 572 573 574 575
    ifa->type = OSPF_IT_PTMP;

  if (ifa->type != old_type)
    log(L_WARN "%s: Cannot use interface %s as %s, forcing %s",
	p->name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);

576 577
  /* Assign iface ID, for vlinks, this is ugly hack */
  ifa->iface_id = (ifa->type != OSPF_IT_VLINK) ? iface->index : oa->po->last_vlink_id++;
578

Ondřej Filip's avatar
Ondřej Filip committed
579 580
  init_list(&ifa->neigh_list);
  init_list(&ifa->nbma_list);
581

Ondřej Filip's avatar
Ondřej Filip committed
582
  WALK_LIST(nb, ip->nbma_list)
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
  {
    /* In OSPFv3, addr is link-local while configured neighbors could
       have global IP (although RFC 5340 C.5 says link-local addresses
       should be used). Because OSPFv3 iface is not subnet-specific,
       there is no need for ipa_in_net() check */

#ifdef OSPFv2
    if (!ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
      continue;
#else
    if (!ipa_has_link_scope(nb->ip))
      log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip);
#endif

    add_nbma_node(ifa, nb, 0);
  }
Ondřej Filip's avatar
Ondřej Filip committed
599 600

  ifa->state = OSPF_IS_DOWN;
601
  add_tail(&oa->po->iface_list, NODE ifa);
Ondřej Filip's avatar
Ondřej Filip committed
602 603 604

  if (ifa->type == OSPF_IT_VLINK)
  {
605
    ifa->voa = ospf_find_area(oa->po, ip->voa);
Ondřej Filip's avatar
Ondřej Filip committed
606
    ifa->vid = ip->vid;
607 608 609

    ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);

610
    return;			/* Don't lock, don't add sockets */
Ondřej Filip's avatar
Ondřej Filip committed
611 612
  }

613 614 615 616 617 618 619
  /*
   * In some cases we allow more ospf_ifaces on one physical iface.
   * In OSPFv2, if they use different IP address prefix.
   * In OSPFv3, if they use different instance_id.
   * Therefore, we store such info to lock->addr field.
   */

620
  lock = olock_new(pool);
621 622 623 624 625
#ifdef OSPFv2
  lock->addr = ifa->addr->prefix;
#else /* OSPFv3 */
  lock->addr = _MI(0,0,0,ifa->instance_id);
#endif
Ondřej Filip's avatar
Ondřej Filip committed
626 627 628 629 630 631 632 633 634
  lock->type = OBJLOCK_IP;
  lock->port = OSPF_PROTO;
  lock->iface = iface;
  lock->data = ifa;
  lock->hook = ospf_iface_add;

  olock_acquire(lock);
}

635 636 637 638 639 640 641 642 643 644 645 646
static void
ospf_iface_change_timer(timer *tm, unsigned val)
{
  if (!tm)
    return;

  tm->recurrent = val;

  if (tm->expires)
    tm_start(tm, val);
}

647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
int
ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
{
  struct proto *p = &ifa->oa->po->proto;
  struct nbma_node *nb, *nbx;
  char *ifname = (ifa->type != OSPF_IT_VLINK) ? ifa->iface->name : "vlink";

  /* Type could be changed in ospf_iface_new(),
     but if config values are same then also results are same */
  int old_type = ospf_iface_classify(ifa->cf->type, ifa->addr);
  int new_type = ospf_iface_classify(new->type, ifa->addr);
  if (old_type != new_type)
    return 0;

  int new_stub = ospf_iface_stubby(new, ifa->addr);
  if (ifa->stub != new_stub)
    return 0;

665 666 667
  /* Change of these options would require to reset the iface socket */
  if ((new->real_bcast != ifa->cf->real_bcast) ||
      (new->tx_tos != ifa->cf->tx_tos) ||
668 669
      (new->tx_priority != ifa->cf->tx_priority) ||
      (new->ttl_security != ifa->cf->ttl_security))
670 671
    return 0;

672 673 674 675 676 677 678 679 680 681 682
  ifa->cf = new;
  ifa->marked = 0;


  /* HELLO TIMER */
  if (ifa->helloint != new->helloint)
  {
    OSPF_TRACE(D_EVENTS, "Changing hello interval on interface %s from %d to %d",
	       ifname, ifa->helloint, new->helloint);

    ifa->helloint = new->helloint;
683
    ospf_iface_change_timer(ifa->hello_timer, ifa->helloint);
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
  }

  /* RXMT TIMER */
  if (ifa->rxmtint != new->rxmtint)
  {
    OSPF_TRACE(D_EVENTS, "Changing retransmit interval on interface %s from %d to %d",
	       ifname, ifa->rxmtint, new->rxmtint);

    ifa->rxmtint = new->rxmtint;
  }

  /* POLL TIMER */
  if (ifa->pollint != new->pollint)
  {
    OSPF_TRACE(D_EVENTS, "Changing poll interval on interface %s from %d to %d",
	       ifname, ifa->pollint, new->pollint);

701 702
    ifa->pollint = new->pollint;
    ospf_iface_change_timer(ifa->poll_timer, ifa->pollint);
703 704 705 706 707 708 709 710 711
  }

  /* WAIT TIMER */
  if (ifa->waitint != new->waitint)
  {
    OSPF_TRACE(D_EVENTS, "Changing wait interval on interface %s from %d to %d",
	       ifname, ifa->waitint, new->waitint);

    ifa->waitint = new->waitint;
712
    if (ifa->wait_timer && ifa->wait_timer->expires)
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797
      tm_start(ifa->wait_timer, ifa->waitint);
  }

  /* DEAD TIMER */
  if (ifa->deadint != new->deadint)
  {
    OSPF_TRACE(D_EVENTS, "Changing dead interval on interface %s from %d to %d",
	       ifname, ifa->deadint, new->deadint);
    ifa->deadint = new->deadint;
  }

  /* INFTRANS */
  if (ifa->inftransdelay != new->inftransdelay)
  {
    OSPF_TRACE(D_EVENTS, "Changing transmit delay on interface %s from %d to %d",
		     ifname, ifa->inftransdelay, new->inftransdelay);
    ifa->inftransdelay = new->inftransdelay;
  }

#ifdef OSPFv2	
  /* AUTHENTICATION */
  if (ifa->autype != new->autype)
  {
    OSPF_TRACE(D_EVENTS, "Changing authentication type on interface %s", ifname);
    ifa->autype = new->autype;
  }

  /* Update passwords */
  ifa->passwords = new->passwords;
#endif

  /* Remaining options are just for proper interfaces */
  if (ifa->type == OSPF_IT_VLINK)
    return 1;


  /* COST */
  if (ifa->cost != new->cost)
  {
    OSPF_TRACE(D_EVENTS, "Changing cost on interface %s from %d to %d",
	       ifname, ifa->cost, new->cost);

    ifa->cost = new->cost;
  }

  /* PRIORITY */
  if (ifa->priority != new->priority)
  {
    OSPF_TRACE(D_EVENTS, "Changing priority on interface %s from %d to %d",
	       ifname, ifa->priority, new->priority);
    ifa->priority = new->priority;
  }

  /* STRICT NBMA */
  if (ifa->strictnbma != new->strictnbma)
  {
    OSPF_TRACE(D_EVENTS, "Changing NBMA strictness on interface %s", ifname);
    ifa->strictnbma = new->strictnbma;
  }

  /* NBMA LIST - remove or update old */
  WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list)
  {
    struct nbma_node *nb2 = find_nbma_node_in(&new->nbma_list, nb->ip);
    if (nb2)
    {
      if (nb->eligible != nb2->eligible)
      {
	OSPF_TRACE(D_EVENTS, "Changing eligibility of neighbor %I on interface %s",
		   nb->ip, ifname);
	nb->eligible = nb2->eligible;
      }
    }
    else
    {
      OSPF_TRACE(D_EVENTS, "Removing NBMA neighbor %I on interface %s",
		       nb->ip, ifname);
      rem_node(NODE nb);
      mb_free(nb);
    }
  }

  /* NBMA LIST - add new */
  WALK_LIST(nb, new->nbma_list)
  {
798 799
    /* See related note in ospf_iface_new() */
#ifdef OSPFv2
800 801
    if (!ipa_in_net(nb->ip, ifa->addr->prefix, ifa->addr->pxlen))
      continue;
802 803 804 805
#else
    if (!ipa_has_link_scope(nb->ip))
      log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip);
#endif
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847

    if (! find_nbma_node(ifa, nb->ip))
    {
      OSPF_TRACE(D_EVENTS, "Adding NBMA neighbor %I on interface %s",
		 nb->ip, ifname);
      add_nbma_node(ifa, nb, !!find_neigh_by_ip(ifa, nb->ip));
    }
  }

  /* RX BUFF */
  if (ifa->rxbuf != new->rxbuf)
  {
    OSPF_TRACE(D_EVENTS, "Changing rxbuf interface %s from %d to %d",
	       ifname, ifa->rxbuf, new->rxbuf);
    ifa->rxbuf = new->rxbuf;
    ospf_iface_change_mtu(ifa->oa->po, ifa);
  }

  /* LINK */
  if (ifa->check_link != new->check_link)
  {
    OSPF_TRACE(D_EVENTS, "%s link check on interface %s",
	       new->check_link ? "Enabling" : "Disabling", ifname);
    ifa->check_link = new->check_link;

    if (!(ifa->iface->flags & IF_LINK_UP))
      ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP);
  }

  /* ECMP weight */
  if (ifa->ecmp_weight != new->ecmp_weight)
  {
    OSPF_TRACE(D_EVENTS, "Changing ECMP weight of interface %s from %d to %d",
	       ifname, (int)ifa->ecmp_weight + 1, (int)new->ecmp_weight + 1);
    ifa->ecmp_weight = new->ecmp_weight;
  }

  /* instance_id is not updated - it is part of key */

  return 1;
}

848 849 850

#ifdef OSPFv2

851 852 853 854 855 856
static inline struct ospf_iface_patt *
ospf_iface_patt_find(struct ospf_area_config *ac, struct ifa *a)
{
  return (struct ospf_iface_patt *) iface_patt_find(&ac->patt_list, a->iface, a);
}

857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
void
ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
{
  struct proto_ospf *po = (struct proto_ospf *) p;

  if (a->flags & IA_SECONDARY)
    return;

  if (a->scope <= SCOPE_LINK)
    return;

  /* In OSPFv2, we create OSPF iface for each address. */
  if (flags & IF_CHANGE_UP)
  {
    int done = 0;
872 873
    struct ospf_area *oa;
    WALK_LIST(oa, po->area_list)
874
    {
875 876
      struct ospf_iface_patt *ip;
      if (ip = ospf_iface_patt_find(oa->ac, a))
877 878
      {
	if (!done)
879
	  ospf_iface_new(oa, a, ip);
880 881 882 883 884 885 886 887 888 889 890 891 892 893
	done++;
      }
    }

    if (done > 1)
      log(L_WARN "%s: Interface %s (IP %I) matches for multiple areas", p->name,  a->iface->name, a->ip);
  }

  if (flags & IF_CHANGE_DOWN)
  {
    struct ospf_iface *ifa, *ifx;
    WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
    {
      if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
894
	ospf_iface_remove(ifa);
895 896 897 898 899
      /* See a note in ospf_iface_notify() */
    }
  }
}

900 901 902 903 904 905 906 907 908 909
static struct ospf_iface *
ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a)
{
  struct ospf_iface *ifa;
  WALK_LIST(ifa, oa->po->iface_list)
    if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->type != OSPF_IT_VLINK))
      return ifa;

  return NULL;
}
910

911 912
void
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
913
{
914 915 916 917 918
  struct ospf_iface_patt *ip;
  struct iface *iface;
  struct ifa *a;

  WALK_LIST(iface, iface_list)
919 920 921 922
  {
    if (! (iface->flags & IF_UP))
      continue;

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
    WALK_LIST(a, iface->addrs)
    {
      if (a->flags & IA_SECONDARY)
	continue;

      if (a->scope <= SCOPE_LINK)
	continue;

      if (ip = ospf_iface_patt_find(oa->ac, a))
      {
	/* Main inner loop */
	struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a);
	if (ifa)
	{
	  if (ospf_iface_reconfigure(ifa, ip))
	    continue;

	  /* Hard restart */
	  ospf_iface_shutdown(ifa);
	  ospf_iface_remove(ifa);
	}
	
	ospf_iface_new(oa, a, ip);
      }
    }
948
  }
949 950
}

951 952 953 954 955

#else /* OSPFv3 */

struct ospf_iface_patt *
ospf_iface_patt_find(struct ospf_area_config *ac, struct iface *iface, int iid)
956
{
957 958 959 960 961 962 963 964
  struct ospf_iface_patt *pt, *res = NULL;

  WALK_LIST(pt, ac->patt_list)
    if ((pt->instance_id >= iid) && (iface_patt_match(&pt->i, iface, NULL)) &&
	(!res || (pt->instance_id < res->instance_id)))
      res = pt;

  return res;
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
}

void
ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
{
  struct proto_ospf *po = (struct proto_ospf *) p;

  if (a->flags & IA_SECONDARY)
    return;

  if (a->scope < SCOPE_LINK)
    return;

  /* In OSPFv3, we create OSPF iface for link-local address,
     other addresses are used for link-LSA. */
  if (a->scope == SCOPE_LINK)
  {
    if (flags & IF_CHANGE_UP)
    {
984 985
      int done0 = 0;
      struct ospf_area *oa;
986

987
      WALK_LIST(oa, po->area_list)
988
      {
989
	int iid = 0;
990

991 992
	struct ospf_iface_patt *ip;
	while (ip = ospf_iface_patt_find(oa->ac, a->iface, iid))
993
	{
994 995 996 997
	  ospf_iface_new(oa, a, ip);
	  if (ip->instance_id == 0)
	    done0++;
	  iid = ip->instance_id + 1;
998 999
	}
      }
1000 1001 1002 1003

      if (done0 > 1)
	log(L_WARN "%s: Interface %s matches for multiple areas",
	    p->name,  a->iface->name);
1004 1005 1006 1007 1008 1009 1010 1011
    }

    if (flags & IF_CHANGE_DOWN)
    {
      struct ospf_iface *ifa, *ifx;
      WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
      {
	if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
1012
	  ospf_iface_remove(ifa);
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
	/* See a note in ospf_iface_notify() */
      }
    }
  }
  else
  {
    struct ospf_iface *ifa;
    WALK_LIST(ifa, po->iface_list)
    {
      if (ifa->iface == a->iface)
      {
	schedule_rt_lsa(ifa->oa);
	/* Event 5 from RFC5340 4.4.3. */
	schedule_link_lsa(ifa);
	return;
      }
    }
  }
}

1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
static struct ospf_iface *
ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a, int iid)
{
  struct ospf_iface *ifa;
  WALK_LIST(ifa, oa->po->iface_list)
    if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->instance_id == iid) && (ifa->type != OSPF_IT_VLINK))
      return ifa;

  return NULL;
}
1043

1044
void
1045 1046 1047 1048 1049 1050 1051
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
{
  struct ospf_iface_patt *ip;
  struct iface *iface;
  struct ifa *a;

  WALK_LIST(iface, iface_list)
1052 1053 1054 1055
  {
    if (! (iface->flags & IF_UP))
      continue;

1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
    WALK_LIST(a, iface->addrs)
    {
      if (a->flags & IA_SECONDARY)
	continue;

      if (a->scope != SCOPE_LINK)
	continue;

      int iid = 0;
      while (ip = ospf_iface_patt_find(nac, iface, iid))
      {
	iid = ip->instance_id + 1;

	/* Main inner loop */
	struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a, ip->instance_id);
	if (ifa)
	{
	  if (ospf_iface_reconfigure(ifa, ip))
	    continue;

	  /* Hard restart */
	  ospf_iface_shutdown(ifa);
	  ospf_iface_remove(ifa);
	}

	ospf_iface_new(oa, a, ip);
      }
    }
1084
  }
1085 1086 1087 1088 1089
}

#endif

static void
1090 1091 1092 1093 1094
ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
{
  struct proto *p = &po->proto;
  struct ospf_packet *op;
  struct ospf_neighbor *n;
1095
  OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->iface->name);
1096 1097

  if (ifa->sk)
1098
  {
1099
    ifa->sk->rbsize = rxbufsize(ifa);
1100
    ifa->sk->tbsize = rxbufsize(ifa);
1101
    sk_reallocate(ifa->sk);
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
  }

  WALK_LIST(n, ifa->neigh_list)
  {
    op = (struct ospf_packet *) n->ldbdes;
    n->ldbdes = mb_allocz(n->pool, ifa->iface->mtu);

    if (ntohs(op->length) <= ifa->iface->mtu)	/* If the packet in old buffer is bigger, let it filled by zeros */
      memcpy(n->ldbdes, op, ifa->iface->mtu);	/* If the packet is old is same or smaller, copy it */

Ondřej Zajíček's avatar
Ondřej Zajíček committed
1112
    mb_free(op);
1113 1114 1115
  }
}

1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
static void
ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa)
{
  if (flags & IF_CHANGE_DOWN)
  {
    ospf_iface_remove(ifa);
    return;
  }

  if (flags & IF_CHANGE_LINK)
    ospf_iface_sm(ifa, (ifa->iface->flags & IF_LINK_UP) ? ISM_UNLOOP : ISM_LOOP);

  if (flags & IF_CHANGE_MTU)
    ospf_iface_change_mtu(po, ifa);
}

1132
void
1133
ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
1134
{
Ondřej Filip's avatar
Ondřej Filip committed
1135
  struct proto_ospf *po = (struct proto_ospf *) p;
1136 1137

  /*
1138 1139
  if (iface->flags & IF_IGNORE)
    return;
1140
  */
1141

1142
  /* Going up means that there are no such ifaces yet */
1143 1144
  if (flags & IF_CHANGE_UP)
    return;
1145

1146 1147 1148 1149
  struct ospf_iface *ifa, *ifx;
  WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
    if ((ifa->type != OSPF_IT_VLINK) && (ifa->iface == iface))
      ospf_iface_notify(po, flags, ifa);
1150

1151 1152 1153
  /* We use here that even shutting down iface also shuts down
     the vlinks, but vlinks are not freed and stays in the
     iface_list even when down */
1154 1155
}

1156 1157 1158
void
ospf_iface_info(struct ospf_iface *ifa)
{
1159
  char *more = "";
1160 1161 1162

  if (ifa->strictnbma &&
      ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)))
1163 1164 1165 1166 1167
    more = " (strict)";

  if (ifa->cf->real_bcast &&
      ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP)))
    more = " (real)";
Ondřej Filip's avatar
Ondřej Filip committed
1168

1169 1170
  if (ifa->type == OSPF_IT_VLINK)
  {
1171
    cli_msg(-1015, "Virtual link to %R:", ifa->vid);
1172
    cli_msg(-1015, "\tPeer IP: %I", ifa->vip);
1173
    cli_msg(-1015, "\tTransit area: %R (%u)", ifa->voa->areaid,
1174
	    ifa->voa->areaid);
1175 1176
    cli_msg(-1015, "\tInterface: \"%s\"",
	    (ifa->iface ? ifa->iface->name : "(none)"));
1177 1178 1179
  }
  else
  {
1180
#ifdef OSPFv2
1181
    if (ifa->addr->flags & IA_PEER)
1182 1183 1184 1185 1186 1187
      cli_msg(-1015, "Interface %s (peer %I)", ifa->iface->name, ifa->addr->opposite);
    else
      cli_msg(-1015, "Interface %s (%I/%d)", ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen);
#else /* OSPFv3 */
    cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id);
#endif
1188
    cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more);
1189
    cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid);
1190
  }
1191
  cli_msg(-1015, "\tState: %s%s", ospf_is[ifa->state], ifa->stub ? " (stub)" : "");
Ondřej Filip's avatar
Ondřej Filip committed
1192 1193
  cli_msg(-1015, "\tPriority: %u", ifa->priority);
  cli_msg(-1015, "\tCost: %u", ifa->cost);
1194 1195
  if (ifa->oa->po->ecmp)
    cli_msg(-1015, "\tECMP weight: %d", ((int) ifa->ecmp_weight) + 1);
Ondřej Filip's avatar
Ondřej Filip committed
1196
  cli_msg(-1015, "\tHello timer: %u", ifa->helloint);
1197

Ondřej Filip's avatar
Ondřej Filip committed
1198
  if (ifa->type == OSPF_IT_NBMA)
Ondřej Filip's avatar
Ondřej Filip committed
1199
  {
Ondřej Filip's avatar
Ondřej Filip committed
1200
    cli_msg(-1015, "\tPoll timer: %u", ifa->pollint);
Ondřej Filip's avatar
Ondřej Filip committed
1201
  }
Ondřej Filip's avatar
Ondřej Filip committed
1202
  cli_msg(-1015, "\tWait timer: %u", ifa->waitint);
1203
  cli_msg(-1015, "\tDead timer: %u", ifa->deadint);
Ondřej Filip's avatar
Ondřej Filip committed
1204 1205
  cli_msg(-1015, "\tRetransmit timer: %u", ifa->rxmtint);
  if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
Ondřej Filip's avatar
Ondřej Filip committed
1206
  {
1207
    cli_msg(-1015, "\tDesigned router (ID): %R", ifa->drid);
Ondřej Filip's avatar
Ondřej Filip committed
1208
    cli_msg(-1015, "\tDesigned router (IP): %I", ifa->drip);
1209
    cli_msg(-1015, "\tBackup designed router (ID): %R", ifa->bdrid);
Ondřej Filip's avatar
Ondřej Filip committed
1210
    cli_msg(-1015, "\tBackup designed router (IP): %I", ifa->bdrip);
Ondřej Filip's avatar
Ondřej Filip committed
1211
  }
1212
}
1213