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

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

26
#undef LOCAL_DEBUG
27

28 29
#include "nest/bird.h"
#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 37

static pool *if_pool;

38 39
list iface_list;

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

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

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

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

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

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

118
  if (((i->flags ^ j->flags) & ~(IF_UP | IF_SHUTDOWN | IF_UPDATED | IF_ADMIN_UP | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED))
Ondřej Zajíček's avatar
Ondřej Zajíček committed
119
      || (i->index != j->index) || (i->master != j->master))
120 121 122 123
    return IF_CHANGE_TOO_MUCH;
  c = 0;
  if ((i->flags ^ j->flags) & IF_UP)
    c |= (i->flags & IF_UP) ? IF_CHANGE_DOWN : IF_CHANGE_UP;
124 125
  if ((i->flags ^ j->flags) & IF_LINK_UP)
    c |= IF_CHANGE_LINK;
126 127 128
  if (i->mtu != j->mtu)
    c |= IF_CHANGE_MTU;
  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;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
136 137
  to->master_index = from->master_index;
  to->master = from->master;
138 139
}

140 141 142
static inline void
ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
143
  if (p->ifa_notify && (!p->vrf || p->vrf == a->iface->master))
144 145
    {
      if (p->debug & D_IFACES)
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
146 147
	log(L_TRACE "%s <%s address %I/%d on interface %s %s",
	    p->name, (a->flags & IA_PRIMARY) ? " primary" : "",
148 149 150 151 152 153
	    a->prefix, a->pxlen, a->iface->name,
	    (c & IF_CHANGE_UP) ? "added" : "removed");
      p->ifa_notify(p, c, a);
    }
}

154
static void
155
ifa_notify_change_(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 163 164
    ifa_send_notify(p, c, a);
}

165 166 167
static inline void
ifa_notify_change(unsigned c, struct ifa *a)
{
168 169 170 171 172 173 174
  if (c & IF_CHANGE_DOWN)
    neigh_ifa_update(a);

  ifa_notify_change_(c, a);

  if (c & IF_CHANGE_UP)
    neigh_ifa_update(a);
175 176
}

177 178 179
static inline void
if_send_notify(struct proto *p, unsigned c, struct iface *i)
{
Ondřej Zajíček's avatar
Ondřej Zajíček committed
180
  if (p->if_notify && (!p->vrf || p->vrf == i->master))
181 182 183 184 185 186
    {
      if (p->debug & D_IFACES)
	log(L_TRACE "%s < interface %s %s", p->name, i->name,
	    (c & IF_CHANGE_UP) ? "goes up" :
	    (c & IF_CHANGE_DOWN) ? "goes down" :
	    (c & IF_CHANGE_MTU) ? "changes MTU" :
187
	    (c & IF_CHANGE_LINK) ? "changes link" :
188 189 190 191
	    (c & IF_CHANGE_CREATE) ? "created" :
	    "sends unknown event");
      p->if_notify(p, c, i);
    }
192 193 194
}

static void
195
if_notify_change(unsigned c, struct iface *i)
196
{
197
  struct proto *p;
198
  struct ifa *a;
199

200 201 202 203 204 205
  if (i->flags & IF_JUST_CREATED)
    {
      i->flags &= ~IF_JUST_CREATED;
      c |= IF_CHANGE_CREATE | IF_CHANGE_MTU;
    }

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

211 212
  if (c & IF_CHANGE_DOWN)
    neigh_if_down(i);
213

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

221
  WALK_LIST(p, active_proto_list)
222
    if_send_notify(p, c, i);
223

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

231 232 233
  if (c & IF_CHANGE_UP)
    neigh_if_up(i);

234 235
  if ((c & (IF_CHANGE_UP | IF_CHANGE_DOWN | IF_CHANGE_LINK)) == IF_CHANGE_LINK)
    neigh_if_link(i);
236 237
}

238 239 240
static unsigned
if_recalc_flags(struct iface *i, unsigned flags)
{
241 242
  if ((flags & (IF_SHUTDOWN | IF_TMP_DOWN)) ||
      !(flags & IF_ADMIN_UP) ||
Ondřej Zajíček's avatar
Ondřej Zajíček committed
243 244
      !i->addr ||
      (i->master_index && !i->master))
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
    flags &= ~IF_UP;
  else
    flags |= IF_UP;
  return flags;
}

static void
if_change_flags(struct iface *i, unsigned flags)
{
  unsigned of = i->flags;

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

261
/**
262 263
 * if_delete - remove interface
 * @old: interface
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
 *
 * This function is called by the low-level platform dependent code
 * whenever it notices an interface disappears. It is just a shorthand
 * for if_update().
 */

void
if_delete(struct iface *old)
{
  struct iface f = {};
  strncpy(f.name, old->name, sizeof(f.name)-1);
  f.flags = IF_SHUTDOWN;
  if_update(&f);
}

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

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

	if_copy(i, new);
	if (c)
	  if_notify_change(c, i);

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

336 337 338 339
void
if_start_update(void)
{
  struct iface *i;
340
  struct ifa *a;
341 342

  WALK_LIST(i, iface_list)
343 344 345 346 347 348 349 350 351 352 353 354
    {
      i->flags &= ~IF_UPDATED;
      WALK_LIST(a, i->addrs)
	a->flags &= ~IF_UPDATED;
    }
}

void
if_end_partial_update(struct iface *i)
{
  if (i->flags & IF_TMP_DOWN)
    if_change_flags(i, i->flags & ~IF_TMP_DOWN);
355 356
}

357 358 359
void
if_end_update(void)
{
360
  struct iface *i;
361
  struct ifa *a, *b;
362 363

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

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

Martin Mareš's avatar
Martin Mareš committed
386 387 388 389 390 391 392
/**
 * if_feed_baby - advertise interfaces to a new protocol
 * @p: protocol to feed
 *
 * When a new protocol starts, this function sends it a series
 * of notifications about all existing interfaces.
 */
393 394 395 396
void
if_feed_baby(struct proto *p)
{
  struct iface *i;
397
  struct ifa *a;
398

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

Martin Mareš's avatar
Martin Mareš committed
411 412 413 414 415 416 417 418
/**
 * if_find_by_index - find interface by ifindex
 * @idx: ifindex
 *
 * This function finds an &iface structure corresponding to an interface
 * of the given index @idx. Returns a pointer to the structure or %NULL
 * if no such structure exists.
 */
419 420 421 422 423 424
struct iface *
if_find_by_index(unsigned idx)
{
  struct iface *i;

  WALK_LIST(i, iface_list)
425
    if (i->index == idx && !(i->flags & IF_SHUTDOWN))
426 427 428 429
      return i;
  return NULL;
}

Martin Mareš's avatar
Martin Mareš committed
430 431 432 433 434 435 436 437
/**
 * if_find_by_name - find interface by name
 * @name: interface name
 *
 * This function finds an &iface structure corresponding to an interface
 * of the given name @name. Returns a pointer to the structure or %NULL
 * if no such structure exists.
 */
438 439 440 441 442 443 444 445 446 447 448
struct iface *
if_find_by_name(char *name)
{
  struct iface *i;

  WALK_LIST(i, iface_list)
    if (!strcmp(i->name, name))
      return i;
  return NULL;
}

449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
struct iface *
if_get_by_name(char *name)
{
  struct iface *i;

  if (i = if_find_by_name(name))
    return i;

  /* No active iface, create a dummy */
  i = mb_allocz(if_pool, sizeof(struct iface));
  strncpy(i->name, name, sizeof(i->name)-1);
  i->flags = IF_SHUTDOWN;
  init_list(&i->addrs);
  init_list(&i->neighbors);
  add_tail(&iface_list, &i->n);
  return i;
}

467 468
struct ifa *kif_choose_primary(struct iface *i);

469 470 471
static int
ifa_recalc_primary(struct iface *i)
{
472
  struct ifa *a = kif_choose_primary(i);
473

474 475 476 477 478 479 480
  if (a == i->addr)
    return 0;

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

  if (a)
481
    {
482 483 484
      a->flags |= IA_PRIMARY;
      rem_node(&a->n);
      add_head(&i->addrs, &a->n);
485
    }
486 487 488 489 490 491 492 493 494 495 496

  i->addr = a;
  return 1;
}

void
ifa_recalc_all_primary_addresses(void)
{
  struct iface *i;

  WALK_LIST(i, iface_list)
497
    {
498 499
      if (ifa_recalc_primary(i))
	if_change_flags(i, i->flags | IF_TMP_DOWN);
500 501 502
    }
}

503 504 505 506 507 508 509
static inline int
ifa_same(struct ifa *a, struct ifa *b)
{
  return ipa_equal(a->ip, b->ip) && ipa_equal(a->prefix, b->prefix) &&
    a->pxlen == b->pxlen;
}

510

Martin Mareš's avatar
Martin Mareš committed
511 512 513 514 515 516 517 518
/**
 * ifa_update - update interface address
 * @a: new interface address
 *
 * This function adds address information to a network
 * interface. It's called by the platform dependent code during
 * the interface update process described under if_update().
 */
519 520 521 522 523 524 525
struct ifa *
ifa_update(struct ifa *a)
{
  struct iface *i = a->iface;
  struct ifa *b;

  WALK_LIST(b, i->addrs)
526
    if (ifa_same(b, a))
527
      {
528
	if (ipa_equal(b->brd, a->brd) &&
529
	    ipa_equal(b->opposite, a->opposite) &&
530
	    b->scope == a->scope &&
531
	    !((b->flags ^ a->flags) & IA_PEER))
532 533 534 535 536 537 538
	  {
	    b->flags |= IF_UPDATED;
	    return b;
	  }
	ifa_delete(b);
	break;
      }
539

540
#ifndef IPV6
541 542
  if ((i->flags & IF_BROADCAST) && !ipa_nonzero(a->brd))
    log(L_ERR "Missing broadcast address for interface %s", i->name);
543
#endif
544

545 546 547 548
  b = mb_alloc(if_pool, sizeof(struct ifa));
  memcpy(b, a, sizeof(struct ifa));
  add_tail(&i->addrs, &b->n);
  b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
549
  if (ifa_recalc_primary(i))
550 551 552 553 554 555
    if_change_flags(i, i->flags | IF_TMP_DOWN);
  if (b->flags & IF_UP)
    ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
  return b;
}

Martin Mareš's avatar
Martin Mareš committed
556 557 558 559 560 561 562 563
/**
 * ifa_delete - remove interface address
 * @a: interface address
 *
 * This function removes address information from a network
 * interface. It's called by the platform dependent code during
 * the interface update process described under if_update().
 */
564 565 566 567 568 569 570
void
ifa_delete(struct ifa *a)
{
  struct iface *i = a->iface;
  struct ifa *b;

  WALK_LIST(b, i->addrs)
571
    if (ifa_same(b, a))
572 573 574 575 576 577 578 579 580 581 582 583 584
      {
	rem_node(&b->n);
	if (b->flags & IF_UP)
	  {
	    b->flags &= ~IF_UP;
	    ifa_notify_change(IF_CHANGE_DOWN, b);
	  }
	if (b->flags & IA_PRIMARY)
	  {
	    if_change_flags(i, i->flags | IF_TMP_DOWN);
	    ifa_recalc_primary(i);
	  }
	mb_free(b);
585
	return;
586 587 588
      }
}

589
u32
590
if_choose_router_id(struct iface_patt *mask UNUSED6, u32 old_id UNUSED6)
591
{
592
#ifndef IPV6
593 594
  struct iface *i;
  struct ifa *a, *b;
595

596
  b = NULL;
597
  WALK_LIST(i, iface_list)
598 599
    {
      if (!(i->flags & IF_ADMIN_UP) ||
600
	  (i->flags & IF_SHUTDOWN))
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
	continue;

      WALK_LIST(a, i->addrs)
	{
	  if (a->flags & IA_SECONDARY)
	    continue;

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

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

	  /* No pattern or pattern matched */
	  if (!b || ipa_to_u32(a->ip) < ipa_to_u32(b->ip))
	    b = a;
	}
    }

  if (!b)
    return 0;

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

  return id;

#else
  return 0;
632
#endif
633 634
}

Martin Mareš's avatar
Martin Mareš committed
635 636 637 638 639 640
/**
 * if_init - initialize interface module
 *
 * This function is called during BIRD startup to initialize
 * all data structures of the interface module.
 */
641 642 643 644 645
void
if_init(void)
{
  if_pool = rp_new(&root_pool, "Interfaces");
  init_list(&iface_list);
646
  neigh_init(if_pool);
647
}
648 649 650 651 652

/*
 *	Interface Pattern Lists
 */

653 654
int
iface_patt_match(struct iface_patt *ifp, struct iface *i, struct ifa *a)
655
{
656
  struct iface_patt_node *p;
657

658
  WALK_LIST(p, ifp->ipn_list)
659 660
    {
      char *t = p->pattern;
661 662
      int pos = p->positive;

663
      if (t)
664
	{
665 666 667
	  if (*t == '-')
	    {
	      t++;
668
	      pos = !pos;
669
	    }
670

671 672
	  if (!patmatch(t, i->name))
	    continue;
673
	}
674

675 676
      if (p->pxlen == 0)
	return pos;
677

678 679 680 681 682 683
      if (!a)
	continue;

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

684
      if ((a->flags & IA_PEER) &&
685 686
	  ipa_in_net(a->opposite, p->prefix, p->pxlen))
	return pos;
687

688
      continue;
689
    }
690 691 692 693 694

  return 0;
}

struct iface_patt *
695
iface_patt_find(list *l, struct iface *i, struct ifa *a)
696 697 698 699
{
  struct iface_patt *p;

  WALK_LIST(p, *l)
700
    if (iface_patt_match(p, i, a))
701 702
      return p;

703 704 705
  return NULL;
}

706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
static int
iface_plists_equal(struct iface_patt *pa, struct iface_patt *pb)
{
  struct iface_patt_node *x, *y;

  x = HEAD(pa->ipn_list);
  y = HEAD(pb->ipn_list);
  while (x->n.next && y->n.next)
    {
      if ((x->positive != y->positive) ||
	  (!x->pattern && y->pattern) ||	/* This nasty lines where written by me... :-( Feela */
	  (!y->pattern && x->pattern) ||
	  ((x->pattern != y->pattern) && strcmp(x->pattern, y->pattern)) ||
	  !ipa_equal(x->prefix, y->prefix) ||
	  (x->pxlen != y->pxlen))
	return 0;
      x = (void *) x->n.next;
      y = (void *) y->n.next;
    }
  return (!x->n.next && !y->n.next);
}

728 729 730 731 732 733 734 735 736
int
iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct iface_patt *))
{
  struct iface_patt *x, *y;

  x = HEAD(*a);
  y = HEAD(*b);
  while (x->n.next && y->n.next)
    {
737 738
      if (!iface_plists_equal(x, y) ||
	  (comp && !comp(x, y)))
739 740 741 742 743 744
	return 0;
      x = (void *) x->n.next;
      y = (void *) y->n.next;
    }
  return (!x->n.next && !y->n.next);
}
745 746 747 748 749 750 751 752 753 754 755 756 757 758

/*
 *  CLI commands.
 */

static void
if_show_addr(struct ifa *a)
{
  byte opp[STD_ADDRESS_P_LENGTH + 16];

  if (ipa_nonzero(a->opposite))
    bsprintf(opp, ", opposite %I", a->opposite);
  else
    opp[0] = 0;
759
  cli_msg(-1003, "\t%I/%d (%s%s, scope %s)",
760
	  a->ip, a->pxlen,
761
	  (a->flags & IA_PRIMARY) ? "Primary" : (a->flags & IA_SECONDARY) ? "Secondary" : "Unselected",
762
	  opp, ip_scope_text(a->scope));
763 764 765 766 767 768 769 770 771 772 773
}

void
if_show(void)
{
  struct iface *i;
  struct ifa *a;
  char *type;

  WALK_LIST(i, iface_list)
    {
774 775 776
      if (i->flags & IF_SHUTDOWN)
	continue;

Ondřej Zajíček's avatar
Ondřej Zajíček committed
777 778 779 780 781 782 783
      char mbuf[16 + sizeof(i->name)] = {};
      if (i->master)
	bsprintf(mbuf, " master=%s", i->master->name);
      else if (i->master_index)
	bsprintf(mbuf, " master=#%u", i->master_index);

      cli_msg(-1001, "%s %s (index=%d%s)", i->name, (i->flags & IF_UP) ? "up" : "DOWN", i->index, mbuf);
784
      if (!(i->flags & IF_MULTIACCESS))
785 786 787
	type = "PtP";
      else
	type = "MultiAccess";
788
      cli_msg(-1004, "\t%s%s%s Admin%s Link%s%s%s MTU=%d",
789 790 791
	      type,
	      (i->flags & IF_BROADCAST) ? " Broadcast" : "",
	      (i->flags & IF_MULTICAST) ? " Multicast" : "",
792
	      (i->flags & IF_ADMIN_UP) ? "Up" : "Down",
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
	      (i->flags & IF_LINK_UP) ? "Up" : "Down",
	      (i->flags & IF_LOOPBACK) ? " Loopback" : "",
	      (i->flags & IF_IGNORE) ? " Ignored" : "",
	      i->mtu);
      if (i->addr)
	if_show_addr(i->addr);
      WALK_LIST(a, i->addrs)
	if (a != i->addr)
	  if_show_addr(a);
    }
  cli_msg(0, "");
}

void
if_show_summary(void)
{
  struct iface *i;
  byte addr[STD_ADDRESS_P_LENGTH + 16];

812
  cli_msg(-2005, "interface state address");
813 814 815 816 817 818
  WALK_LIST(i, iface_list)
    {
      if (i->addr)
	bsprintf(addr, "%I/%d", i->addr->ip, i->addr->pxlen);
      else
	addr[0] = 0;
819
      cli_msg(-1005, "%-9s %-5s %s", i->name, (i->flags & IF_UP) ? "up" : "DOWN", addr);
820 821 822
    }
  cli_msg(0, "");
}