Statistics
| Branch: | Revision:

iof-bird-daemon / nest / iface.c @ cf7f0645

History | View | Annotate | Download (16.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
static void auto_router_id(void);
39

    
40
list iface_list;
41

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

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

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

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

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

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

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

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

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

    
154
static void
155
ifa_notify_change_dep(unsigned c, struct ifa *a)
156
{
157
  struct proto *p;
158

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

    
161
  WALK_LIST(p, active_proto_list)
162
    ifa_send_notify(p, c, a);
163
}
164

    
165
static inline void
166
ifa_notify_change(unsigned c, struct ifa *a)
167
{
168
  neigh_ifa_update(a);
169
  ifa_notify_change_dep(c, a);
170
}
171

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

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

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

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

    
206
  if (c & IF_CHANGE_UP)
207
    neigh_if_up(i);
208

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

    
216
  WALK_LIST(p, active_proto_list)
217
    if_send_notify(p, c, i);
218

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

    
226
  if ((c & (IF_CHANGE_UP | IF_CHANGE_DOWN | IF_CHANGE_LINK)) == IF_CHANGE_LINK)
227
    neigh_if_link(i);
228

    
229
  if (c & IF_CHANGE_DOWN)
230
    neigh_if_down(i);
231
}
232

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

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

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

    
255
/**
256
 * if_update - update interface status
257
 * @new: new interface status
258
 *
259
 * if_update() is called by the low-level platform dependent code
260
 * whenever it notices an interface change.
261
 *
262
 * There exist two types of interface updates -- synchronous and asynchronous
263
 * ones. In the synchronous case, the low-level code calls if_start_update(),
264
 * scans all interfaces reported by the OS, uses if_update() and ifa_update()
265
 * to pass them to the core and then it finishes the update sequence by
266
 * calling if_end_update(). When working asynchronously, the sysdep code
267
 * calls if_update() and ifa_update() whenever it notices a change.
268
 *
269
 * if_update() will automatically notify all other modules about the change.
270
 */
271
struct iface *
272
if_update(struct iface *new)
273
{
274
  struct iface *i;
275
  unsigned c;
276

    
277
  WALK_LIST(i, iface_list)
278
    if (!strcmp(new->name, i->name))
279
      {
280
        new->addr = i->addr;
281
        new->flags = if_recalc_flags(new, new->flags);
282
        c = if_what_changed(i, new);
283
        if (c & IF_CHANGE_TOO_MUCH)        /* Changed a lot, convert it to down/up */
284
          {
285
            DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
286
            if_change_flags(i, i->flags | IF_TMP_DOWN);
287
            rem_node(&i->n);
288
            new->addr = i->addr;
289
            memcpy(&new->addrs, &i->addrs, sizeof(i->addrs));
290
            memcpy(i, new, sizeof(*i));
291
            goto newif;
292
          }
293
        else if (c)
294
          {
295
            if_copy(i, new);
296
            if_notify_change(c, i);
297
          }
298
        i->flags |= IF_UPDATED;
299
        return i;
300
      }
301
  i = mb_alloc(if_pool, sizeof(struct iface));
302
  memcpy(i, new, sizeof(*i));
303
  init_list(&i->addrs);
304
newif:
305
  init_list(&i->neighbors);
306
  i->flags |= IF_UPDATED | IF_TMP_DOWN;                /* Tmp down as we don't have addresses yet */
307
  add_tail(&iface_list, &i->n);
308
  return i;
309
}
310

    
311
void
312
if_start_update(void)
313
{
314
  struct iface *i;
315
  struct ifa *a;
316

    
317
  WALK_LIST(i, iface_list)
318
    {
319
      i->flags &= ~IF_UPDATED;
320
      WALK_LIST(a, i->addrs)
321
        a->flags &= ~IF_UPDATED;
322
    }
323
}
324

    
325
void
326
if_end_partial_update(struct iface *i)
327
{
328
  if (i->flags & IF_TMP_DOWN)
329
    if_change_flags(i, i->flags & ~IF_TMP_DOWN);
330
}
331

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

    
338
  if (!config->router_id)
339
    auto_router_id();
340

    
341
  WALK_LIST(i, iface_list)
342
    {
343
      if (!(i->flags & IF_UPDATED))
344
        if_change_flags(i, (i->flags & ~IF_ADMIN_UP) | IF_SHUTDOWN);
345
      else
346
        {
347
          WALK_LIST_DELSAFE(a, b, i->addrs)
348
            if (!(a->flags & IF_UPDATED))
349
              ifa_delete(a);
350
          if_end_partial_update(i);
351
        }
352
    }
353
}
354

    
355
void
356
if_flush_ifaces(struct proto *p)
357
{
358
  if (p->debug & D_EVENTS)
359
    log(L_TRACE "%s: Flushing interfaces", p->name);
360
  if_start_update();
361
  if_end_update();
362
}
363

    
364
/**
365
 * if_feed_baby - advertise interfaces to a new protocol
366
 * @p: protocol to feed
367
 *
368
 * When a new protocol starts, this function sends it a series
369
 * of notifications about all existing interfaces.
370
 */
371
void
372
if_feed_baby(struct proto *p)
373
{
374
  struct iface *i;
375
  struct ifa *a;
376

    
377
  if (!p->if_notify && !p->ifa_notify)        /* shortcut */
378
    return;
379
  DBG("Announcing interfaces to new protocol %s\n", p->name);
380
  WALK_LIST(i, iface_list)
381
    {
382
      if_send_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
383
      if (i->flags & IF_UP)
384
        WALK_LIST(a, i->addrs)
385
          ifa_send_notify(p, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
386
    }
387
}
388

    
389
/**
390
 * if_find_by_index - find interface by ifindex
391
 * @idx: ifindex
392
 *
393
 * This function finds an &iface structure corresponding to an interface
394
 * of the given index @idx. Returns a pointer to the structure or %NULL
395
 * if no such structure exists.
396
 */
397
struct iface *
398
if_find_by_index(unsigned idx)
399
{
400
  struct iface *i;
401

    
402
  WALK_LIST(i, iface_list)
403
    if (i->index == idx)
404
      return i;
405
  return NULL;
406
}
407

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

    
421
  WALK_LIST(i, iface_list)
422
    if (!strcmp(i->name, name))
423
      return i;
424
  return NULL;
425
}
426

    
427
struct ifa *kif_choose_primary(struct iface *i);
428

    
429
static int
430
ifa_recalc_primary(struct iface *i)
431
{
432
  struct ifa *a = kif_choose_primary(i);
433

    
434
  if (a == i->addr)
435
    return 0;
436

    
437
  if (i->addr)
438
    i->addr->flags &= ~IA_PRIMARY;
439

    
440
  if (a)
441
    {
442
      a->flags |= IA_PRIMARY;
443
      rem_node(&a->n);
444
      add_head(&i->addrs, &a->n);
445
    }
446

    
447
  i->addr = a;
448
  return 1;
449
}
450

    
451
void
452
ifa_recalc_all_primary_addresses(void)
453
{
454
  struct iface *i;
455

    
456
  WALK_LIST(i, iface_list)
457
    {
458
      if (ifa_recalc_primary(i))
459
        if_change_flags(i, i->flags | IF_TMP_DOWN);
460
    }
461
}
462

    
463
static inline int
464
ifa_same(struct ifa *a, struct ifa *b)
465
{
466
  return ipa_equal(a->ip, b->ip) && ipa_equal(a->prefix, b->prefix) &&
467
    a->pxlen == b->pxlen;
468
}
469

    
470

    
471
/**
472
 * ifa_update - update interface address
473
 * @a: new interface address
474
 *
475
 * This function adds address information to a network
476
 * interface. It's called by the platform dependent code during
477
 * the interface update process described under if_update().
478
 */
479
struct ifa *
480
ifa_update(struct ifa *a)
481
{
482
  struct iface *i = a->iface;
483
  struct ifa *b;
484

    
485
  WALK_LIST(b, i->addrs)
486
    if (ifa_same(b, a))
487
      {
488
        if (ipa_equal(b->brd, a->brd) &&
489
            ipa_equal(b->opposite, a->opposite) &&
490
            b->scope == a->scope &&
491
            !((b->flags ^ a->flags) & IA_PEER))
492
          {
493
            b->flags |= IF_UPDATED;
494
            return b;
495
          }
496
        ifa_delete(b);
497
        break;
498
      }
499

    
500
#ifndef IPV6
501
  if ((i->flags & IF_BROADCAST) && !ipa_nonzero(a->brd))
502
    log(L_ERR "Missing broadcast address for interface %s", i->name);
503
#endif
504

    
505
  b = mb_alloc(if_pool, sizeof(struct ifa));
506
  memcpy(b, a, sizeof(struct ifa));
507
  add_tail(&i->addrs, &b->n);
508
  b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
509
  if (ifa_recalc_primary(i))
510
    if_change_flags(i, i->flags | IF_TMP_DOWN);
511
  if (b->flags & IF_UP)
512
    ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
513
  return b;
514
}
515

    
516
/**
517
 * ifa_delete - remove interface address
518
 * @a: interface address
519
 *
520
 * This function removes address information from a network
521
 * interface. It's called by the platform dependent code during
522
 * the interface update process described under if_update().
523
 */
524
void
525
ifa_delete(struct ifa *a)
526
{
527
  struct iface *i = a->iface;
528
  struct ifa *b;
529

    
530
  WALK_LIST(b, i->addrs)
531
    if (ifa_same(b, a))
532
      {
533
        rem_node(&b->n);
534
        if (b->flags & IF_UP)
535
          {
536
            b->flags &= ~IF_UP;
537
            ifa_notify_change(IF_CHANGE_DOWN, b);
538
          }
539
        if (b->flags & IA_PRIMARY)
540
          {
541
            if_change_flags(i, i->flags | IF_TMP_DOWN);
542
            ifa_recalc_primary(i);
543
          }
544
        mb_free(b);
545
        return;
546
      }
547
}
548

    
549
static void
550
auto_router_id(void)
551
{
552
#ifndef IPV6
553
  struct iface *i, *j;
554

    
555
  j = NULL;
556
  WALK_LIST(i, iface_list)
557
    if ((i->flags & IF_ADMIN_UP) &&
558
        !(i->flags & (IF_IGNORE | IF_SHUTDOWN)) &&
559
        i->addr &&
560
        !(i->addr->flags & IA_PEER) &&
561
        (!j || ipa_to_u32(i->addr->ip) < ipa_to_u32(j->addr->ip)))
562
      j = i;
563
  if (!j)
564
    die("Cannot determine router ID (no suitable network interface found), please configure it manually");
565
  log(L_INFO "Guessed router ID %I according to interface %s", j->addr->ip, j->name);
566
  config->router_id = ipa_to_u32(j->addr->ip);
567
#endif
568
}
569

    
570
/**
571
 * if_init - initialize interface module
572
 *
573
 * This function is called during BIRD startup to initialize
574
 * all data structures of the interface module.
575
 */
576
void
577
if_init(void)
578
{
579
  if_pool = rp_new(&root_pool, "Interfaces");
580
  init_list(&iface_list);
581
  neigh_init(if_pool);
582
}
583

    
584
/*
585
 *        Interface Pattern Lists
586
 */
587

    
588
int
589
iface_patt_match(struct iface_patt *ifp, struct iface *i, struct ifa *a)
590
{
591
  struct iface_patt_node *p;
592

    
593
  WALK_LIST(p, ifp->ipn_list)
594
    {
595
      char *t = p->pattern;
596
      int pos = p->positive;
597

    
598
      if (t)
599
        {
600
          if (*t == '-')
601
            {
602
              t++;
603
              pos = !pos;
604
            }
605

    
606
          if (!patmatch(t, i->name))
607
            continue;
608
        }
609

    
610
      if (p->pxlen == 0)
611
        return pos;
612

    
613
      if (!a)
614
        continue;
615

    
616
      if (ipa_in_net(a->ip, p->prefix, p->pxlen))
617
        return pos;
618

    
619
      if ((a->flags & IA_PEER) &&
620
          ipa_in_net(a->opposite, p->prefix, p->pxlen))
621
        return pos;
622
          
623
      continue;
624
    }
625

    
626
  return 0;
627
}
628

    
629
struct iface_patt *
630
iface_patt_find(list *l, struct iface *i, struct ifa *a)
631
{
632
  struct iface_patt *p;
633

    
634
  WALK_LIST(p, *l)
635
    if (iface_patt_match(p, i, a))
636
      return p;
637

    
638
  return NULL;
639
}
640

    
641
static int
642
iface_plists_equal(struct iface_patt *pa, struct iface_patt *pb)
643
{
644
  struct iface_patt_node *x, *y;
645

    
646
  x = HEAD(pa->ipn_list);
647
  y = HEAD(pb->ipn_list);
648
  while (x->n.next && y->n.next)
649
    {
650
      if ((x->positive != y->positive) ||
651
          (!x->pattern && y->pattern) ||        /* This nasty lines where written by me... :-( Feela */
652
          (!y->pattern && x->pattern) ||
653
          ((x->pattern != y->pattern) && strcmp(x->pattern, y->pattern)) ||
654
          !ipa_equal(x->prefix, y->prefix) ||
655
          (x->pxlen != y->pxlen))
656
        return 0;
657
      x = (void *) x->n.next;
658
      y = (void *) y->n.next;
659
    }
660
  return (!x->n.next && !y->n.next);
661
}
662

    
663
int
664
iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct iface_patt *))
665
{
666
  struct iface_patt *x, *y;
667

    
668
  x = HEAD(*a);
669
  y = HEAD(*b);
670
  while (x->n.next && y->n.next)
671
    {
672
      if (!iface_plists_equal(x, y) ||
673
          (comp && !comp(x, y)))
674
        return 0;
675
      x = (void *) x->n.next;
676
      y = (void *) y->n.next;
677
    }
678
  return (!x->n.next && !y->n.next);
679
}
680

    
681
/*
682
 *  CLI commands.
683
 */
684

    
685
static void
686
if_show_addr(struct ifa *a)
687
{
688
  byte opp[STD_ADDRESS_P_LENGTH + 16];
689

    
690
  if (ipa_nonzero(a->opposite))
691
    bsprintf(opp, ", opposite %I", a->opposite);
692
  else
693
    opp[0] = 0;
694
  cli_msg(-1003, "\t%I/%d (%s%s, scope %s)",
695
          a->ip, a->pxlen,
696
          (a->flags & IA_PRIMARY) ? "Primary" : (a->flags & IA_SECONDARY) ? "Secondary" : "Unselected",
697
          opp, ip_scope_text(a->scope));
698
}
699

    
700
void
701
if_show(void)
702
{
703
  struct iface *i;
704
  struct ifa *a;
705
  char *type;
706

    
707
  WALK_LIST(i, iface_list)
708
    {
709
      if (i->flags & IF_SHUTDOWN)
710
        continue;
711

    
712
      cli_msg(-1001, "%s %s (index=%d)", i->name, (i->flags & IF_UP) ? "up" : "DOWN", i->index);
713
      if (!(i->flags & IF_MULTIACCESS))
714
        type = "PtP";
715
      else
716
        type = "MultiAccess";
717
      cli_msg(-1004, "\t%s%s%s Admin%s Link%s%s%s MTU=%d",
718
              type,
719
              (i->flags & IF_BROADCAST) ? " Broadcast" : "",
720
              (i->flags & IF_MULTICAST) ? " Multicast" : "",
721
              (i->flags & IF_ADMIN_UP) ? "Up" : "Down",
722
              (i->flags & IF_LINK_UP) ? "Up" : "Down",
723
              (i->flags & IF_LOOPBACK) ? " Loopback" : "",
724
              (i->flags & IF_IGNORE) ? " Ignored" : "",
725
              i->mtu);
726
      if (i->addr)
727
        if_show_addr(i->addr);
728
      WALK_LIST(a, i->addrs)
729
        if (a != i->addr)
730
          if_show_addr(a);
731
    }
732
  cli_msg(0, "");
733
}
734

    
735
void
736
if_show_summary(void)
737
{
738
  struct iface *i;
739
  byte addr[STD_ADDRESS_P_LENGTH + 16];
740

    
741
  cli_msg(-2005, "interface state address");
742
  WALK_LIST(i, iface_list)
743
    {
744
      if (i->addr)
745
        bsprintf(addr, "%I/%d", i->addr->ip, i->addr->pxlen);
746
      else
747
        addr[0] = 0;
748
      cli_msg(-1005, "%-9s %-5s %s", i->name, (i->flags & IF_UP) ? "up" : "DOWN", addr);
749
    }
750
  cli_msg(0, "");
751
}