Statistics
| Branch: | Revision:

iof-bird-daemon / nest / iface.c @ 62e64905

History | View | Annotate | Download (17.5 KB)

1
/*
2
 *        BIRD -- Management of Interfaces and Neighbor Cache
3
 *
4
 *        (c) 1998--2000 Martin Mares <mj@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
/**
10
 * DOC: Interfaces
11
 *
12
 * The interface module keeps track of all network interfaces in the
13
 * system and their addresses.
14
 *
15
 * Each interface is represented by an &iface structure which carries
16
 * interface capability flags (%IF_MULTIACCESS, %IF_BROADCAST etc.),
17
 * MTU, interface name and index and finally a linked list of network
18
 * prefixes assigned to the interface, each one represented by
19
 * struct &ifa.
20
 *
21
 * The interface module keeps a `soft-up' state for each &iface which
22
 * is a conjunction of link being up, the interface being of a `sane'
23
 * type and at least one IP address assigned to it.
24
 */
25

    
26
#undef LOCAL_DEBUG
27

    
28
#include "nest/bird.h"
29
#include "nest/iface.h"
30
#include "nest/protocol.h"
31
#include "nest/cli.h"
32
#include "lib/resource.h"
33
#include "lib/string.h"
34
#include "conf/conf.h"
35

    
36
static pool *if_pool;
37

    
38
list iface_list;
39

    
40
/**
41
 * ifa_dump - dump interface address
42
 * @a: interface address descriptor
43
 *
44
 * This function dumps contents of an &ifa to the debug output.
45
 */
46
void
47
ifa_dump(struct ifa *a)
48
{
49
  debug("\t%I, net %N bc %I -> %I%s%s%s\n", a->ip, &a->prefix, a->brd, a->opposite,
50
        (a->flags & IF_UP) ? "" : " DOWN",
51
        (a->flags & IA_PRIMARY) ? "" : " SEC",
52
        (a->flags & IA_PEER) ? "PEER" : "");
53
}
54

    
55
/**
56
 * if_dump - dump interface
57
 * @i: interface to dump
58
 *
59
 * This function dumps all information associated with a given
60
 * network interface to the debug output.
61
 */
62
void
63
if_dump(struct iface *i)
64
{
65
  struct ifa *a;
66

    
67
  debug("IF%d: %s", i->index, i->name);
68
  if (i->flags & IF_SHUTDOWN)
69
    debug(" SHUTDOWN");
70
  if (i->flags & IF_UP)
71
    debug(" UP");
72
  else
73
    debug(" DOWN");
74
  if (i->flags & IF_ADMIN_UP)
75
    debug(" LINK-UP");
76
  if (i->flags & IF_MULTIACCESS)
77
    debug(" MA");
78
  if (i->flags & IF_BROADCAST)
79
    debug(" BC");
80
  if (i->flags & IF_MULTICAST)
81
    debug(" MC");
82
  if (i->flags & IF_LOOPBACK)
83
    debug(" LOOP");
84
  if (i->flags & IF_IGNORE)
85
    debug(" IGN");
86
  if (i->flags & IF_TMP_DOWN)
87
    debug(" TDOWN");
88
  debug(" MTU=%d\n", i->mtu);
89
  WALK_LIST(a, i->addrs)
90
    {
91
      ifa_dump(a);
92
      ASSERT((a != i->addr) == !(a->flags & IA_PRIMARY));
93
    }
94
}
95

    
96
/**
97
 * if_dump_all - dump all interfaces
98
 *
99
 * This function dumps information about all known network
100
 * interfaces to the debug output.
101
 */
102
void
103
if_dump_all(void)
104
{
105
  struct iface *i;
106

    
107
  debug("Known network interfaces:\n");
108
  WALK_LIST(i, iface_list)
109
    if_dump(i);
110
  debug("Router ID: %08x\n", config->router_id);
111
}
112

    
113
static inline unsigned
114
if_what_changed(struct iface *i, struct iface *j)
115
{
116
  unsigned c;
117

    
118
  if (((i->flags ^ j->flags) & ~(IF_UP | IF_SHUTDOWN | IF_UPDATED | IF_ADMIN_UP | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED))
119
      || i->index != j->index)
120
    return IF_CHANGE_TOO_MUCH;
121
  c = 0;
122
  if ((i->flags ^ j->flags) & IF_UP)
123
    c |= (i->flags & IF_UP) ? IF_CHANGE_DOWN : IF_CHANGE_UP;
124
  if ((i->flags ^ j->flags) & IF_LINK_UP)
125
    c |= IF_CHANGE_LINK;
126
  if (i->mtu != j->mtu)
127
    c |= IF_CHANGE_MTU;
128
  return c;
129
}
130

    
131
static inline void
132
if_copy(struct iface *to, struct iface *from)
133
{
134
  to->flags = from->flags | (to->flags & IF_TMP_DOWN);
135
  to->mtu = from->mtu;
136
}
137

    
138
static inline void
139
ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
140
{
141
  if (p->ifa_notify && (p->proto_state != PS_DOWN))
142
    {
143
      if (p->debug & D_IFACES)
144
        log(L_TRACE "%s < %s address %N on interface %s %s",
145
            p->name, (a->flags & IA_PRIMARY) ? "primary" : "secondary",
146
            &a->prefix, a->iface->name, (c & IF_CHANGE_UP) ? "added" : "removed");
147
      p->ifa_notify(p, c, a);
148
    }
149
}
150

    
151
static void
152
ifa_notify_change_(unsigned c, struct ifa *a)
153
{
154
  struct proto *p;
155

    
156
  DBG("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip);
157

    
158
  WALK_LIST(p, proto_list)
159
    ifa_send_notify(p, c, a);
160
}
161

    
162
static inline void
163
ifa_notify_change(unsigned c, struct ifa *a)
164
{
165
  if (c & IF_CHANGE_DOWN)
166
    neigh_ifa_update(a);
167

    
168
  ifa_notify_change_(c, a);
169

    
170
  if (c & IF_CHANGE_UP)
171
    neigh_ifa_update(a);
172
}
173

    
174
static inline void
175
if_send_notify(struct proto *p, unsigned c, struct iface *i)
176
{
177
  if (p->if_notify && (p->proto_state != PS_DOWN))
178
    {
179
      if (p->debug & D_IFACES)
180
        log(L_TRACE "%s < interface %s %s", p->name, i->name,
181
            (c & IF_CHANGE_UP) ? "goes up" :
182
            (c & IF_CHANGE_DOWN) ? "goes down" :
183
            (c & IF_CHANGE_MTU) ? "changes MTU" :
184
            (c & IF_CHANGE_LINK) ? "changes link" :
185
            (c & IF_CHANGE_CREATE) ? "created" :
186
            "sends unknown event");
187
      p->if_notify(p, c, i);
188
    }
189
}
190

    
191
static void
192
if_notify_change(unsigned c, struct iface *i)
193
{
194
  struct proto *p;
195
  struct ifa *a;
196

    
197
  if (i->flags & IF_JUST_CREATED)
198
    {
199
      i->flags &= ~IF_JUST_CREATED;
200
      c |= IF_CHANGE_CREATE | IF_CHANGE_MTU;
201
    }
202

    
203
  DBG("Interface change notification (%x) for %s\n", c, i->name);
204
#ifdef LOCAL_DEBUG
205
  if_dump(i);
206
#endif
207

    
208
  if (c & IF_CHANGE_DOWN)
209
    neigh_if_down(i);
210

    
211
  if (c & IF_CHANGE_DOWN)
212
    WALK_LIST(a, i->addrs)
213
      {
214
        a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
215
        ifa_notify_change_(IF_CHANGE_DOWN, a);
216
      }
217

    
218
  WALK_LIST(p, proto_list)
219
    if_send_notify(p, c, i);
220

    
221
  if (c & IF_CHANGE_UP)
222
    WALK_LIST(a, i->addrs)
223
      {
224
        a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
225
        ifa_notify_change_(IF_CHANGE_UP, a);
226
      }
227

    
228
  if (c & IF_CHANGE_UP)
229
    neigh_if_up(i);
230

    
231
  if ((c & (IF_CHANGE_UP | IF_CHANGE_DOWN | IF_CHANGE_LINK)) == IF_CHANGE_LINK)
232
    neigh_if_link(i);
233
}
234

    
235
static unsigned
236
if_recalc_flags(struct iface *i, unsigned flags)
237
{
238
  if ((flags & (IF_SHUTDOWN | IF_TMP_DOWN)) ||
239
      !(flags & IF_ADMIN_UP) ||
240
      !i->addr)
241
    flags &= ~IF_UP;
242
  else
243
    flags |= IF_UP;
244
  return flags;
245
}
246

    
247
static void
248
if_change_flags(struct iface *i, unsigned flags)
249
{
250
  unsigned of = i->flags;
251

    
252
  i->flags = if_recalc_flags(i, flags);
253
  if ((i->flags ^ of) & IF_UP)
254
    if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i);
255
}
256

    
257
/**
258
 * if_delete - remove interface
259
 * @old: interface
260
 *
261
 * This function is called by the low-level platform dependent code
262
 * whenever it notices an interface disappears. It is just a shorthand
263
 * for if_update().
264
 */
265

    
266
void
267
if_delete(struct iface *old)
268
{
269
  struct iface f = {};
270
  strncpy(f.name, old->name, sizeof(f.name)-1);
271
  f.flags = IF_SHUTDOWN;
272
  if_update(&f);
273
}
274

    
275
/**
276
 * if_update - update interface status
277
 * @new: new interface status
278
 *
279
 * if_update() is called by the low-level platform dependent code
280
 * whenever it notices an interface change.
281
 *
282
 * There exist two types of interface updates -- synchronous and asynchronous
283
 * ones. In the synchronous case, the low-level code calls if_start_update(),
284
 * scans all interfaces reported by the OS, uses if_update() and ifa_update()
285
 * to pass them to the core and then it finishes the update sequence by
286
 * calling if_end_update(). When working asynchronously, the sysdep code
287
 * calls if_update() and ifa_update() whenever it notices a change.
288
 *
289
 * if_update() will automatically notify all other modules about the change.
290
 */
291
struct iface *
292
if_update(struct iface *new)
293
{
294
  struct iface *i;
295
  unsigned c;
296

    
297
  WALK_LIST(i, iface_list)
298
    if (!strcmp(new->name, i->name))
299
      {
300
        new->addr = i->addr;
301
        new->flags = if_recalc_flags(new, new->flags);
302
        c = if_what_changed(i, new);
303
        if (c & IF_CHANGE_TOO_MUCH)        /* Changed a lot, convert it to down/up */
304
          {
305
            DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
306
            if_change_flags(i, i->flags | IF_TMP_DOWN);
307
            rem_node(&i->n);
308
            new->addr = i->addr;
309
            memcpy(&new->addrs, &i->addrs, sizeof(i->addrs));
310
            memcpy(i, new, sizeof(*i));
311
            i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */
312
            goto newif;
313
          }
314

    
315
        if_copy(i, new);
316
        if (c)
317
          if_notify_change(c, i);
318

    
319
        i->flags |= IF_UPDATED;
320
        return i;
321
      }
322
  i = mb_alloc(if_pool, sizeof(struct iface));
323
  memcpy(i, new, sizeof(*i));
324
  init_list(&i->addrs);
325
newif:
326
  init_list(&i->neighbors);
327
  i->flags |= IF_UPDATED | IF_TMP_DOWN;                /* Tmp down as we don't have addresses yet */
328
  add_tail(&iface_list, &i->n);
329
  return i;
330
}
331

    
332
void
333
if_start_update(void)
334
{
335
  struct iface *i;
336
  struct ifa *a;
337

    
338
  WALK_LIST(i, iface_list)
339
    {
340
      i->flags &= ~IF_UPDATED;
341
      WALK_LIST(a, i->addrs)
342
        a->flags &= ~IF_UPDATED;
343
    }
344
}
345

    
346
void
347
if_end_partial_update(struct iface *i)
348
{
349
  if (i->flags & IF_TMP_DOWN)
350
    if_change_flags(i, i->flags & ~IF_TMP_DOWN);
351
}
352

    
353
void
354
if_end_update(void)
355
{
356
  struct iface *i;
357
  struct ifa *a, *b;
358

    
359
  WALK_LIST(i, iface_list)
360
    {
361
      if (!(i->flags & IF_UPDATED))
362
        if_change_flags(i, (i->flags & ~IF_ADMIN_UP) | IF_SHUTDOWN);
363
      else
364
        {
365
          WALK_LIST_DELSAFE(a, b, i->addrs)
366
            if (!(a->flags & IF_UPDATED))
367
              ifa_delete(a);
368
          if_end_partial_update(i);
369
        }
370
    }
371
}
372

    
373
void
374
if_flush_ifaces(struct proto *p)
375
{
376
  if (p->debug & D_EVENTS)
377
    log(L_TRACE "%s: Flushing interfaces", p->name);
378
  if_start_update();
379
  if_end_update();
380
}
381

    
382
/**
383
 * if_feed_baby - advertise interfaces to a new protocol
384
 * @p: protocol to feed
385
 *
386
 * When a new protocol starts, this function sends it a series
387
 * of notifications about all existing interfaces.
388
 */
389
void
390
if_feed_baby(struct proto *p)
391
{
392
  struct iface *i;
393
  struct ifa *a;
394

    
395
  if (!p->if_notify && !p->ifa_notify)        /* shortcut */
396
    return;
397
  DBG("Announcing interfaces to new protocol %s\n", p->name);
398
  WALK_LIST(i, iface_list)
399
    {
400
      if_send_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
401
      if (i->flags & IF_UP)
402
        WALK_LIST(a, i->addrs)
403
          ifa_send_notify(p, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
404
    }
405
}
406

    
407
/**
408
 * if_find_by_index - find interface by ifindex
409
 * @idx: ifindex
410
 *
411
 * This function finds an &iface structure corresponding to an interface
412
 * of the given index @idx. Returns a pointer to the structure or %NULL
413
 * if no such structure exists.
414
 */
415
struct iface *
416
if_find_by_index(unsigned idx)
417
{
418
  struct iface *i;
419

    
420
  WALK_LIST(i, iface_list)
421
    if (i->index == idx && !(i->flags & IF_SHUTDOWN))
422
      return i;
423
  return NULL;
424
}
425

    
426
/**
427
 * if_find_by_name - find interface by name
428
 * @name: interface name
429
 *
430
 * This function finds an &iface structure corresponding to an interface
431
 * of the given name @name. Returns a pointer to the structure or %NULL
432
 * if no such structure exists.
433
 */
434
struct iface *
435
if_find_by_name(char *name)
436
{
437
  struct iface *i;
438

    
439
  WALK_LIST(i, iface_list)
440
    if (!strcmp(i->name, name))
441
      return i;
442
  return NULL;
443
}
444

    
445
struct iface *
446
if_get_by_name(char *name)
447
{
448
  struct iface *i;
449

    
450
  if (i = if_find_by_name(name))
451
    return i;
452

    
453
  /* No active iface, create a dummy */
454
  i = mb_allocz(if_pool, sizeof(struct iface));
455
  strncpy(i->name, name, sizeof(i->name)-1);
456
  i->flags = IF_SHUTDOWN;
457
  init_list(&i->addrs);
458
  init_list(&i->neighbors);
459
  add_tail(&iface_list, &i->n);
460
  return i;
461
}
462

    
463
struct ifa *kif_choose_primary(struct iface *i);
464

    
465
static int
466
ifa_recalc_primary(struct iface *i)
467
{
468
  struct ifa *a = kif_choose_primary(i);
469

    
470
  if (a == i->addr)
471
    return 0;
472

    
473
  if (i->addr)
474
    i->addr->flags &= ~IA_PRIMARY;
475

    
476
  if (a)
477
    {
478
      a->flags |= IA_PRIMARY;
479
      rem_node(&a->n);
480
      add_head(&i->addrs, &a->n);
481
    }
482

    
483
  i->addr = a;
484
  return 1;
485
}
486

    
487
void
488
ifa_recalc_all_primary_addresses(void)
489
{
490
  struct iface *i;
491

    
492
  WALK_LIST(i, iface_list)
493
    {
494
      if (ifa_recalc_primary(i))
495
        if_change_flags(i, i->flags | IF_TMP_DOWN);
496
    }
497
}
498

    
499
static inline int
500
ifa_same(struct ifa *a, struct ifa *b)
501
{
502
  return ipa_equal(a->ip, b->ip) && net_equal(&a->prefix, &b->prefix);
503
}
504

    
505

    
506
/**
507
 * ifa_update - update interface address
508
 * @a: new interface address
509
 *
510
 * This function adds address information to a network
511
 * interface. It's called by the platform dependent code during
512
 * the interface update process described under if_update().
513
 */
514
struct ifa *
515
ifa_update(struct ifa *a)
516
{
517
  struct iface *i = a->iface;
518
  struct ifa *b;
519

    
520
  WALK_LIST(b, i->addrs)
521
    if (ifa_same(b, a))
522
      {
523
        if (ipa_equal(b->brd, a->brd) &&
524
            ipa_equal(b->opposite, a->opposite) &&
525
            b->scope == a->scope &&
526
            !((b->flags ^ a->flags) & IA_PEER))
527
          {
528
            b->flags |= IF_UPDATED;
529
            return b;
530
          }
531
        ifa_delete(b);
532
        break;
533
      }
534

    
535
  if ((a->prefix.type == NET_IP4) && (i->flags & IF_BROADCAST) && ipa_zero(a->brd))
536
    log(L_ERR "Missing broadcast address for interface %s", i->name);
537

    
538
  b = mb_alloc(if_pool, sizeof(struct ifa));
539
  memcpy(b, a, sizeof(struct ifa));
540
  add_tail(&i->addrs, &b->n);
541
  b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
542
  if (ifa_recalc_primary(i))
543
    if_change_flags(i, i->flags | IF_TMP_DOWN);
544
  if (b->flags & IF_UP)
545
    ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
546
  return b;
547
}
548

    
549
/**
550
 * ifa_delete - remove interface address
551
 * @a: interface address
552
 *
553
 * This function removes address information from a network
554
 * interface. It's called by the platform dependent code during
555
 * the interface update process described under if_update().
556
 */
557
void
558
ifa_delete(struct ifa *a)
559
{
560
  struct iface *i = a->iface;
561
  struct ifa *b;
562

    
563
  WALK_LIST(b, i->addrs)
564
    if (ifa_same(b, a))
565
      {
566
        rem_node(&b->n);
567
        if (b->flags & IF_UP)
568
          {
569
            b->flags &= ~IF_UP;
570
            ifa_notify_change(IF_CHANGE_DOWN, b);
571
          }
572
        if (b->flags & IA_PRIMARY)
573
          {
574
            if_change_flags(i, i->flags | IF_TMP_DOWN);
575
            ifa_recalc_primary(i);
576
          }
577
        mb_free(b);
578
        return;
579
      }
580
}
581

    
582
u32
583
if_choose_router_id(struct iface_patt *mask, u32 old_id)
584
{
585
  struct iface *i;
586
  struct ifa *a, *b;
587

    
588
  b = NULL;
589
  WALK_LIST(i, iface_list)
590
    {
591
      if (!(i->flags & IF_ADMIN_UP) ||
592
          (i->flags & IF_SHUTDOWN))
593
        continue;
594

    
595
      WALK_LIST(a, i->addrs)
596
        {
597
          if (a->prefix.type != NET_IP4)
598
            continue;
599

    
600
          if (a->flags & IA_SECONDARY)
601
            continue;
602

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

    
606
          /* Check pattern if specified */
607
          if (mask && !iface_patt_match(mask, i, a))
608
            continue;
609

    
610
          /* No pattern or pattern matched */
611
          if (!b || ipa_to_u32(a->ip) < ipa_to_u32(b->ip))
612
            b = a;
613
        }
614
    }
615

    
616
  if (!b)
617
    return 0;
618

    
619
  u32 id = ipa_to_u32(b->ip);
620
  if (id != old_id)
621
    log(L_INFO "Chosen router ID %R according to interface %s", id, b->iface->name);
622

    
623
  return id;
624
}
625

    
626
/**
627
 * if_init - initialize interface module
628
 *
629
 * This function is called during BIRD startup to initialize
630
 * all data structures of the interface module.
631
 */
632
void
633
if_init(void)
634
{
635
  if_pool = rp_new(&root_pool, "Interfaces");
636
  init_list(&iface_list);
637
  neigh_init(if_pool);
638
}
639

    
640
/*
641
 *        Interface Pattern Lists
642
 */
643

    
644
int
645
iface_patt_match(struct iface_patt *ifp, struct iface *i, struct ifa *a)
646
{
647
  struct iface_patt_node *p;
648

    
649
  WALK_LIST(p, ifp->ipn_list)
650
    {
651
      char *t = p->pattern;
652
      int pos = p->positive;
653

    
654
      if (t)
655
        {
656
          if (*t == '-')
657
            {
658
              t++;
659
              pos = !pos;
660
            }
661

    
662
          if (!patmatch(t, i->name))
663
            continue;
664
        }
665

    
666
      if (p->prefix.pxlen == 0)
667
        return pos;
668

    
669
      if (!a)
670
        continue;
671

    
672
      if (ipa_in_netX(a->ip, &p->prefix))
673
        return pos;
674

    
675
      if ((a->flags & IA_PEER) &&
676
          ipa_in_netX(a->opposite, &p->prefix))
677
        return pos;
678

    
679
      continue;
680
    }
681

    
682
  return 0;
683
}
684

    
685
struct iface_patt *
686
iface_patt_find(list *l, struct iface *i, struct ifa *a)
687
{
688
  struct iface_patt *p;
689

    
690
  WALK_LIST(p, *l)
691
    if (iface_patt_match(p, i, a))
692
      return p;
693

    
694
  return NULL;
695
}
696

    
697
static int
698
iface_plists_equal(struct iface_patt *pa, struct iface_patt *pb)
699
{
700
  struct iface_patt_node *x, *y;
701

    
702
  x = HEAD(pa->ipn_list);
703
  y = HEAD(pb->ipn_list);
704
  while (x->n.next && y->n.next)
705
    {
706
      if ((x->positive != y->positive) ||
707
          (!x->pattern && y->pattern) ||        /* This nasty lines where written by me... :-( Feela */
708
          (!y->pattern && x->pattern) ||
709
          ((x->pattern != y->pattern) && strcmp(x->pattern, y->pattern)) ||
710
          !net_equal(&x->prefix, &y->prefix))
711
        return 0;
712
      x = (void *) x->n.next;
713
      y = (void *) y->n.next;
714
    }
715
  return (!x->n.next && !y->n.next);
716
}
717

    
718
int
719
iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct iface_patt *))
720
{
721
  struct iface_patt *x, *y;
722

    
723
  x = HEAD(*a);
724
  y = HEAD(*b);
725
  while (x->n.next && y->n.next)
726
    {
727
      if (!iface_plists_equal(x, y) ||
728
          (comp && !comp(x, y)))
729
        return 0;
730
      x = (void *) x->n.next;
731
      y = (void *) y->n.next;
732
    }
733
  return (!x->n.next && !y->n.next);
734
}
735

    
736
/*
737
 *  CLI commands.
738
 */
739

    
740
static void
741
if_show_addr(struct ifa *a)
742
{
743
  byte opp[IPA_MAX_TEXT_LENGTH + 16];
744

    
745
  if (ipa_nonzero(a->opposite))
746
    bsprintf(opp, ", opposite %I", a->opposite);
747
  else
748
    opp[0] = 0;
749
  cli_msg(-1003, "\t%I/%d (%s%s, scope %s)",
750
          a->ip, a->prefix.pxlen,
751
          (a->flags & IA_PRIMARY) ? "Primary" : (a->flags & IA_SECONDARY) ? "Secondary" : "Unselected",
752
          opp, ip_scope_text(a->scope));
753
}
754

    
755
void
756
if_show(void)
757
{
758
  struct iface *i;
759
  struct ifa *a;
760
  char *type;
761

    
762
  WALK_LIST(i, iface_list)
763
    {
764
      if (i->flags & IF_SHUTDOWN)
765
        continue;
766

    
767
      cli_msg(-1001, "%s %s (index=%d)", i->name, (i->flags & IF_UP) ? "up" : "DOWN", i->index);
768
      if (!(i->flags & IF_MULTIACCESS))
769
        type = "PtP";
770
      else
771
        type = "MultiAccess";
772
      cli_msg(-1004, "\t%s%s%s Admin%s Link%s%s%s MTU=%d",
773
              type,
774
              (i->flags & IF_BROADCAST) ? " Broadcast" : "",
775
              (i->flags & IF_MULTICAST) ? " Multicast" : "",
776
              (i->flags & IF_ADMIN_UP) ? "Up" : "Down",
777
              (i->flags & IF_LINK_UP) ? "Up" : "Down",
778
              (i->flags & IF_LOOPBACK) ? " Loopback" : "",
779
              (i->flags & IF_IGNORE) ? " Ignored" : "",
780
              i->mtu);
781
      if (i->addr)
782
        if_show_addr(i->addr);
783
      WALK_LIST(a, i->addrs)
784
        if (a != i->addr)
785
          if_show_addr(a);
786
    }
787
  cli_msg(0, "");
788
}
789

    
790
void
791
if_show_summary(void)
792
{
793
  struct iface *i;
794
  byte addr[IPA_MAX_TEXT_LENGTH + 16];
795

    
796
  cli_msg(-2005, "interface state address");
797
  WALK_LIST(i, iface_list)
798
    {
799
      if (i->addr)
800
        bsprintf(addr, "%I/%d", i->addr->ip, i->addr->prefix.pxlen);
801
      else
802
        addr[0] = 0;
803
      cli_msg(-1005, "%-9s %-5s %s", i->name, (i->flags & IF_UP) ? "up" : "DOWN", addr);
804
    }
805
  cli_msg(0, "");
806
}