Revision 153f02da

View differences:

nest/iface.c
32 32
#include "lib/resource.h"
33 33
#include "lib/string.h"
34 34
#include "conf/conf.h"
35
#include "sysdep/unix/krt.h"
35 36

  
36 37
static pool *if_pool;
37 38

  
38 39
list iface_list;
39 40

  
41
static void if_recalc_preferred(struct iface *i);
42

  
40 43
/**
41 44
 * ifa_dump - dump interface address
42 45
 * @a: interface address descriptor
......
183 186
	    (c & IF_CHANGE_DOWN) ? "goes down" :
184 187
	    (c & IF_CHANGE_MTU) ? "changes MTU" :
185 188
	    (c & IF_CHANGE_LINK) ? "changes link" :
189
	    (c & IF_CHANGE_PREFERRED) ? "changes preferred address" :
186 190
	    (c & IF_CHANGE_CREATE) ? "created" :
187 191
	    "sends unknown event");
188 192
      p->if_notify(p, c, i);
......
211 215

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

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

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

  
229 227
  if (c & IF_CHANGE_UP)
230 228
    neigh_if_up(i);
......
233 231
    neigh_if_link(i);
234 232
}
235 233

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

  
245 242
  return flags;
246 243
}
247 244

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

  
248
  uint of = i->flags;
253 249
  i->flags = if_recalc_flags(i, flags);
250

  
254 251
  if ((i->flags ^ of) & IF_UP)
255 252
    if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i);
256 253
}
......
298 295
  WALK_LIST(i, iface_list)
299 296
    if (!strcmp(new->name, i->name))
300 297
      {
301
	new->addr = i->addr;
302 298
	new->flags = if_recalc_flags(new, new->flags);
303 299
	c = if_what_changed(i, new);
304 300
	if (c & IF_CHANGE_TOO_MUCH)	/* Changed a lot, convert it to down/up */
......
306 302
	    DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
307 303
	    if_change_flags(i, i->flags | IF_TMP_DOWN);
308 304
	    rem_node(&i->n);
309
	    new->addr = i->addr;
305
	    new->addr4 = i->addr4;
306
	    new->addr6 = i->addr6;
307
	    new->llv6 = i->llv6;
308
	    new->sysdep = i->sysdep;
310 309
	    memcpy(&new->addrs, &i->addrs, sizeof(i->addrs));
311 310
	    memcpy(i, new, sizeof(*i));
312
	    i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */
311
	    i->flags &= ~IF_UP; 	/* IF_TMP_DOWN will be added later */
313 312
	    goto newif;
314 313
	  }
315 314

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

  
347 346
void
348 347
if_end_partial_update(struct iface *i)
349 348
{
349
  if (i->flags & IF_NEEDS_RECALC)
350
    if_recalc_preferred(i);
351

  
350 352
  if (i->flags & IF_TMP_DOWN)
351 353
    if_change_flags(i, i->flags & ~IF_TMP_DOWN);
352 354
}
......
364 366
      else
365 367
	{
366 368
	  WALK_LIST_DELSAFE(a, b, i->addrs)
367
	    if (!(a->flags & IF_UPDATED))
369
	    if (!(a->flags & IA_UPDATED))
368 370
	      ifa_delete(a);
369 371
	  if_end_partial_update(i);
370 372
	}
......
461 463
  return i;
462 464
}
463 465

  
464
struct ifa *kif_choose_primary(struct iface *i);
466
static inline void
467
if_set_preferred(struct ifa **pos, struct ifa *new)
468
{
469
  if (*pos)
470
    (*pos)->flags &= ~IA_PRIMARY;
471
  if (new)
472
    new->flags |= IA_PRIMARY;
465 473

  
466
static int
467
ifa_recalc_primary(struct iface *i)
474
  *pos = new;
475
}
476

  
477
static void
478
if_recalc_preferred(struct iface *i)
468 479
{
469
  struct ifa *a = kif_choose_primary(i);
480
  /*
481
   * Preferred address selection priority:
482
   * 1) Address configured in Device protocol
483
   * 2) Sysdep IPv4 address (BSD)
484
   * 3) Old preferred address
485
   * 4) First address in list
486
   */
470 487

  
471
  if (a == i->addr)
472
    return 0;
488
  struct kif_iface_config *ic = kif_get_iface_config(i);
489
  struct ifa *a4 = i->addr4, *a6 = i->addr6, *ll = i->llv6;
490
  ip_addr pref_v4 = ic->pref_v4;
491
  uint change = 0;
492

  
493
  if (kif_update_sysdep_addr(i))
494
    change |= IF_CHANGE_SYSDEP;
473 495

  
474
  if (i->addr)
475
    i->addr->flags &= ~IA_PRIMARY;
496
  /* BSD sysdep address */
497
  if (ipa_zero(pref_v4) && ip4_nonzero(i->sysdep))
498
    pref_v4 = ipa_from_ip4(i->sysdep);
476 499

  
477
  if (a)
500
  struct ifa *a;
501
  WALK_LIST(a, i->addrs)
478 502
    {
479
      a->flags |= IA_PRIMARY;
480
      rem_node(&a->n);
481
      add_head(&i->addrs, &a->n);
503
      /* Secondary address is never selected */
504
      if (a->flags & IA_SECONDARY)
505
	continue;
506

  
507
      if (ipa_is_ip4(a->ip)) {
508
	if (!a4 || ipa_equal(a->ip, pref_v4))
509
	  a4 = a;
510
      } else if (!ipa_is_link_local(a->ip)) {
511
	if (!a6 || ipa_equal(a->ip, ic->pref_v6))
512
	  a6 = a;
513
      } else {
514
	if (!ll || ipa_equal(a->ip, ic->pref_ll))
515
	  ll = a;
516
      }
482 517
    }
483 518

  
484
  i->addr = a;
485
  return 1;
519
  if (a4 != i->addr4)
520
  {
521
    if_set_preferred(&i->addr4, a4);
522
    change |= IF_CHANGE_ADDR4;
523
  }
524

  
525
  if (a6 != i->addr6)
526
  {
527
    if_set_preferred(&i->addr6, a6);
528
    change |= IF_CHANGE_ADDR6;
529
  }
530

  
531
  if (ll != i->llv6)
532
  {
533
    if_set_preferred(&i->llv6, ll);
534
    change |= IF_CHANGE_LLV6;
535
  }
536

  
537
  i->flags &= ~IF_NEEDS_RECALC;
538

  
539
  /*
540
   * FIXME: There should be proper notification instead of iface restart:
541
   * if_notify_change(change, i)
542
   */
543
  if (change)
544
    if_change_flags(i, i->flags | IF_TMP_DOWN);
486 545
}
487 546

  
488 547
void
489
ifa_recalc_all_primary_addresses(void)
548
if_recalc_all_preferred_addresses(void)
490 549
{
491 550
  struct iface *i;
492 551

  
493 552
  WALK_LIST(i, iface_list)
494
    {
495
      if (ifa_recalc_primary(i))
496
	if_change_flags(i, i->flags | IF_TMP_DOWN);
497
    }
553
  {
554
    if_recalc_preferred(i);
555

  
556
    if (i->flags & IF_TMP_DOWN)
557
      if_change_flags(i, i->flags & ~IF_TMP_DOWN);
558
  }
498 559
}
499 560

  
500 561
static inline int
......
526 587
	    b->scope == a->scope &&
527 588
	    !((b->flags ^ a->flags) & IA_PEER))
528 589
	  {
529
	    b->flags |= IF_UPDATED;
590
	    b->flags |= IA_UPDATED;
530 591
	    return b;
531 592
	  }
532 593
	ifa_delete(b);
......
534 595
      }
535 596

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

  
539 600
  b = mb_alloc(if_pool, sizeof(struct ifa));
540 601
  memcpy(b, a, sizeof(struct ifa));
541 602
  add_tail(&i->addrs, &b->n);
542
  b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
543
  if (ifa_recalc_primary(i))
544
    if_change_flags(i, i->flags | IF_TMP_DOWN);
545
  if (b->flags & IF_UP)
603
  b->flags |= IA_UPDATED;
604

  
605
  i->flags |= IF_NEEDS_RECALC;
606
  if (i->flags & IF_UP)
546 607
    ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
547 608
  return b;
548 609
}
......
565 626
    if (ifa_same(b, a))
566 627
      {
567 628
	rem_node(&b->n);
568
	if (b->flags & IF_UP)
569
	  {
570
	    b->flags &= ~IF_UP;
571
	    ifa_notify_change(IF_CHANGE_DOWN, b);
572
	  }
629

  
573 630
	if (b->flags & IA_PRIMARY)
574 631
	  {
575
	    if_change_flags(i, i->flags | IF_TMP_DOWN);
576
	    ifa_recalc_primary(i);
632
	    /*
633
	     * We unlink deleted preferred address and mark for recalculation.
634
	     * FIXME: This could break if we make iface scan non-atomic, as
635
	     * protocols still could use the freed address until they get
636
	     * if_notify from preferred route recalculation.
637
	     */
638
	    if (b == i->addr4) i->addr4 = NULL;
639
	    if (b == i->addr6) i->addr6 = NULL;
640
	    if (b == i->llv6) i->llv6 = NULL;
641
	    i->flags |= IF_NEEDS_RECALC;
577 642
	  }
643

  
644
	if (i->flags & IF_UP)
645
	  ifa_notify_change(IF_CHANGE_DOWN, b);
646

  
578 647
	mb_free(b);
579 648
	return;
580 649
      }
......
741 810
static void
742 811
if_show_addr(struct ifa *a)
743 812
{
744
  byte opp[IPA_MAX_TEXT_LENGTH + 16];
813
  byte *flg, opp[IPA_MAX_TEXT_LENGTH + 16];
814

  
815
  flg = (a->flags & IA_PRIMARY) ? "Preferred, " : (a->flags & IA_SECONDARY) ? "Secondary, " : "";
745 816

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

  
822
  cli_msg(-1003, "\t%I/%d (%s%sscope %s)",
823
	  a->ip, a->prefix.pxlen, flg, opp, ip_scope_text(a->scope));
754 824
}
755 825

  
756 826
void
......
765 835
      if (i->flags & IF_SHUTDOWN)
766 836
	continue;
767 837

  
768
      cli_msg(-1001, "%s %s (index=%d)", i->name, (i->flags & IF_UP) ? "up" : "DOWN", i->index);
838
      cli_msg(-1001, "%s %s (index=%d)", i->name, (i->flags & IF_UP) ? "Up" : "Down", i->index);
769 839
      if (!(i->flags & IF_MULTIACCESS))
770 840
	type = "PtP";
771 841
      else
......
779 849
	      (i->flags & IF_LOOPBACK) ? " Loopback" : "",
780 850
	      (i->flags & IF_IGNORE) ? " Ignored" : "",
781 851
	      i->mtu);
782
      if (i->addr)
783
	if_show_addr(i->addr);
852

  
853
      WALK_LIST(a, i->addrs)
854
	if (a->prefix.type == NET_IP4)
855
	  if_show_addr(a);
856

  
784 857
      WALK_LIST(a, i->addrs)
785
	if (a != i->addr)
858
	if (a->prefix.type == NET_IP6)
786 859
	  if_show_addr(a);
787 860
    }
788 861
  cli_msg(0, "");
......
792 865
if_show_summary(void)
793 866
{
794 867
  struct iface *i;
795
  byte addr[IPA_MAX_TEXT_LENGTH + 16];
796 868

  
797
  cli_msg(-2005, "interface state address");
869
  cli_msg(-2005,  "%-10s %-6s %-18s %s", "Interface", "State", "IPv4 address", "IPv6 address");
798 870
  WALK_LIST(i, iface_list)
799 871
    {
800
      if (i->addr)
801
	bsprintf(addr, "%I/%d", i->addr->ip, i->addr->prefix.pxlen);
872
      byte a4[IPA_MAX_TEXT_LENGTH + 17];
873
      byte a6[IPA_MAX_TEXT_LENGTH + 17];
874

  
875
      if (i->addr4)
876
	bsprintf(a4, "%I/%d", i->addr4->ip, i->addr4->prefix.pxlen);
802 877
      else
803
	addr[0] = 0;
804
      cli_msg(-1005, "%-9s %-5s %s", i->name, (i->flags & IF_UP) ? "up" : "DOWN", addr);
878
	a4[0] = 0;
879

  
880
      if (i->addr6)
881
	bsprintf(a6, "%I/%d", i->addr6->ip, i->addr6->prefix.pxlen);
882
      else
883
	a6[0] = 0;
884

  
885
      cli_msg(-1005, "%-10s %-6s %-18s %s",
886
	      i->name, (i->flags & IF_UP) ? "Up" : "Down", a4, a6);
805 887
    }
806 888
  cli_msg(0, "");
807 889
}
nest/iface.h
35 35
  unsigned mtu;
36 36
  unsigned index;			/* OS-dependent interface index */
37 37
  list addrs;				/* Addresses assigned to this interface */
38
  struct ifa *addr;			/* Primary address */
38
  struct ifa *addr4;			/* Primary address for IPv4 */
39
  struct ifa *addr6;			/* Primary address for IPv6 */
40
  struct ifa *llv6;			/* Primary link-local address for IPv6 */
41
  ip4_addr sysdep;			/* Arbitrary IPv4 address for internal sysdep use */
39 42
  list neighbors;			/* All neighbors on this interface */
40 43
};
41 44

  
42
#define IF_UP 1				/* IF_ADMIN_UP and IP address known */
45
#define IF_UP 1				/* Currently just IF_ADMIN_UP */
43 46
#define IF_MULTIACCESS 2
44 47
#define IF_BROADCAST 4
45 48
#define IF_MULTICAST 8
......
70 73

  
71 74
#define IF_JUST_CREATED 0x10000000	/* Send creation event as soon as possible */
72 75
#define IF_TMP_DOWN 0x20000000		/* Temporary shutdown due to interface reconfiguration */
73
#define IF_UPDATED 0x40000000		/* Touched in last scan */
76
#define IF_UPDATED 0x40000000		/* Iface touched in last scan */
77
#define IF_NEEDS_RECALC	0x80000000	/* Preferred address recalculation is needed */
78

  
79
#define IA_UPDATED IF_UPDATED		/* Address touched in last scan */
74 80

  
75 81
/* Interface change events */
76 82

  
......
79 85
#define IF_CHANGE_MTU 4
80 86
#define IF_CHANGE_CREATE 8		/* Seen this interface for the first time */
81 87
#define IF_CHANGE_LINK 0x10
88
#define IF_CHANGE_ADDR4	0x100		/* Change of iface->addr4 */
89
#define IF_CHANGE_ADDR6	0x200		/* ... */
90
#define IF_CHANGE_LLV6 0x400
91
#define IF_CHANGE_SYSDEP 0x800
82 92
#define IF_CHANGE_TOO_MUCH 0x40000000	/* Used internally */
83 93

  
94
#define IF_CHANGE_PREFERRED (IF_CHANGE_ADDR4 | IF_CHANGE_ADDR6 | IF_CHANGE_LLV6)
95

  
84 96
void if_init(void);
85 97
void if_dump(struct iface *);
86 98
void if_dump_all(void);
......
99 111
struct iface *if_find_by_index(unsigned);
100 112
struct iface *if_find_by_name(char *);
101 113
struct iface *if_get_by_name(char *);
102
void ifa_recalc_all_primary_addresses(void);
114
void if_recalc_all_preferred_addresses(void);
103 115

  
104 116

  
105 117
/* The Neighbor Cache */
nest/rt-dev.c
33 33
  struct channel *c;
34 34

  
35 35
  if (!EMPTY_LIST(cf->iface_list) &&
36
      !iface_patt_find(&cf->iface_list, ad->iface, ad->iface->addr))
36
      !iface_patt_find(&cf->iface_list, ad->iface, ad))
37 37
    /* Empty list is automatically treated as "*" */
38 38
    return;
39 39

  
proto/babel/babel.c
1501 1501
  ifa->cf = ic;
1502 1502
  ifa->pool = pool;
1503 1503
  ifa->ifname = new->name;
1504
  ifa->addr = new->llv6->ip;
1504 1505

  
1505 1506
  add_tail(&p->interfaces, NODE ifa);
1506 1507

  
1507
  ip_addr addr4 = IPA_NONE;
1508
  struct ifa *addr;
1509
  WALK_LIST(addr, new->addrs)
1510
  {
1511
    if (ipa_is_link_local(addr->ip))
1512
      ifa->addr = addr->ip;
1513

  
1514
    if (ipa_zero(addr4) && ipa_is_ip4(addr->ip))
1515
      addr4 = addr->ip;
1516
  }
1517

  
1508
  ip_addr addr4 = new->addr4 ? new->addr4->ip : IPA_NONE;
1518 1509
  ifa->next_hop_ip4 = ipa_nonzero(ic->next_hop_ip4) ? ic->next_hop_ip4 : addr4;
1519 1510
  ifa->next_hop_ip6 = ipa_nonzero(ic->next_hop_ip6) ? ic->next_hop_ip6 : ifa->addr;
1520 1511

  
1521
  if (ipa_zero(ifa->addr))
1522
    log(L_WARN "%s: Cannot find link-local addr on %s", p->p.name, new->name);
1523

  
1524 1512
  if (ipa_zero(ifa->next_hop_ip4) && p->ip4_channel)
1525 1513
    log(L_WARN "%s: Cannot find IPv4 next hop addr on %s", p->p.name, new->name);
1526 1514

  
......
1576 1564
    if (!(iface->flags & IF_MULTICAST))
1577 1565
      return;
1578 1566

  
1567
    /* Ignore ifaces without link-local address */
1568
    if (!iface->llv6)
1569
      return;
1570

  
1579 1571
    if (ic)
1580 1572
      babel_add_iface(p, iface, ic);
1581 1573

  
......
1615 1607

  
1616 1608
  ifa->cf = new;
1617 1609

  
1618
  if (ipa_nonzero(new->next_hop_ip4))
1619
    ifa->next_hop_ip4 = new->next_hop_ip4;
1620
  else
1621
  {
1622
    ifa->next_hop_ip4 = IPA_NONE;
1623

  
1624
    struct ifa *addr;
1625
    WALK_LIST(addr, ifa->iface->addrs)
1626
      if (ipa_is_ip4(addr->ip))
1627
      {
1628
	ifa->next_hop_ip4 = addr->ip;
1629
	break;
1630
      }
1631
  }
1632

  
1610
  ip_addr addr4 = ifa->iface->addr4 ? ifa->iface->addr4->ip : IPA_NONE;
1611
  ifa->next_hop_ip4 = ipa_nonzero(new->next_hop_ip4) ? new->next_hop_ip4 : addr4;
1633 1612
  ifa->next_hop_ip6 = ipa_nonzero(new->next_hop_ip6) ? new->next_hop_ip6 : ifa->addr;
1634 1613

  
1635 1614
  if (ipa_zero(ifa->next_hop_ip4) && p->ip4_channel)
......
1660 1639

  
1661 1640
  WALK_LIST(iface, iface_list)
1662 1641
  {
1663
    if (! (iface->flags & IF_UP))
1642
    if (!(iface->flags & IF_UP))
1643
      continue;
1644

  
1645
    /* Ignore non-multicast ifaces */
1646
    if (!(iface->flags & IF_MULTICAST))
1647
      continue;
1648

  
1649
    /* Ignore ifaces without link-local address */
1650
    if (!iface->llv6)
1664 1651
      continue;
1665 1652

  
1666 1653
    struct babel_iface *ifa = babel_find_iface(p, iface);
proto/babel/packets.c
1294 1294
      sk->iface->name, sk->faddr, sk->laddr);
1295 1295

  
1296 1296
  /* Silently ignore my own packets */
1297
  if (ipa_equal(ifa->iface->addr->ip, sk->faddr))
1297
  if (ipa_equal(sk->faddr, sk->saddr))
1298 1298
    return 1;
1299 1299

  
1300 1300
  if (!ipa_is_link_local(sk->faddr))
......
1329 1329
  sk->sport = ifa->cf->port;
1330 1330
  sk->dport = ifa->cf->port;
1331 1331
  sk->iface = ifa->iface;
1332
  sk->saddr = ifa->addr;
1332 1333

  
1333 1334
  sk->rx_hook = babel_rx_hook;
1334 1335
  sk->tx_hook = babel_tx_hook;
proto/bgp/bgp.c
1094 1094

  
1095 1095
  if (ipa_is_link_local(p->source_addr))
1096 1096
    p->link_addr = p->source_addr;
1097
  else
1098
  {
1099
    /* Find some link-local address for given iface */
1100
    struct ifa *a;
1101
    WALK_LIST(a, p->neigh->iface->addrs)
1102
      if (a->scope == SCOPE_LINK)
1103
      {
1104
	p->link_addr = a->ip;
1105
	break;
1106
      }
1107

  
1108
    DBG("%s: Selected link-local address %I\n", p->p.name, p->link_addr);
1109
  }
1097
  else if (p->neigh->iface->llv6)
1098
    p->link_addr = p->neigh->iface->llv6->ip;
1110 1099

  
1111 1100
  bgp_initiate(p);
1112 1101
}
proto/radv/packets.c
358 358
  if (sk->lifindex != sk->iface->index)
359 359
    return 1;
360 360

  
361
  if (ipa_equal(sk->faddr, ifa->addr->ip))
361
  if (ipa_equal(sk->faddr, sk->saddr))
362 362
    return 1;
363 363

  
364 364
  if (size < 8)
proto/radv/radv.c
138 138
  radv_iface_notify(ifa, RA_EV_INIT);
139 139
}
140 140

  
141
static inline struct ifa *
142
find_lladdr(struct iface *iface)
143
{
144
  struct ifa *a;
145
  WALK_LIST(a, iface->addrs)
146
    if ((a->prefix.type == NET_IP6) && (a->scope == SCOPE_LINK))
147
      return a;
148

  
149
  return NULL;
150
}
151

  
152 141
static void
153 142
radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_config *cf)
154 143
{
......
161 150
  ifa->ra = p;
162 151
  ifa->cf = cf;
163 152
  ifa->iface = iface;
153
  ifa->addr = iface->llv6;
164 154

  
165 155
  add_tail(&p->iface_list, NODE ifa);
166 156

  
167
  ifa->addr = find_lladdr(iface);
168
  if (!ifa->addr)
169
  {
170
    log(L_ERR "%s: Missing link-local address on interface %s", p->p.name, iface->name);
171
    return;
172
  }
173

  
174 157
  timer *tm = tm_new(pool);
175 158
  tm->hook = radv_timer;
176 159
  tm->data = ifa;
......
216 199

  
217 200
  if (flags & IF_CHANGE_UP)
218 201
  {
219
    struct radv_iface_config *ic = (struct radv_iface_config *)
220
      iface_patt_find(&cf->patt_list, iface, NULL);
202
    struct radv_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
203

  
204
    /* Ignore non-multicast ifaces */
205
    if (!(iface->flags & IF_MULTICAST))
206
      return;
207

  
208
    /* Ignore ifaces without link-local address */
209
    if (!iface->llv6)
210
      return;
221 211

  
222 212
    if (ic)
223 213
      radv_iface_new(p, iface, ic);
......
395 385
  struct iface *iface;
396 386
  WALK_LIST(iface, iface_list)
397 387
  {
388
    if (!(iface->flags & IF_UP))
389
      continue;
390

  
391
    /* Ignore non-multicast ifaces */
392
    if (!(iface->flags & IF_MULTICAST))
393
      continue;
394

  
395
    /* Ignore ifaces without link-local address */
396
    if (!iface->llv6)
397
      continue;
398

  
398 399
    struct radv_iface *ifa = radv_iface_find(p, iface);
399 400
    struct radv_iface_config *ic = (struct radv_iface_config *)
400 401
      iface_patt_find(&new->patt_list, iface, NULL);
proto/rip/packets.c
669 669
      sk->iface->name, sk->faddr, sk->laddr);
670 670

  
671 671
  /* Silently ignore my own packets */
672
  /* FIXME: Better local address check */
673
  if (ipa_equal(ifa->iface->addr->ip, sk->faddr))
672
  if (ipa_equal(sk->faddr, sk->saddr))
674 673
    return 1;
675 674

  
676 675
  if (rip_is_ng(p) && !ipa_is_link_local(sk->faddr))
......
742 741
  sk->sport = ifa->cf->port;
743 742
  sk->dport = ifa->cf->port;
744 743
  sk->iface = ifa->iface;
745

  
746
  /*
747
   * For RIPv2, we explicitly choose a primary address, mainly to ensure that
748
   * RIP and BFD uses the same one. For RIPng, we left it to kernel, which
749
   * should choose some link-local address based on the same scope rule.
750
   */
751
  if (rip_is_v2(p))
752
    sk->saddr = ifa->iface->addr->ip;
744
  sk->saddr = rip_is_v2(p) ? ifa->iface->addr4->ip : ifa->iface->llv6->ip;
753 745

  
754 746
  sk->rx_hook = rip_rx_hook;
755 747
  sk->tx_hook = rip_tx_hook;
proto/rip/rip.c
630 630
  else if (ic->mode == RIP_IM_MULTICAST)
631 631
    ifa->addr = rip_is_v2(p) ? IP4_RIP_ROUTERS : IP6_RIP_ROUTERS;
632 632
  else /* Broadcast */
633
    ifa->addr = iface->addr->brd;
633
    ifa->addr = iface->addr4->brd;
634
  /*
635
   * The above is just a workaround for BSD as it can't send broadcasts
636
   * to 255.255.255.255. BSD systems need the network broadcast address instead.
637
   *
638
   * TODO: move this to sysdep code
639
   */
634 640

  
635 641
  init_list(&ifa->neigh_list);
636 642

  
......
706 712

  
707 713
  WALK_LIST(iface, iface_list)
708 714
  {
709
    if (! (iface->flags & IF_UP))
715
    if (!(iface->flags & IF_UP))
716
      continue;
717

  
718
    /* Ignore ifaces without appropriate address */
719
    if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
710 720
      continue;
711 721

  
712 722
    struct rip_iface *ifa = rip_find_iface(p, iface);
......
744 754
  {
745 755
    struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
746 756

  
757
    /* Ignore ifaces without appropriate address */
758
    if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
759
      return;
760

  
747 761
    if (ic)
748 762
      rip_add_iface(p, iface, ic);
749 763

  
sysdep/bsd/krt-sock.c
287 287
#endif
288 288
  {
289 289
    /* Fallback for all other valid cases */
290
    if (!i->addr)
291
    {
292
      log(L_ERR "KRT: interface %s has no IP addess", i->name);
293
      return -1;
294
    }
295 290

  
296 291
#ifdef RTF_CLONING
297 292
    if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS)	/* PTP */
298 293
      msg.rtm.rtm_flags |= RTF_CLONING;
299 294
#endif
300 295

  
301
    sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0);
296
    struct ifa *addr = (net->n.addr->type == NET_IP4) ? i->addr4 : (i->addr6 ?: i->llv6);
297

  
298
    if (!addr)
299
    {
300
      log(L_ERR "KRT: interface %s has no IP addess", i->name);
301
      return -1;
302
    }
303

  
304
    sockaddr_fill(&gate, af, addr->ip, i, 0);
302 305
    msg.rtm.rtm_addrs |= RTA_GATEWAY;
303 306
    break;
304 307
  }
......
1124 1127
  krt_buffer_release(&p->p);
1125 1128
}
1126 1129

  
1127

  
1128
struct ifa *
1129
kif_get_primary_ip(struct iface *i UNUSED)
1130
int
1131
kif_update_sysdep_addr(struct iface *i)
1130 1132
{
1131
#if 0
1132 1133
  static int fd = -1;
1133
  
1134

  
1134 1135
  if (fd < 0)
1135 1136
    fd = socket(AF_INET, SOCK_DGRAM, 0);
1136 1137

  
......
1140 1141

  
1141 1142
  int rv = ioctl(fd, SIOCGIFADDR, (char *) &ifr);
1142 1143
  if (rv < 0)
1143
    return NULL;
1144

  
1145
  ip_addr addr;
1146
  struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
1147
  memcpy(&addr, &sin->sin_addr.s_addr, sizeof(ip_addr));
1148
  ipa_ntoh(addr);
1144
    return 0;
1149 1145

  
1150
  struct ifa *a;
1151
  WALK_LIST(a, i->addrs)
1152
  {
1153
    if (ipa_equal(a->ip, addr))
1154
      return a;
1155
  }
1156
#endif
1146
  ip4_addr old = i->sysdep;
1147
  i->sysdep = ip4_from_ipa(ipa_from_sa4(&ifr.ifr_addr);
1157 1148

  
1158
  return NULL;
1149
  return !ip4_equal(i->sysdep, addr);
1159 1150
}
sysdep/bsd/sysio.h
38 38
 */
39 39

  
40 40
#define INIT_MREQ4(maddr,ifa) \
41
  { .imr_multiaddr = ipa_to_in4(maddr), .imr_interface = ipa_to_in4(ifa->addr->ip) }
41
  { .imr_multiaddr = ipa_to_in4(maddr), .imr_interface = ip4_to_in4(ifa->sysdep) }
42 42

  
43 43
static inline int
44 44
sk_setup_multicast4(sock *s)
45 45
{
46
  struct in_addr ifa = ipa_to_in4(s->iface->addr->ip);
46
  struct in_addr ifa = ip4_to_in4(s->iface->sysdep);
47 47
  u8 ttl = s->ttl;
48 48
  u8 n = 0;
49 49

  
sysdep/linux/netlink.c
2030 2030
kif_sys_shutdown(struct kif_proto *p UNUSED)
2031 2031
{
2032 2032
}
2033

  
2034
int
2035
kif_update_sysdep_addr(struct iface *i UNUSED)
2036
{
2037
  return 0;
2038
}
sysdep/unix/krt.Y
14 14

  
15 15
#define THIS_KRT ((struct krt_config *) this_proto)
16 16
#define THIS_KIF ((struct kif_config *) this_proto)
17
#define KIF_IFACE ((struct kif_iface_config *) this_ipatt)
17 18

  
18 19
static void
19 20
krt_set_merge_paths(struct channel_config *cc, uint merge, uint limit)
......
25 26
  cc->merge_limit = limit;
26 27
}
27 28

  
29
static void
30
kif_set_preferred(ip_addr ip)
31
{
32
  if (ipa_is_ip4(ip))
33
    KIF_IFACE->pref_v4 = ip;
34
  else if (!ipa_is_link_local(ip))
35
    KIF_IFACE->pref_v6 = ip;
36
  else
37
    KIF_IFACE->pref_ll = ip;
38
}
39

  
28 40
CF_DECLS
29 41

  
30 42
CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE, ROUTES, GRACEFUL, RESTART, KRT_SOURCE, KRT_METRIC, MERGE, PATHS)
......
88 100

  
89 101
kif_item:
90 102
   proto_item
103
 | INTERFACE kif_iface
91 104
 | SCAN TIME expr {
92 105
      /* Scan time of 0 means scan on startup only */
93 106
      THIS_KIF->scan_time = $3;
94 107
   }
95
 | PRIMARY opttext net_or_ipa {
96
     struct kif_primary_item *kpi = cfg_alloc(sizeof (struct kif_primary_item));
97
     kpi->pattern = $2;
98
     kpi->addr = $3;
99
     add_tail(&THIS_KIF->primary, &kpi->n);
100
   }
101 108
 ;
102 109

  
110
kif_iface_start:
111
{
112
  this_ipatt = cfg_allocz(sizeof(struct kif_iface_config));
113
  add_tail(&THIS_KIF->iface_list, NODE this_ipatt);
114
  init_list(&this_ipatt->ipn_list);
115
}
116

  
117
kif_iface_item:
118
   PREFERRED ipa { kif_set_preferred($2); }
119
 ;
120

  
121
kif_iface_opts:
122
   /* empty */
123
 | kif_iface_opts kif_iface_item ';'
124
 ;
125

  
126
kif_iface_opt_list:
127
   /* empty */
128
 | '{' kif_iface_opts '}'
129
 ;
130

  
131
kif_iface:
132
  kif_iface_start iface_patt_list_nopx kif_iface_opt_list;
133

  
134

  
103 135
CF_ADDTO(dynamic_attr, KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_KRT_SOURCE); })
104 136
CF_ADDTO(dynamic_attr, KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_KRT_METRIC); })
105 137

  
sysdep/unix/krt.c
89 89
static timer *kif_scan_timer;
90 90
static bird_clock_t kif_last_shot;
91 91

  
92
static struct kif_iface_config kif_default_iface = {};
93

  
94
struct kif_iface_config *
95
kif_get_iface_config(struct iface *iface)
96
{
97
  struct kif_config *cf = (void *) (kif_proto->p.cf);
98
  struct kif_iface_config *ic = (void *) iface_patt_find(&cf->iface_list, iface, NULL);
99
  return ic ?: &kif_default_iface;
100
}
101

  
92 102
static void
93 103
kif_scan(timer *t)
94 104
{
......
116 126
    tm_start(kif_scan_timer, 1);
117 127
}
118 128

  
119
static inline int
120
prefer_addr(struct ifa *a, struct ifa *b)
121
{
122
  int sa = a->scope > SCOPE_LINK;
123
  int sb = b->scope > SCOPE_LINK;
124

  
125
  if (sa < sb)
126
    return 0;
127
  else if (sa > sb)
128
    return 1;
129
  else
130
    return ipa_compare(a->ip, b->ip) < 0;
131
}
132

  
133
static inline struct ifa *
134
find_preferred_ifa(struct iface *i, const net_addr *n)
135
{
136
  struct ifa *a, *b = NULL;
137

  
138
  WALK_LIST(a, i->addrs)
139
    {
140
      if (!(a->flags & IA_SECONDARY) &&
141
	  (!n || ipa_in_netX(a->ip, n)) &&
142
	  (!b || prefer_addr(a, b)))
143
	b = a;
144
    }
145

  
146
  return b;
147
}
148

  
149
struct ifa *
150
kif_choose_primary(struct iface *i)
151
{
152
  struct kif_config *cf = (struct kif_config *) (kif_proto->p.cf);
153
  struct kif_primary_item *it;
154
  struct ifa *a;
155

  
156
  WALK_LIST(it, cf->primary)
157
    {
158
      if (!it->pattern || patmatch(it->pattern, i->name))
159
	if (a = find_preferred_ifa(i, &it->addr))
160
	  return a;
161
    }
162

  
163
  if (a = kif_get_primary_ip(i))
164
    return a;
165

  
166
  return find_preferred_ifa(i, NULL);
167
}
168

  
169

  
170 129
static struct proto *
171 130
kif_init(struct proto_config *c)
172 131
{
......
224 183
      tm_start(kif_scan_timer, n->scan_time);
225 184
    }
226 185

  
227
  if (!EMPTY_LIST(o->primary) || !EMPTY_LIST(n->primary))
186
  if (!EMPTY_LIST(o->iface_list) || !EMPTY_LIST(n->iface_list))
228 187
    {
229 188
      /* This is hack, we have to update a configuration
230 189
       * to the new value just now, because it is used
231
       * for recalculation of primary addresses.
190
       * for recalculation of preferred addresses.
232 191
       */
233 192
      p->cf = new;
234 193

  
235
      ifa_recalc_all_primary_addresses();
194
      if_recalc_all_preferred_addresses();
236 195
    }
237 196

  
238 197
  return 1;
......
254 213

  
255 214
  kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, class);
256 215
  kif_cf->scan_time = 60;
257
  init_list(&kif_cf->primary);
216
  init_list(&kif_cf->iface_list);
258 217

  
259 218
  kif_sys_init_config(kif_cf);
260 219
  return (struct proto_config *) kif_cf;
......
266 225
  struct kif_config *d = (struct kif_config *) dest;
267 226
  struct kif_config *s = (struct kif_config *) src;
268 227

  
269
  /* Copy primary addr list */
270
  cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item));
228
  /* Copy interface config list */
229
  cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct kif_iface_config));
271 230

  
272 231
  /* Fix sysdep parts */
273 232
  kif_sys_copy_config(d, s);
274 233
}
275 234

  
276

  
277 235
struct protocol proto_unix_iface = {
278 236
  .name = 		"Device",
279 237
  .template = 		"device%d",
sysdep/unix/krt.h
94 94

  
95 95
extern struct protocol proto_unix_iface;
96 96

  
97
struct kif_primary_item {
98
  node n;
99
  byte *pattern;
100
  net_addr addr;
101
};
102

  
103 97
struct kif_config {
104 98
  struct proto_config c;
105 99
  struct kif_params sys;	/* Sysdep params */
100

  
101
  list iface_list;		/* List of iface configs (struct kif_iface_config) */
106 102
  int scan_time;		/* How often we re-scan interfaces */
107
  list primary;			/* Preferences for primary addresses (struct kif_primary_item) */
103
};
104

  
105
struct kif_iface_config {
106
  struct iface_patt i;
107

  
108
  ip_addr pref_v4;
109
  ip_addr pref_v6;
110
  ip_addr pref_ll;
108 111
};
109 112

  
110 113
struct kif_proto {
......
116 119

  
117 120
#define KIF_CF ((struct kif_config *)p->p.cf)
118 121

  
122
struct kif_iface_config * kif_get_iface_config(struct iface *iface);
119 123
struct proto_config * krt_init_config(int class);
120 124

  
121 125

  
......
150 154

  
151 155
void kif_do_scan(struct kif_proto *);
152 156

  
153
struct ifa *kif_get_primary_ip(struct iface *i);
157
int kif_update_sysdep_addr(struct iface *i);
154 158

  
155 159
#endif
sysdep/unix/unix.h
80 80
static inline struct in_addr ipa_to_in4(ip_addr a)
81 81
{ return (struct in_addr) { htonl(ipa_to_u32(a)) }; }
82 82

  
83
static inline struct in_addr ip4_to_in4(ip4_addr a)
84
{ return (struct in_addr) { htonl(ip4_to_u32(a)) }; }
85

  
83 86
static inline struct in6_addr ipa_to_in6(ip_addr a)
84 87
{ return (struct in6_addr) { .s6_addr32 = { htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a)) } }; }
85 88

  

Also available in: Unified diff