Statistics
| Branch: | Revision:

iof-bird-daemon / nest / iface.c @ 9a158361

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
            WALK_LIST_DELSAFE(a, b, i->addrs)
365
              ifa_delete(a);
366
            goto newif;
367
          }
368
        else if (c)
369
          {
370
            if_copy(i, new);
371
            if_notify_change(c, i);
372
          }
373
        i->flags |= IF_UPDATED;
374
        return i;
375
      }
376
  i = mb_alloc(if_pool, sizeof(struct iface));
377
newif:
378
  memcpy(i, new, sizeof(*i));
379
  init_list(&i->addrs);
380
  i->flags |= IF_UPDATED | IF_TMP_DOWN;                /* Tmp down as we don't have addresses yet */
381
  add_tail(&iface_list, &i->n);
382
  return i;
383
}
384

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
554
  j = NULL;
555
  WALK_LIST(i, iface_list)
556
    if ((i->flags & IF_LINK_UP) &&
557
        !(i->flags & (IF_UNNUMBERED | IF_IGNORE | IF_ADMIN_DOWN)) &&
558
        i->addr &&
559
        (!j || ipa_to_u32(i->addr->ip) < ipa_to_u32(j->addr->ip)))
560
      j = i;
561
  if (!j)
562
    die("Cannot determine router ID (no suitable network interface found), please configure it manually");
563
  debug("Guessed router ID %I (%s)\n", j->addr->ip, j->name);
564
  config->router_id = ipa_to_u32(j->addr->ip);
565
}
566

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

    
576
/*
577
 *        Interface Pattern Lists
578
 */
579

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

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

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

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