Statistics
| Branch: | Revision:

iof-bird-daemon / proto / ospf / iface.c @ 48e5f32d

History | View | Annotate | Download (31.1 KB)

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

    
9
#include "ospf.h"
10

    
11
char *ospf_is[] = { "down", "loop", "waiting", "ptp", "drother",
12
  "backup", "dr"
13
};
14

    
15
char *ospf_ism[] = { "interface up", "wait timer fired", "backup seen",
16
  "neighbor change", "loop indicated", "unloop indicated", "interface down"
17
};
18

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

    
21
static void
22
poll_timer_hook(timer * timer)
23
{
24
  ospf_hello_send(timer->data, OHS_POLL, NULL);
25
}
26

    
27
static void
28
hello_timer_hook(timer * timer)
29
{
30
  ospf_hello_send(timer->data, OHS_HELLO, NULL);
31
}
32

    
33
static void
34
wait_timer_hook(timer * timer)
35
{
36
  struct ospf_iface *ifa = (struct ospf_iface *) timer->data;
37
  struct proto *p = &ifa->oa->po->proto;
38

    
39
  OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->ifname);
40
  ospf_iface_sm(ifa, ISM_WAITF);
41
}
42

    
43
static inline uint
44
ifa_tx_length(struct ospf_iface *ifa)
45
{
46
  return ifa->cf->tx_length ?: ifa->iface->mtu; 
47
}
48

    
49
static inline uint
50
ifa_bufsize(struct ospf_iface *ifa)
51
{
52
  uint bsize = ifa->cf->rx_buffer ?: ifa->iface->mtu;
53
  return MAX(bsize, ifa->tx_length);
54
}
55

    
56
int
57
ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen)
58
{
59
  plen += SIZE_OF_IP_HEADER;
60

    
61
#ifdef OSPFv2
62
  if (ifa->autype == OSPF_AUTH_CRYPT)
63
    plen += OSPF_AUTH_CRYPT_SIZE;
64
#endif
65

    
66
  if (plen <= ifa->sk->tbsize)
67
    return 0;
68

    
69
  if (ifa->cf->rx_buffer || (plen > 0xffff))
70
    return -1;
71

    
72
  plen = BIRD_ALIGN(plen, 1024);
73
  plen = MIN(plen, 0xffff);
74
  sk_set_tbsize(ifa->sk, plen);
75
  return 1;
76
}
77

    
78

    
79
struct nbma_node *
80
find_nbma_node_in(list *nnl, ip_addr ip)
81
{
82
  struct nbma_node *nn;
83
  WALK_LIST(nn, *nnl)
84
    if (ipa_equal(nn->ip, ip))
85
      return nn;
86
  return NULL;
87
}
88

    
89

    
90
static int
91
ospf_sk_open(struct ospf_iface *ifa)
92
{
93
  sock *sk = sk_new(ifa->pool);
94
  sk->type = SK_IP;
95
  sk->dport = OSPF_PROTO;
96
  sk->saddr = ifa->addr->ip;
97
  sk->iface = ifa->iface;
98

    
99
  sk->tos = ifa->cf->tx_tos;
100
  sk->priority = ifa->cf->tx_priority;
101
  sk->rx_hook = ospf_rx_hook;
102
  // sk->tx_hook = ospf_tx_hook;
103
  sk->err_hook = ospf_err_hook;
104
  sk->rbsize = sk->tbsize = ifa_bufsize(ifa);
105
  sk->data = (void *) ifa;
106
  sk->flags = SKF_LADDR_RX | (ifa->check_ttl ? SKF_TTL_RX : 0);
107
  sk->ttl = ifa->cf->ttl_security ? 255 : 1;
108

    
109
  if (sk_open(sk) < 0)
110
    goto err;
111

    
112
#ifdef OSPFv3
113
  /* 12 is an offset of the checksum in an OSPF packet */
114
  if (sk_set_ipv6_checksum(sk, 12) < 0)
115
    goto err;
116
#endif
117

    
118
  if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))
119
  {
120
    if (ifa->cf->real_bcast)
121
    {
122
      ifa->all_routers = ifa->addr->brd;
123

    
124
      if (sk_set_broadcast(sk, 1) < 0)
125
        goto err;
126
    }
127
    else
128
    {
129
      ifa->all_routers = AllSPFRouters;
130

    
131
      if (sk_setup_multicast(sk) < 0)
132
        goto err;
133

    
134
      if (sk_join_group(sk, ifa->all_routers) < 0)
135
        goto err;
136
    }
137
  }
138

    
139
  ifa->sk = sk;
140
  ifa->sk_dr = 0;
141
  return 1;
142

    
143
 err:
144
  rfree(sk);
145
  return 0;
146
}
147

    
148
static inline void
149
ospf_sk_join_dr(struct ospf_iface *ifa)
150
{
151
  if (ifa->sk_dr)
152
    return;
153

    
154
  sk_join_group(ifa->sk, AllDRouters);
155
  ifa->sk_dr = 1;
156
}
157

    
158
static inline void
159
ospf_sk_leave_dr(struct ospf_iface *ifa)
160
{
161
  if (!ifa->sk_dr)
162
    return;
163

    
164
  sk_leave_group(ifa->sk, AllDRouters);
165
  ifa->sk_dr = 0;
166
}
167

    
168
void
169
ospf_open_vlink_sk(struct proto_ospf *po)
170
{
171
  struct proto *p = &po->proto;
172

    
173
  sock *sk = sk_new(po->proto.pool);
174
  sk->type = SK_IP;
175
  sk->dport = OSPF_PROTO;
176

    
177
  /* FIXME: configurable tos/priority ? */
178
  sk->tos = IP_PREC_INTERNET_CONTROL;
179
  sk->priority = sk_priority_control;
180
  sk->err_hook = ospf_verr_hook;
181

    
182
  sk->rbsize = 0;
183
  sk->tbsize = OSPF_VLINK_MTU;
184
  sk->data = (void *) po;
185
  sk->flags = 0;
186

    
187
  if (sk_open(sk) < 0)
188
    goto err;
189

    
190
#ifdef OSPFv3
191
  /* 12 is an offset of the checksum in an OSPF packet */
192
  if (sk_set_ipv6_checksum(sk, 12) < 0)
193
    goto err;
194
#endif
195

    
196
  po->vlink_sk = sk;
197
  return;
198

    
199
 err:
200
  rfree(sk);
201
  log(L_ERR "%s: Cannot open virtual link socket", p->name);
202
}
203

    
204
static void
205
ospf_iface_down(struct ospf_iface *ifa)
206
{
207
  struct ospf_neighbor *n, *nx;
208
  struct proto_ospf *po = ifa->oa->po;
209
  struct proto *p = &po->proto;
210
  struct ospf_iface *iff;
211

    
212
  if (ifa->type != OSPF_IT_VLINK)
213
  {
214
#ifdef OSPFv2
215
    OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
216
               ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
217
#else
218
    OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
219
               ifa->ifname, ifa->instance_id, ifa->oa->areaid);
220
#endif
221

    
222
    /* First of all kill all the related vlinks */
223
    WALK_LIST(iff, po->iface_list)
224
    {
225
      if ((iff->type == OSPF_IT_VLINK) && (iff->vifa == ifa))
226
        ospf_iface_sm(iff, ISM_DOWN);
227
    }
228
  }
229

    
230
  WALK_LIST_DELSAFE(n, nx, ifa->neigh_list)
231
  {
232
    OSPF_TRACE(D_EVENTS, "Removing neighbor %I", n->ip);
233
    ospf_neigh_remove(n);
234
  }
235

    
236
  if (ifa->hello_timer)
237
    tm_stop(ifa->hello_timer);
238

    
239
  if (ifa->poll_timer)
240
    tm_stop(ifa->poll_timer);
241

    
242
  if (ifa->wait_timer)
243
    tm_stop(ifa->wait_timer);
244

    
245
  if (ifa->type == OSPF_IT_VLINK)
246
  {
247
    ifa->vifa = NULL;
248
    ifa->addr = NULL;
249
    ifa->cost = 0;
250
    ifa->vip = IPA_NONE;
251
  }
252

    
253
  ifa->rt_pos_beg = 0;
254
  ifa->rt_pos_end = 0;
255
#ifdef OSPFv3
256
  ifa->px_pos_beg = 0;
257
  ifa->px_pos_end = 0;
258
#endif
259
}
260

    
261

    
262
void
263
ospf_iface_remove(struct ospf_iface *ifa)
264
{
265
  struct proto *p = &ifa->oa->po->proto;
266
  if (ifa->type == OSPF_IT_VLINK)
267
    OSPF_TRACE(D_EVENTS, "Removing vlink to %R via area %R", ifa->vid, ifa->voa->areaid);
268

    
269
  ospf_iface_sm(ifa, ISM_DOWN);
270
  rem_node(NODE ifa);
271
  rfree(ifa->pool);
272
}
273

    
274
void
275
ospf_iface_shutdown(struct ospf_iface *ifa)
276
{
277
  if (ifa->state > OSPF_IS_DOWN)
278
    ospf_hello_send(ifa, OHS_SHUTDOWN, NULL);
279
}
280

    
281
/**
282
 * ospf_iface_chstate - handle changes of interface state
283
 * @ifa: OSPF interface
284
 * @state: new state
285
 *
286
 * Many actions must be taken according to interface state changes. New network
287
 * LSAs must be originated, flushed, new multicast sockets to listen for messages for
288
 * %ALLDROUTERS have to be opened, etc.
289
 */
290
void
291
ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
292
{
293
  struct proto_ospf *po = ifa->oa->po;
294
  struct proto *p = &po->proto;
295
  u8 oldstate = ifa->state;
296

    
297
  if (oldstate == state)
298
    return;
299

    
300
  ifa->state = state;
301

    
302
  if (ifa->type == OSPF_IT_VLINK)
303
    OSPF_TRACE(D_EVENTS, "Changing state of virtual link %R from %s to %s",
304
               ifa->vid, ospf_is[oldstate], ospf_is[state]);
305
  else
306
    OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
307
               ifa->ifname, ospf_is[oldstate], ospf_is[state]);
308

    
309
  if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk)
310
  {
311
    if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))
312
      ospf_sk_join_dr(ifa);
313
    else
314
      ospf_sk_leave_dr(ifa);
315
  }
316

    
317
  if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL))
318
  {
319
    ifa->net_lsa->lsa.age = LSA_MAXAGE;
320
    if (state >= OSPF_IS_WAITING)
321
      ospf_lsupd_flush_nlsa(po, ifa->net_lsa);
322

    
323
    if (can_flush_lsa(po))
324
      flush_lsa(ifa->net_lsa, po);
325
    ifa->net_lsa = NULL;
326
  }
327

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

    
331
  schedule_rt_lsa(ifa->oa);
332
  // FIXME flushling of link LSA
333
}
334

    
335
/**
336
 * ospf_iface_sm - OSPF interface state machine
337
 * @ifa: OSPF interface
338
 * @event: event comming to state machine
339
 *
340
 * This fully respects 9.3 of RFC 2328 except we have slightly
341
 * different handling of %DOWN and %LOOP state. We remove intefaces
342
 * that are %DOWN. %DOWN state is used when an interface is waiting
343
 * for a lock. %LOOP state is used when an interface does not have a
344
 * link.
345
 */
346
void
347
ospf_iface_sm(struct ospf_iface *ifa, int event)
348
{
349
  DBG("SM on iface %s. Event is '%s'\n", ifa->ifname, ospf_ism[event]);
350

    
351
  switch (event)
352
  {
353
  case ISM_UP:
354
    if (ifa->state <= OSPF_IS_LOOP)
355
    {
356
      /* Now, nothing should be adjacent */
357
      if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_PTMP) || (ifa->type == OSPF_IT_VLINK))
358
      {
359
        ospf_iface_chstate(ifa, OSPF_IS_PTP);
360
      }
361
      else
362
      {
363
        if (ifa->priority == 0)
364
          ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
365
        else
366
        {
367
          ospf_iface_chstate(ifa, OSPF_IS_WAITING);
368
          if (ifa->wait_timer)
369
            tm_start(ifa->wait_timer, ifa->waitint);
370
        }
371
      }
372

    
373
      if (ifa->hello_timer)
374
        tm_start(ifa->hello_timer, ifa->helloint);
375

    
376
      if (ifa->poll_timer)
377
        tm_start(ifa->poll_timer, ifa->pollint);
378

    
379
      ospf_hello_send(ifa, OHS_HELLO, NULL);
380
      schedule_link_lsa(ifa);
381
    }
382
    break;
383

    
384
  case ISM_BACKS:
385
  case ISM_WAITF:
386
    if (ifa->state == OSPF_IS_WAITING)
387
    {
388
      bdr_election(ifa);
389
    }
390
    break;
391

    
392
  case ISM_NEICH:
393
    if ((ifa->state == OSPF_IS_DROTHER) || (ifa->state == OSPF_IS_DR) ||
394
        (ifa->state == OSPF_IS_BACKUP))
395
    {
396
      bdr_election(ifa);
397
      schedule_rt_lsa(ifa->oa);
398
    }
399
    break;
400

    
401
  case ISM_LOOP:
402
    if ((ifa->state > OSPF_IS_LOOP) && ifa->check_link)
403
      ospf_iface_chstate(ifa, OSPF_IS_LOOP);
404
    break;
405

    
406
  case ISM_UNLOOP:
407
    /* Immediate go UP */
408
    if (ifa->state == OSPF_IS_LOOP)
409
      ospf_iface_sm(ifa, ISM_UP);
410
    break;
411

    
412
  case ISM_DOWN:
413
    ospf_iface_chstate(ifa, OSPF_IS_DOWN);
414
    break;
415

    
416
  default:
417
    bug("OSPF_I_SM - Unknown event?");
418
    break;
419
  }
420

    
421
}
422

    
423
static u8
424
ospf_iface_classify_int(struct iface *ifa, struct ifa *addr)
425
{
426
  if (ipa_nonzero(addr->opposite))
427
    return (ifa->flags & IF_MULTICAST) ? OSPF_IT_PTP :  OSPF_IT_PTMP;
428

    
429
  if ((ifa->flags & (IF_MULTIACCESS | IF_MULTICAST)) ==
430
      (IF_MULTIACCESS | IF_MULTICAST))
431
    return OSPF_IT_BCAST;
432

    
433
  if ((ifa->flags & (IF_MULTIACCESS | IF_MULTICAST)) == IF_MULTIACCESS)
434
    return OSPF_IT_NBMA;
435

    
436
  return OSPF_IT_PTP;
437
}
438

    
439
static inline u8
440
ospf_iface_classify(u8 type, struct ifa *addr)
441
{
442
  return (type != OSPF_IT_UNDEF) ? type : ospf_iface_classify_int(addr->iface, addr);
443
}
444

    
445

    
446
struct ospf_iface *
447
ospf_iface_find(struct proto_ospf *p, struct iface *what)
448
{
449
  struct ospf_iface *i;
450

    
451
  WALK_LIST(i, p->iface_list) if ((i->iface == what) && (i->type != OSPF_IT_VLINK))
452
    return i;
453
  return NULL;
454
}
455

    
456
static void
457
ospf_iface_add(struct object_lock *lock)
458
{
459
  struct ospf_iface *ifa = lock->data;
460
  struct proto_ospf *po = ifa->oa->po;
461
  struct proto *p = &po->proto;
462

    
463
  /* Open socket if interface is not stub */
464
  if (! ifa->stub && ! ospf_sk_open(ifa))
465
  {
466
    log(L_ERR "%s: Socket open failed on interface %s, declaring as stub", p->name, ifa->ifname);
467
    ifa->ioprob = OSPF_I_SK;
468
    ifa->stub = 1;
469
  }
470

    
471
  if (! ifa->stub)
472
  {
473
    ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
474

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

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

    
482
  /* Do iface UP, unless there is no link and we use link detection */
483
  ospf_iface_sm(ifa, (ifa->check_link && !(ifa->iface->flags & IF_LINK_UP)) ? ISM_LOOP : ISM_UP);
484
}
485

    
486
static inline void
487
add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
488
{
489
  struct nbma_node *n = mb_alloc(ifa->pool, sizeof(struct nbma_node));
490
  add_tail(&ifa->nbma_list, NODE n);
491
  n->ip = src->ip;
492
  n->eligible = src->eligible;
493
  n->found = found;
494
}
495

    
496
static int
497
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
498
{
499
  /* a host address */
500
  if (addr->flags & IA_HOST)
501
    return 1;
502

    
503
  /* a loopback iface */
504
  if (addr->iface->flags & IF_LOOPBACK)
505
    return 1;
506

    
507
  /*
508
   * For compatibility reasons on BSD systems, we force OSPF
509
   * interfaces with non-primary IP prefixes to be stub.
510
   */
511
#if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
512
  if (!ip->bsd_secondary && !(addr->flags & IA_PRIMARY))
513
    return 1;
514
#endif
515

    
516
  return ip->stub;
517
}
518

    
519
void
520
ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
521
{
522
  struct proto *p = &oa->po->proto;
523
  struct iface *iface = addr->iface;
524
  struct ospf_iface *ifa;
525
  struct pool *pool;
526

    
527
#ifdef OSPFv2
528
  OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
529
             iface->name, addr->prefix, addr->pxlen, oa->areaid);
530
#else
531
  OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
532
             iface->name, ip->instance_id, oa->areaid);
533
#endif
534

    
535
  pool = rp_new(p->pool, "OSPF Interface");
536
  ifa = mb_allocz(pool, sizeof(struct ospf_iface));
537
  ifa->iface = iface;
538
  ifa->addr = addr;
539
  ifa->oa = oa;
540
  ifa->cf = ip;
541
  ifa->pool = pool;
542

    
543
  ifa->iface_id = iface->index;
544
  ifa->ifname = iface->name;
545

    
546
  ifa->cost = ip->cost;
547
  ifa->rxmtint = ip->rxmtint;
548
  ifa->inftransdelay = ip->inftransdelay;
549
  ifa->priority = ip->priority;
550
  ifa->helloint = ip->helloint;
551
  ifa->pollint = ip->pollint;
552
  ifa->strictnbma = ip->strictnbma;
553
  ifa->waitint = ip->waitint;
554
  ifa->deadint = ip->deadint;
555
  ifa->stub = ospf_iface_stubby(ip, addr);
556
  ifa->ioprob = OSPF_I_OK;
557

    
558
  ifa->tx_length = ifa_tx_length(ifa);
559
  ifa->check_link = ip->check_link;
560
  ifa->ecmp_weight = ip->ecmp_weight;
561
  ifa->check_ttl = (ip->ttl_security == 1);
562
  ifa->bfd = ip->bfd;
563

    
564
#ifdef OSPFv2
565
  ifa->autype = ip->autype;
566
  ifa->passwords = ip->passwords;
567
  ifa->ptp_netmask = !(addr->flags & IA_PEER);
568
  if (ip->ptp_netmask < 2)
569
    ifa->ptp_netmask = ip->ptp_netmask;
570
#endif
571

    
572
#ifdef OSPFv3
573
  ifa->instance_id = ip->instance_id;
574
#endif
575

    
576

    
577
  ifa->type = ospf_iface_classify(ip->type, addr);
578

    
579
  /* Check validity of interface type */
580
  int old_type = ifa->type;
581
  u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST;
582

    
583
#ifdef OSPFv2
584
  if ((ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
585
    ifa->type = OSPF_IT_PTP;
586

    
587
  if ((ifa->type == OSPF_IT_NBMA) && (addr->flags & IA_PEER))
588
    ifa->type = OSPF_IT_PTMP;
589
#endif
590

    
591
  if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag))
592
    ifa->type = OSPF_IT_NBMA;
593

    
594
  if ((ifa->type == OSPF_IT_PTP) && !(iface->flags & if_multi_flag))
595
    ifa->type = OSPF_IT_PTMP;
596

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

    
601

    
602
  ifa->state = OSPF_IS_DOWN;
603
  init_list(&ifa->neigh_list);
604
  init_list(&ifa->nbma_list);
605

    
606
  struct nbma_node *nb;
607
  WALK_LIST(nb, ip->nbma_list)
608
  {
609
    /* In OSPFv3, addr is link-local while configured neighbors could
610
       have global IP (although RFC 5340 C.5 says link-local addresses
611
       should be used). Because OSPFv3 iface is not subnet-specific,
612
       there is no need for ipa_in_net() check */
613

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

    
622
    add_nbma_node(ifa, nb, 0);
623
  }
624

    
625
  add_tail(&oa->po->iface_list, NODE ifa);
626

    
627
  /*
628
   * In some cases we allow more ospf_ifaces on one physical iface.
629
   * In OSPFv2, if they use different IP address prefix.
630
   * In OSPFv3, if they use different instance_id.
631
   * Therefore, we store such info to lock->addr field.
632
   */
633

    
634
  struct object_lock *lock = olock_new(pool);
635
#ifdef OSPFv2
636
  lock->addr = ifa->addr->prefix;
637
#else /* OSPFv3 */
638
  lock->addr = _MI(0,0,0,ifa->instance_id);
639
#endif
640
  lock->type = OBJLOCK_IP;
641
  lock->port = OSPF_PROTO;
642
  lock->iface = iface;
643
  lock->data = ifa;
644
  lock->hook = ospf_iface_add;
645

    
646
  olock_acquire(lock);
647
}
648

    
649
void
650
ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip)
651
{
652
  struct proto *p = &po->proto;
653
  struct ospf_iface *ifa;
654
  struct pool *pool;
655

    
656
  if (!po->vlink_sk)
657
    return;
658

    
659
  OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
660

    
661
  /* Vlink ifname is stored just after the ospf_iface structure */
662

    
663
  pool = rp_new(p->pool, "OSPF Vlink");
664
  ifa = mb_allocz(pool, sizeof(struct ospf_iface) + 16);
665
  ifa->oa = po->backbone;
666
  ifa->cf = ip;
667
  ifa->pool = pool;
668

    
669
  /* Assign iface ID, for vlinks, this is ugly hack */
670
  u32 vlink_id = po->last_vlink_id++;
671
  ifa->iface_id = vlink_id + OSPF_VLINK_ID_OFFSET;
672
  ifa->ifname = (void *) (ifa + 1);
673
  bsprintf(ifa->ifname, "vlink%d", vlink_id);
674

    
675
  ifa->voa = ospf_find_area(po, ip->voa);
676
  ifa->vid = ip->vid;
677
  ifa->sk = po->vlink_sk;
678

    
679
  ifa->helloint = ip->helloint;
680
  ifa->rxmtint = ip->rxmtint;
681
  ifa->waitint = ip->waitint;
682
  ifa->deadint = ip->deadint;
683
  ifa->inftransdelay = ip->inftransdelay;
684
  ifa->tx_length = OSPF_VLINK_MTU;
685

    
686
#ifdef OSPFv2
687
  ifa->autype = ip->autype;
688
  ifa->passwords = ip->passwords;
689
#endif
690

    
691
#ifdef OSPFv3
692
  ifa->instance_id = ip->instance_id;
693
#endif
694

    
695
  ifa->type = OSPF_IT_VLINK;
696

    
697
  ifa->state = OSPF_IS_DOWN;
698
  init_list(&ifa->neigh_list);
699
  init_list(&ifa->nbma_list);
700

    
701
  add_tail(&po->iface_list, NODE ifa);
702

    
703
  ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
704
}
705

    
706
static void
707
ospf_iface_change_timer(timer *tm, unsigned val)
708
{
709
  if (!tm)
710
    return;
711

    
712
  tm->recurrent = val;
713

    
714
  if (tm->expires)
715
    tm_start(tm, val);
716
}
717

    
718
int
719
ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
720
{
721
  struct proto *p = &ifa->oa->po->proto;
722
  struct ospf_iface_patt *old = ifa->cf;
723
  char *ifname = ifa->ifname;
724

    
725
  /* Type could be changed in ospf_iface_new(),
726
     but if config values are same then also results are same */
727
  int old_type = ospf_iface_classify(old->type, ifa->addr);
728
  int new_type = ospf_iface_classify(new->type, ifa->addr);
729
  if (old_type != new_type)
730
    return 0;
731

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

    
736
  /* Change of these options would require to reset the iface socket */
737
  if ((new->real_bcast != old->real_bcast) ||
738
      (new->tx_tos != old->tx_tos) ||
739
      (new->tx_priority != old->tx_priority) ||
740
      (new->ttl_security != old->ttl_security))
741
    return 0;
742

    
743
  ifa->cf = new;
744
  ifa->marked = 0;
745

    
746

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

    
753
    ifa->helloint = new->helloint;
754
    ospf_iface_change_timer(ifa->hello_timer, ifa->helloint);
755
  }
756

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

    
763
    ifa->rxmtint = new->rxmtint;
764
  }
765

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

    
772
    ifa->pollint = new->pollint;
773
    ospf_iface_change_timer(ifa->poll_timer, ifa->pollint);
774
  }
775

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

    
782
    ifa->waitint = new->waitint;
783
    if (ifa->wait_timer && ifa->wait_timer->expires)
784
      tm_start(ifa->wait_timer, ifa->waitint);
785
  }
786

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

    
795
  /* INFTRANS */
796
  if (ifa->inftransdelay != new->inftransdelay)
797
  {
798
    OSPF_TRACE(D_EVENTS, "Changing transmit delay on interface %s from %d to %d",
799
                     ifname, ifa->inftransdelay, new->inftransdelay);
800
    ifa->inftransdelay = new->inftransdelay;
801
  }
802

    
803
#ifdef OSPFv2        
804
  /* AUTHENTICATION */
805
  if (ifa->autype != new->autype)
806
  {
807
    OSPF_TRACE(D_EVENTS, "Changing authentication type on interface %s", ifname);
808
    ifa->autype = new->autype;
809
  }
810

    
811
  /* Update passwords */
812
  ifa->passwords = new->passwords;
813
#endif
814

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

    
819

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

    
826
    ifa->cost = new->cost;
827
  }
828

    
829
  /* PRIORITY */
830
  if (ifa->priority != new->priority)
831
  {
832
    OSPF_TRACE(D_EVENTS, "Changing priority on interface %s from %d to %d",
833
               ifname, ifa->priority, new->priority);
834
    ifa->priority = new->priority;
835
  }
836

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

    
844
  struct nbma_node *nb, *nbx;
845

    
846
  /* NBMA LIST - remove or update old */
847
  WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list)
848
  {
849
    struct nbma_node *nb2 = find_nbma_node_in(&new->nbma_list, nb->ip);
850
    if (nb2)
851
    {
852
      if (nb->eligible != nb2->eligible)
853
      {
854
        OSPF_TRACE(D_EVENTS, "Changing eligibility of neighbor %I on interface %s",
855
                   nb->ip, ifname);
856
        nb->eligible = nb2->eligible;
857
      }
858
    }
859
    else
860
    {
861
      OSPF_TRACE(D_EVENTS, "Removing NBMA neighbor %I on interface %s",
862
                       nb->ip, ifname);
863
      rem_node(NODE nb);
864
      mb_free(nb);
865
    }
866
  }
867

    
868
  /* NBMA LIST - add new */
869
  WALK_LIST(nb, new->nbma_list)
870
  {
871
    /* See related note in ospf_iface_new() */
872
#ifdef OSPFv2
873
    if (!ipa_in_net(nb->ip, ifa->addr->prefix, ifa->addr->pxlen))
874
      continue;
875
#else
876
    if (!ipa_has_link_scope(nb->ip))
877
      log(L_WARN "In OSPFv3, configured neighbor address (%I) should be link-local", nb->ip);
878
#endif
879

    
880
    if (! find_nbma_node(ifa, nb->ip))
881
    {
882
      OSPF_TRACE(D_EVENTS, "Adding NBMA neighbor %I on interface %s",
883
                 nb->ip, ifname);
884
      add_nbma_node(ifa, nb, !!find_neigh_by_ip(ifa, nb->ip));
885
    }
886
  }
887

    
888
  int update_buffers = 0;
889

    
890
  /* TX LENGTH */
891
  if (old->tx_length != new->tx_length)
892
  {
893
    OSPF_TRACE(D_EVENTS, "Changing TX length on interface %s from %d to %d",
894
               ifname, old->tx_length, new->tx_length);
895

    
896
    /* ifa cannot be vlink */
897
    ifa->tx_length = ifa_tx_length(ifa);
898
    update_buffers = 1;
899
  }
900

    
901
  /* RX BUFFER */
902
  if (old->rx_buffer != new->rx_buffer)
903
  {
904
    OSPF_TRACE(D_EVENTS, "Changing buffer size on interface %s from %d to %d",
905
               ifname, old->rx_buffer, new->rx_buffer);
906

    
907
    /* ifa cannot be vlink */
908
    update_buffers = 1;
909
  }
910

    
911
  /* Buffer size depends on both tx_length and rx_buffer options */
912
  if (update_buffers && ifa->sk)
913
  {
914
    uint bsize = ifa_bufsize(ifa);
915
    sk_set_rbsize(ifa->sk, bsize);
916
    sk_set_tbsize(ifa->sk, bsize);
917
  }
918

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

    
926
    /* ifa cannot be vlink */
927
    if (!(ifa->iface->flags & IF_LINK_UP))
928
      ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP);
929
  }
930

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

    
939
  /* BFD */
940
  if (ifa->bfd != new->bfd)
941
  {
942
    OSPF_TRACE(D_EVENTS, "%s BFD on interface %s",
943
               new->bfd ? "Enabling" : "Disabling", ifname);
944
    ifa->bfd = new->bfd;
945

    
946
    struct ospf_neighbor *n;
947
    WALK_LIST(n, ifa->neigh_list)
948
      ospf_neigh_update_bfd(n, ifa->bfd);
949
  }
950

    
951

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

    
954
  return 1;
955
}
956

    
957

    
958
#ifdef OSPFv2
959

    
960
static inline struct ospf_iface_patt *
961
ospf_iface_patt_find(struct ospf_area_config *ac, struct ifa *a)
962
{
963
  return (struct ospf_iface_patt *) iface_patt_find(&ac->patt_list, a->iface, a);
964
}
965

    
966
void
967
ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
968
{
969
  struct proto_ospf *po = (struct proto_ospf *) p;
970

    
971
  if (a->flags & IA_SECONDARY)
972
    return;
973

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

    
977
  /* In OSPFv2, we create OSPF iface for each address. */
978
  if (flags & IF_CHANGE_UP)
979
  {
980
    int done = 0;
981
    struct ospf_area *oa;
982
    WALK_LIST(oa, po->area_list)
983
    {
984
      struct ospf_iface_patt *ip;
985
      if (ip = ospf_iface_patt_find(oa->ac, a))
986
      {
987
        if (!done)
988
          ospf_iface_new(oa, a, ip);
989
        done++;
990
      }
991
    }
992

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

    
997
  if (flags & IF_CHANGE_DOWN)
998
  {
999
    struct ospf_iface *ifa, *ifx;
1000
    WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
1001
    {
1002
      if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
1003
        ospf_iface_remove(ifa);
1004
      /* See a note in ospf_iface_notify() */
1005
    }
1006
  }
1007
}
1008

    
1009
static struct ospf_iface *
1010
ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a)
1011
{
1012
  struct ospf_iface *ifa;
1013
  WALK_LIST(ifa, oa->po->iface_list)
1014
    if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->type != OSPF_IT_VLINK))
1015
      return ifa;
1016

    
1017
  return NULL;
1018
}
1019

    
1020
void
1021
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
1022
{
1023
  struct proto *p = &oa->po->proto;
1024
  struct ospf_iface_patt *ip;
1025
  struct iface *iface;
1026
  struct ifa *a;
1027

    
1028
  WALK_LIST(iface, iface_list)
1029
  {
1030
    if (! (iface->flags & IF_UP))
1031
      continue;
1032

    
1033
    WALK_LIST(a, iface->addrs)
1034
    {
1035
      if (a->flags & IA_SECONDARY)
1036
        continue;
1037

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

    
1041
      if (ip = ospf_iface_patt_find(oa->ac, a))
1042
      {
1043
        /* Main inner loop */
1044
        struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a);
1045
        if (ifa)
1046
        {
1047
          if (ospf_iface_reconfigure(ifa, ip))
1048
            continue;
1049

    
1050
          /* Hard restart */
1051
          log(L_INFO "%s: Restarting interface %s (%I/%d) in area %R",
1052
              p->name, ifa->ifname, a->prefix, a->pxlen, oa->areaid);
1053
          ospf_iface_shutdown(ifa);
1054
          ospf_iface_remove(ifa);
1055
        }
1056
        
1057
        ospf_iface_new(oa, a, ip);
1058
      }
1059
    }
1060
  }
1061
}
1062

    
1063

    
1064
#else /* OSPFv3 */
1065

    
1066
struct ospf_iface_patt *
1067
ospf_iface_patt_find(struct ospf_area_config *ac, struct iface *iface, int iid)
1068
{
1069
  struct ospf_iface_patt *pt, *res = NULL;
1070

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

    
1076
  return res;
1077
}
1078

    
1079
void
1080
ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
1081
{
1082
  struct proto_ospf *po = (struct proto_ospf *) p;
1083

    
1084
  if (a->flags & IA_SECONDARY)
1085
    return;
1086

    
1087
  if (a->scope < SCOPE_LINK)
1088
    return;
1089

    
1090
  /* In OSPFv3, we create OSPF iface for link-local address,
1091
     other addresses are used for link-LSA. */
1092
  if (a->scope == SCOPE_LINK)
1093
  {
1094
    if (flags & IF_CHANGE_UP)
1095
    {
1096
      int done0 = 0;
1097
      struct ospf_area *oa;
1098

    
1099
      WALK_LIST(oa, po->area_list)
1100
      {
1101
        int iid = 0;
1102

    
1103
        struct ospf_iface_patt *ip;
1104
        while (ip = ospf_iface_patt_find(oa->ac, a->iface, iid))
1105
        {
1106
          ospf_iface_new(oa, a, ip);
1107
          if (ip->instance_id == 0)
1108
            done0++;
1109
          iid = ip->instance_id + 1;
1110
        }
1111
      }
1112

    
1113
      if (done0 > 1)
1114
        log(L_WARN "%s: Interface %s matches for multiple areas",
1115
            p->name,  a->iface->name);
1116
    }
1117

    
1118
    if (flags & IF_CHANGE_DOWN)
1119
    {
1120
      struct ospf_iface *ifa, *ifx;
1121
      WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
1122
      {
1123
        if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
1124
          ospf_iface_remove(ifa);
1125
        /* See a note in ospf_iface_notify() */
1126
      }
1127
    }
1128
  }
1129
  else
1130
  {
1131
    struct ospf_iface *ifa;
1132
    WALK_LIST(ifa, po->iface_list)
1133
    {
1134
      if (ifa->iface == a->iface)
1135
      {
1136
        schedule_rt_lsa(ifa->oa);
1137
        /* Event 5 from RFC5340 4.4.3. */
1138
        schedule_link_lsa(ifa);
1139
        return;
1140
      }
1141
    }
1142
  }
1143
}
1144

    
1145
static struct ospf_iface *
1146
ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a, int iid)
1147
{
1148
  struct ospf_iface *ifa;
1149
  WALK_LIST(ifa, oa->po->iface_list)
1150
    if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->instance_id == iid) && (ifa->type != OSPF_IT_VLINK))
1151
      return ifa;
1152

    
1153
  return NULL;
1154
}
1155

    
1156
void
1157
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
1158
{
1159
  struct proto *p = &oa->po->proto;
1160
  struct ospf_iface_patt *ip;
1161
  struct iface *iface;
1162
  struct ifa *a;
1163

    
1164
  WALK_LIST(iface, iface_list)
1165
  {
1166
    if (! (iface->flags & IF_UP))
1167
      continue;
1168

    
1169
    WALK_LIST(a, iface->addrs)
1170
    {
1171
      if (a->flags & IA_SECONDARY)
1172
        continue;
1173

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

    
1177
      int iid = 0;
1178
      while (ip = ospf_iface_patt_find(nac, iface, iid))
1179
      {
1180
        iid = ip->instance_id + 1;
1181

    
1182
        /* Main inner loop */
1183
        struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a, ip->instance_id);
1184
        if (ifa)
1185
        {
1186
          if (ospf_iface_reconfigure(ifa, ip))
1187
            continue;
1188

    
1189
          /* Hard restart */
1190
          log(L_INFO "%s: Restarting interface %s (IID %d) in area %R",
1191
              p->name, ifa->ifname, ifa->instance_id, oa->areaid);
1192
          ospf_iface_shutdown(ifa);
1193
          ospf_iface_remove(ifa);
1194
        }
1195

    
1196
        ospf_iface_new(oa, a, ip);
1197
      }
1198
    }
1199
  }
1200
}
1201

    
1202
#endif
1203

    
1204
static void
1205
ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
1206
{
1207
  struct proto *p = &po->proto;
1208

    
1209
  /* ifa is not vlink */
1210

    
1211
  OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->ifname);
1212

    
1213
  ifa->tx_length = ifa_tx_length(ifa);
1214

    
1215
  if (!ifa->sk)
1216
    return;
1217

    
1218
  /* We do not shrink dynamic buffers */
1219
  uint bsize = ifa_bufsize(ifa);
1220
  if (bsize > ifa->sk->rbsize)
1221
    sk_set_rbsize(ifa->sk, bsize);
1222
  if (bsize > ifa->sk->tbsize)
1223
    sk_set_tbsize(ifa->sk, bsize);
1224
}
1225

    
1226
static void
1227
ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa)
1228
{
1229
  /* ifa is not vlink */
1230

    
1231
  if (flags & IF_CHANGE_DOWN)
1232
  {
1233
    ospf_iface_remove(ifa);
1234
    return;
1235
  }
1236

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

    
1240
  if (flags & IF_CHANGE_MTU)
1241
    ospf_iface_change_mtu(po, ifa);
1242
}
1243

    
1244
void
1245
ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
1246
{
1247
  struct proto_ospf *po = (struct proto_ospf *) p;
1248

    
1249
  /*
1250
  if (iface->flags & IF_IGNORE)
1251
    return;
1252
  */
1253

    
1254
  /* Going up means that there are no such ifaces yet */
1255
  if (flags & IF_CHANGE_UP)
1256
    return;
1257

    
1258
  struct ospf_iface *ifa, *ifx;
1259
  WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
1260
    if (ifa->iface == iface)
1261
      ospf_iface_notify(po, flags, ifa);
1262

    
1263
  /* We use here that even shutting down iface also shuts down
1264
     the vlinks, but vlinks are not freed and stays in the
1265
     iface_list even when down */
1266
}
1267

    
1268
void
1269
ospf_iface_info(struct ospf_iface *ifa)
1270
{
1271
  char *more = "";
1272

    
1273
  if (ifa->strictnbma &&
1274
      ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)))
1275
    more = " (strict)";
1276

    
1277
  if (ifa->cf->real_bcast &&
1278
      ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP)))
1279
    more = " (real)";
1280

    
1281
  if (ifa->type == OSPF_IT_VLINK)
1282
  {
1283
    cli_msg(-1015, "Virtual link %s to %R:", ifa->ifname, ifa->vid);
1284
    cli_msg(-1015, "\tPeer IP: %I", ifa->vip);
1285
    cli_msg(-1015, "\tTransit area: %R (%u)", ifa->voa->areaid, ifa->voa->areaid);
1286
  }
1287
  else
1288
  {
1289
#ifdef OSPFv2
1290
    if (ifa->addr->flags & IA_PEER)
1291
      cli_msg(-1015, "Interface %s (peer %I)", ifa->ifname, ifa->addr->opposite);
1292
    else
1293
      cli_msg(-1015, "Interface %s (%I/%d)", ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen);
1294
#else /* OSPFv3 */
1295
    cli_msg(-1015, "Interface %s (IID %d)", ifa->ifname, ifa->instance_id);
1296
#endif
1297
    cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more);
1298
    cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid);
1299
  }
1300
  cli_msg(-1015, "\tState: %s%s", ospf_is[ifa->state], ifa->stub ? " (stub)" : "");
1301
  cli_msg(-1015, "\tPriority: %u", ifa->priority);
1302
  cli_msg(-1015, "\tCost: %u", ifa->cost);
1303
  if (ifa->oa->po->ecmp)
1304
    cli_msg(-1015, "\tECMP weight: %d", ((int) ifa->ecmp_weight) + 1);
1305
  cli_msg(-1015, "\tHello timer: %u", ifa->helloint);
1306

    
1307
  if (ifa->type == OSPF_IT_NBMA)
1308
  {
1309
    cli_msg(-1015, "\tPoll timer: %u", ifa->pollint);
1310
  }
1311
  cli_msg(-1015, "\tWait timer: %u", ifa->waitint);
1312
  cli_msg(-1015, "\tDead timer: %u", ifa->deadint);
1313
  cli_msg(-1015, "\tRetransmit timer: %u", ifa->rxmtint);
1314
  if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
1315
  {
1316
    cli_msg(-1015, "\tDesigned router (ID): %R", ifa->drid);
1317
    cli_msg(-1015, "\tDesigned router (IP): %I", ifa->drip);
1318
    cli_msg(-1015, "\tBackup designed router (ID): %R", ifa->bdrid);
1319
    cli_msg(-1015, "\tBackup designed router (IP): %I", ifa->bdrip);
1320
  }
1321
}
1322