Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (12.1 KB)

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

    
9
#define LOCAL_DEBUG
10

    
11
#include "nest/bird.h"
12
#include "nest/iface.h"
13
#include "nest/protocol.h"
14
#include "lib/resource.h"
15
#include "lib/string.h"
16
#include "conf/conf.h"
17

    
18
static pool *if_pool;
19

    
20
static void auto_router_id(void);
21

    
22
/*
23
 *        Neighbor Cache
24
 *
25
 *        FIXME: Use hashing to get some real speed.
26
 */
27

    
28
static slab *neigh_slab;
29
static list neigh_list;
30

    
31
static int
32
if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */
33
{
34
  struct ifa *b;
35

    
36
  if (!(i->flags & IF_UP))
37
    return 0;
38
  if ((i->flags & IF_UNNUMBERED) && ipa_equal(*a, i->addr->opposite))
39
    return 1;
40
  WALK_LIST(b, i->addrs)
41
    if (ipa_in_net(*a, b->prefix, b->pxlen))
42
      {
43
        if (ipa_equal(*a, b->prefix) ||        /* Network address */
44
            ipa_equal(*a, b->brd) ||        /* Broadcast */
45
            ipa_equal(*a, b->ip))        /* Our own address */
46
          return -1;
47
        return 1;
48
      }
49
  return 0;
50
}
51

    
52
neighbor *
53
neigh_find(struct proto *p, ip_addr *a, unsigned flags)
54
{
55
  neighbor *n;
56
  int class;
57
  struct iface *i, *j;
58

    
59
  WALK_LIST(n, neigh_list)
60
    if (n->proto == p && ipa_equal(*a, n->addr))
61
      return n;
62

    
63
  class = ipa_classify(*a);
64
  if (class < 0)                        /* Invalid address */
65
    return NULL;
66
  if ((class & IADDR_SCOPE_MASK) < SCOPE_SITE ||
67
      !(class & IADDR_HOST))
68
    return NULL;                        /* Bad scope or a somecast */
69

    
70
  j = NULL;
71
  WALK_LIST(i, iface_list)
72
    switch (if_connected(a, i))
73
      {
74
      case -1:
75
        return NULL;
76
      case 1:
77
        if (!j)                                /* FIXME: Search for _optimal_ iface route? */
78
          j = i;
79
        /* Fall-thru */
80
      }
81
  if (!j && !(flags & NEF_STICKY))
82
    return NULL;
83

    
84
  n = sl_alloc(neigh_slab);
85
  n->addr = *a;
86
  n->iface = j;
87
  add_tail(&neigh_list, &n->n);
88
  if (j)
89
    {
90
      n->sibling = j->neigh;
91
      j->neigh = n;
92
    }
93
  else
94
    n->sibling = NULL;
95
  n->proto = p;
96
  n->data = NULL;
97
  n->flags = flags;
98
  return n;
99
}
100

    
101
void
102
neigh_dump(neighbor *n)
103
{
104
  debug("%p %I ", n, n->addr);
105
  if (n->iface)
106
    debug("%s ", n->iface->name);
107
  else
108
    debug("[] ");
109
  debug("%s %p", n->proto->name, n->data);
110
  if (n->flags & NEF_STICKY)
111
    debug(" STICKY");
112
  debug("\n");
113
}
114

    
115
void
116
neigh_dump_all(void)
117
{
118
  neighbor *n;
119

    
120
  debug("Known neighbors:\n");
121
  WALK_LIST(n, neigh_list)
122
    neigh_dump(n);
123
  debug("\n");
124
}
125

    
126
static void
127
neigh_if_up(struct iface *i)
128
{
129
  neighbor *n;
130

    
131
  WALK_LIST(n, neigh_list)
132
    if (!n->iface &&
133
        if_connected(&n->addr, i) > 0)
134
      {
135
        n->iface = i;
136
        n->sibling = i->neigh;
137
        i->neigh = n;
138
        DBG("Waking up sticky neighbor %I\n", n->addr);
139
        if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
140
          n->proto->neigh_notify(n);
141
      }
142
}
143

    
144
static void
145
neigh_if_down(struct iface *i)
146
{
147
  neighbor *n, *m;
148

    
149
  for(m=i->neigh; n = m;)
150
    {
151
      m = n->sibling;
152
      DBG("Flushing neighbor %I on %s\n", n->addr, i->name);
153
      n->iface = NULL;
154
      if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
155
        n->proto->neigh_notify(n);
156
      if (!(n->flags & NEF_STICKY))
157
        {
158
          rem_node(&n->n);
159
          sl_free(neigh_slab, n);
160
        }
161
    }
162
  i->neigh = NULL;
163
}
164

    
165
void
166
neigh_prune(void)
167
{
168
  neighbor *n, *m, **N;
169
  struct iface *i;
170

    
171
  DBG("Pruning neighbors\n");
172
  WALK_LIST(i, iface_list)
173
    {
174
      N = &i->neigh;
175
      while (n = *N)
176
        {
177
          if (n->proto->core_state == FS_FLUSHING)
178
            {
179
              *N = n->sibling;
180
              rem_node(&n->n);
181
              sl_free(neigh_slab, n);
182
              continue;
183
            }
184
          N = &n->sibling;
185
        }
186
    }
187
}
188

    
189
/*
190
 *        The Interface List
191
 */
192

    
193
list iface_list;
194

    
195
void
196
ifa_dump(struct ifa *a)
197
{
198
  debug("\t%I, net %I/%-2d bc %I -> %I%s%s\n", a->ip, a->prefix, a->pxlen, a->brd, a->opposite,
199
        (a->flags & IF_UP) ? "" : " DOWN",
200
        (a->flags & IA_PRIMARY) ? "" : " SEC");
201
}
202

    
203
void
204
if_dump(struct iface *i)
205
{
206
  struct ifa *a;
207

    
208
  debug("IF%d: %s", i->index, i->name);
209
  if (i->flags & IF_ADMIN_DOWN)
210
    debug(" ADMIN-DOWN");
211
  if (i->flags & IF_UP)
212
    debug(" UP");
213
  else
214
    debug(" DOWN");
215
  if (i->flags & IF_LINK_UP)
216
    debug(" LINK-UP");
217
  if (i->flags & IF_MULTIACCESS)
218
    debug(" MA");
219
  if (i->flags & IF_UNNUMBERED)
220
    debug(" UNNUM");
221
  if (i->flags & IF_BROADCAST)
222
    debug(" BC");
223
  if (i->flags & IF_MULTICAST)
224
    debug(" MC");
225
  if (i->flags & IF_TUNNEL)
226
    debug(" TUNL");
227
  if (i->flags & IF_LOOPBACK)
228
    debug(" LOOP");
229
  if (i->flags & IF_IGNORE)
230
    debug(" IGN");
231
  if (i->flags & IF_TMP_DOWN)
232
    debug(" TDOWN");
233
  debug(" MTU=%d\n", i->mtu);
234
  WALK_LIST(a, i->addrs)
235
    {
236
      ifa_dump(a);
237
      ASSERT((a != i->addr) == !(a->flags & IA_PRIMARY));
238
    }
239
}
240

    
241
void
242
if_dump_all(void)
243
{
244
  struct iface *i;
245

    
246
  debug("Known network interfaces:\n");
247
  WALK_LIST(i, iface_list)
248
    if_dump(i);
249
  debug("Router ID: %08x\n", config->router_id);
250
}
251

    
252
static inline unsigned
253
if_what_changed(struct iface *i, struct iface *j)
254
{
255
  unsigned c;
256

    
257
  if (((i->flags ^ j->flags) & ~(IF_UP | IF_ADMIN_DOWN | IF_UPDATED | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED))
258
      || i->index != j->index)
259
    return IF_CHANGE_TOO_MUCH;
260
  c = 0;
261
  if ((i->flags ^ j->flags) & IF_UP)
262
    c |= (i->flags & IF_UP) ? IF_CHANGE_DOWN : IF_CHANGE_UP;
263
  if (i->mtu != j->mtu)
264
    c |= IF_CHANGE_MTU;
265
  return c;
266
}
267

    
268
static inline void
269
if_copy(struct iface *to, struct iface *from)
270
{
271
  to->flags = from->flags | (to->flags & IF_TMP_DOWN);
272
  to->mtu = from->mtu;
273
}
274

    
275
static void
276
ifa_notify_change(unsigned c, struct ifa *a)
277
{
278
  struct proto *p;
279

    
280
  debug("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip);
281
  WALK_LIST(p, proto_list)
282
    if (p->ifa_notify)
283
      p->ifa_notify(p, c, a);
284
}
285

    
286
static void
287
if_notify_change(unsigned c, struct iface *i)
288
{
289
  struct proto *p;
290
  struct ifa *a;
291

    
292
  if (i->flags & IF_JUST_CREATED)
293
    {
294
      i->flags &= ~IF_JUST_CREATED;
295
      c |= IF_CHANGE_CREATE | IF_CHANGE_MTU;
296
    }
297

    
298
  debug("Interface change notification (%x) for %s\n", c, i->name);
299
  if_dump(i);
300

    
301
  if (c & IF_CHANGE_UP)
302
    neigh_if_up(i);
303
  if (c & IF_CHANGE_DOWN)
304
    WALK_LIST(a, i->addrs)
305
      {
306
        a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
307
        ifa_notify_change(IF_CHANGE_DOWN, a);
308
      }
309

    
310
  WALK_LIST(p, proto_list)
311
    if (p->if_notify)
312
      p->if_notify(p, c, i);
313

    
314
  if (c & IF_CHANGE_UP)
315
    WALK_LIST(a, i->addrs)
316
      {
317
        a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
318
        ifa_notify_change(IF_CHANGE_UP, a);
319
      }
320
  if (c & IF_CHANGE_DOWN)
321
    neigh_if_down(i);
322
}
323

    
324
static unsigned
325
if_recalc_flags(struct iface *i, unsigned flags)
326
{
327
  if ((flags & (IF_ADMIN_DOWN | IF_TMP_DOWN)) ||
328
      !(flags & IF_LINK_UP) ||
329
      !i->addr)
330
    flags &= ~IF_UP;
331
  else
332
    flags |= IF_UP;
333
  return flags;
334
}
335

    
336
static void
337
if_change_flags(struct iface *i, unsigned flags)
338
{
339
  unsigned of = i->flags;
340

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

    
346
struct iface *
347
if_update(struct iface *new)
348
{
349
  struct iface *i;
350
  struct ifa *a, *b;
351
  unsigned c;
352

    
353
  WALK_LIST(i, iface_list)
354
    if (!strcmp(new->name, i->name))
355
      {
356
        new->addr = i->addr;
357
        new->flags = if_recalc_flags(new, new->flags);
358
        c = if_what_changed(i, new);
359
        if (c & IF_CHANGE_TOO_MUCH)        /* Changed a lot, convert it to down/up */
360
          {
361
            DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
362
            if_change_flags(i, i->flags | IF_TMP_DOWN);
363
            rem_node(&i->n);
364
            new->addr = i->addr;
365
            memcpy(&new->addrs, &i->addrs, sizeof(i->addrs));
366
            memcpy(i, new, sizeof(*i));
367
            goto newif;
368
          }
369
        else if (c)
370
          {
371
            if_copy(i, new);
372
            if_notify_change(c, i);
373
          }
374
        i->flags |= IF_UPDATED;
375
        return i;
376
      }
377
  i = mb_alloc(if_pool, sizeof(struct iface));
378
  memcpy(i, new, sizeof(*i));
379
  init_list(&i->addrs);
380
newif:
381
  i->flags |= IF_UPDATED | IF_TMP_DOWN;                /* Tmp down as we don't have addresses yet */
382
  add_tail(&iface_list, &i->n);
383
  return i;
384
}
385

    
386
void
387
if_start_update(void)
388
{
389
  struct iface *i;
390
  struct ifa *a;
391

    
392
  WALK_LIST(i, iface_list)
393
    {
394
      i->flags &= ~IF_UPDATED;
395
      WALK_LIST(a, i->addrs)
396
        a->flags &= ~IF_UPDATED;
397
    }
398
}
399

    
400
void
401
if_end_partial_update(struct iface *i)
402
{
403
  if (i->flags & IF_TMP_DOWN)
404
    if_change_flags(i, i->flags & ~IF_TMP_DOWN);
405
}
406

    
407
void
408
if_end_update(void)
409
{
410
  struct iface *i, j;
411
  struct ifa *a, *b;
412

    
413
  if (!config->router_id)
414
    auto_router_id();
415

    
416
  WALK_LIST(i, iface_list)
417
    {
418
      if (!(i->flags & IF_UPDATED))
419
        if_change_flags(i, (i->flags & ~IF_LINK_UP) | IF_ADMIN_DOWN);
420
      else
421
        {
422
          WALK_LIST_DELSAFE(a, b, i->addrs)
423
            if (!(a->flags & IF_UPDATED))
424
              ifa_delete(a);
425
          if_end_partial_update(i);
426
        }
427
    }
428
}
429

    
430
void
431
if_feed_baby(struct proto *p)
432
{
433
  struct iface *i;
434
  struct ifa *a;
435

    
436
  if (!p->if_notify && !p->ifa_notify)
437
    return;
438
  debug("Announcing interfaces to new protocol %s\n", p->name);
439
  WALK_LIST(i, iface_list)
440
    {
441
      if (p->if_notify)
442
        p->if_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
443
      if (p->ifa_notify && (i->flags & IF_UP))
444
        WALK_LIST(a, i->addrs)
445
          p->ifa_notify(p, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
446
    }
447
}
448

    
449
struct iface *
450
if_find_by_index(unsigned idx)
451
{
452
  struct iface *i;
453

    
454
  WALK_LIST(i, iface_list)
455
    if (i->index == idx)
456
      return i;
457
  return NULL;
458
}
459

    
460
struct iface *
461
if_find_by_name(char *name)
462
{
463
  struct iface *i;
464

    
465
  WALK_LIST(i, iface_list)
466
    if (!strcmp(i->name, name))
467
      return i;
468
  return NULL;
469
}
470

    
471
static int
472
ifa_recalc_primary(struct iface *i)
473
{
474
  struct ifa *a, *b = NULL;
475
  int res;
476

    
477
  WALK_LIST(a, i->addrs)
478
    {
479
      if (!(a->flags & IA_SECONDARY) && (!b || a->scope > b->scope))
480
        b = a;
481
      a->flags &= ~IA_PRIMARY;
482
    }
483
  res = (b != i->addr);
484
  i->addr = b;
485
  if (b)
486
    {
487
      b->flags |= IA_PRIMARY;
488
      rem_node(&b->n);
489
      add_head(&i->addrs, &b->n);
490
    }
491
  return res;
492
}
493

    
494
struct ifa *
495
ifa_update(struct ifa *a)
496
{
497
  struct iface *i = a->iface;
498
  struct ifa *b;
499

    
500
  WALK_LIST(b, i->addrs)
501
    if (ipa_equal(b->ip, a->ip))
502
      {
503
        if (ipa_equal(b->prefix, a->prefix) &&
504
            b->pxlen == a->pxlen &&
505
            ipa_equal(b->brd, a->brd) &&
506
            ipa_equal(b->opposite, a->opposite) &&
507
            b->scope == a->scope)
508
          {
509
            b->flags |= IF_UPDATED;
510
            return b;
511
          }
512
        ifa_delete(b);
513
        break;
514
      }
515
  b = mb_alloc(if_pool, sizeof(struct ifa));
516
  memcpy(b, a, sizeof(struct ifa));
517
  add_tail(&i->addrs, &b->n);
518
  b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
519
  if ((!i->addr || i->addr->scope < b->scope) && ifa_recalc_primary(i))
520
    if_change_flags(i, i->flags | IF_TMP_DOWN);
521
  if (b->flags & IF_UP)
522
    ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
523
  return b;
524
}
525

    
526
void
527
ifa_delete(struct ifa *a)
528
{
529
  struct iface *i = a->iface;
530
  struct ifa *b;
531

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

    
551
static void
552
auto_router_id(void)                        /* FIXME: What if we run IPv6??? */
553
{
554
  struct iface *i, *j;
555

    
556
  j = NULL;
557
  WALK_LIST(i, iface_list)
558
    if ((i->flags & IF_LINK_UP) &&
559
        !(i->flags & (IF_UNNUMBERED | IF_IGNORE | IF_ADMIN_DOWN)) &&
560
        i->addr &&
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
  debug("Guessed router ID %I (%s)\n", j->addr->ip, j->name);
566
  config->router_id = ipa_to_u32(j->addr->ip);
567
}
568

    
569
void
570
if_init(void)
571
{
572
  if_pool = rp_new(&root_pool, "Interfaces");
573
  init_list(&iface_list);
574
  neigh_slab = sl_new(if_pool, sizeof(neighbor));
575
  init_list(&neigh_list);
576
}
577

    
578
/*
579
 *        Interface Pattern Lists
580
 */
581

    
582
struct iface_patt *
583
iface_patt_match(list *l, struct iface *i)
584
{
585
  struct iface_patt *p;
586

    
587
  WALK_LIST(p, *l)
588
    {
589
      char *t = p->pattern;
590
      int ok = 1;
591
      if (*t == '-')
592
        {
593
          t++;
594
          ok = 0;
595
        }
596
      if (patmatch(t, i->name))
597
        return ok ? p : NULL;
598
    }
599
  return NULL;
600
}
601

    
602
int
603
iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct iface_patt *))
604
{
605
  struct iface_patt *x, *y;
606

    
607
  x = HEAD(*a);
608
  y = HEAD(*b);
609
  while (x->n.next && y->n.next)
610
    {
611
      if (strcmp(x->pattern, y->pattern) || comp && !comp(x, y))
612
        return 0;
613
      x = (void *) x->n.next;
614
      y = (void *) y->n.next;
615
    }
616
  return (!x->n.next && !y->n.next);
617
}