Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (8.75 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
  if (!(i->flags & IF_UP))
35
    return 0;
36
  if ((i->flags & IF_UNNUMBERED) && ipa_equal(*a, i->opposite))
37
    return 1;
38
  if (!ipa_in_net(*a, i->prefix, i->pxlen))
39
    return 0;
40
  if (ipa_equal(*a, i->prefix) ||        /* Network address */
41
      ipa_equal(*a, i->brd) ||                /* Broadcast */
42
      ipa_equal(*a, i->ip))                /* Our own address */
43
    return -1;
44
  return 1;
45
}
46

    
47
neighbor *
48
neigh_find(struct proto *p, ip_addr *a, unsigned flags)
49
{
50
  neighbor *n;
51
  int class;
52
  struct iface *i, *j;
53

    
54
  WALK_LIST(n, neigh_list)
55
    if (n->proto == p && ipa_equal(*a, n->addr))
56
      return n;
57

    
58
  class = ipa_classify(*a);
59
  if (class < 0)                        /* Invalid address */
60
    return NULL;
61
  if ((class & IADDR_SCOPE_MASK) < SCOPE_SITE ||
62
      !(class & IADDR_HOST))
63
    return NULL;                        /* Bad scope or a somecast */
64

    
65
  j = NULL;
66
  WALK_LIST(i, iface_list)
67
    switch (if_connected(a, i))
68
      {
69
      case -1:
70
        return NULL;
71
      case 1:
72
        if (!j || j->pxlen > i->pxlen)
73
          j = i;
74
        /* Fall-thru */
75
      }
76
  if (!j && !(flags & NEF_STICKY))
77
    return NULL;
78

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

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

    
110
void
111
neigh_dump_all(void)
112
{
113
  neighbor *n;
114

    
115
  debug("Known neighbors:\n");
116
  WALK_LIST(n, neigh_list)
117
    neigh_dump(n);
118
  debug("\n");
119
}
120

    
121
static void
122
neigh_if_up(struct iface *i)
123
{
124
  neighbor *n;
125

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

    
139
static void
140
neigh_if_down(struct iface *i)
141
{
142
  neighbor *n, *m;
143

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

    
160
void
161
neigh_prune(void)
162
{
163
  neighbor *n, *m, **N;
164
  struct iface *i;
165

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

    
184
/*
185
 *        The Interface List
186
 */
187

    
188
list iface_list;
189

    
190
void
191
if_dump(struct iface *i)
192
{
193
  debug("IF%d: %s", i->index, i->name);
194
  if (i->flags & IF_ADMIN_DOWN)
195
    debug(" ADMIN-DOWN");
196
  if (i->flags & IF_UP)
197
    debug(" UP");
198
  else
199
    debug(" DOWN");
200
  if (i->flags & IF_LINK_UP)
201
    debug(" LINK-UP");
202
  if (i->flags & IF_MULTIACCESS)
203
    debug(" MA");
204
  if (i->flags & IF_UNNUMBERED)
205
    debug(" UNNUM");
206
  if (i->flags & IF_BROADCAST)
207
    debug(" BC");
208
  if (i->flags & IF_MULTICAST)
209
    debug(" MC");
210
  if (i->flags & IF_TUNNEL)
211
    debug(" TUNL");
212
  if (i->flags & IF_LOOPBACK)
213
    debug(" LOOP");
214
  if (i->flags & IF_IGNORE)
215
    debug(" IGN");
216
  debug(" MTU=%d\n", i->mtu);
217
  debug("\t%I, net %I/%-2d bc %I -> %I\n", i->ip, i->prefix, i->pxlen, i->brd, i->opposite);
218
}
219

    
220
void
221
if_dump_all(void)
222
{
223
  struct iface *i;
224

    
225
  debug("Known network interfaces:\n");
226
  WALK_LIST(i, iface_list)
227
    if_dump(i);
228
  debug("Router ID: %08x\n", config->router_id);
229
}
230

    
231
static inline int
232
if_change_too_big_p(struct iface *i, struct iface *j)
233
{
234
  if ((i->flags ^ j->flags) & IF_UP)        /* Going up/down is always OK */
235
    return 0;
236
  if (!ipa_equal(i->ip, j->ip) ||        /* Address change isn't */
237
      !ipa_equal(i->prefix, j->prefix) ||
238
      i->pxlen != j->pxlen ||
239
      !ipa_equal(i->brd, j->brd) ||
240
      !ipa_equal(i->opposite, j->opposite))
241
    return 1;
242
  if ((i->flags ^ j->flags) & ~(IF_UP | IF_ADMIN_DOWN | IF_UPDATED | IF_LINK_UP))
243
    return 1;                                /* Interface type change isn't as well */
244
  return 0;
245
}
246

    
247
static inline void
248
if_copy(struct iface *to, struct iface *from)
249
{
250
  to->flags = from->flags;
251
  to->mtu = from->mtu;
252
  to->index = from->index;
253
}
254

    
255
static unsigned
256
if_changed(struct iface *i, struct iface *j)
257
{
258
  unsigned f = 0;
259

    
260
  if (i->mtu != j->mtu)
261
    f |= IF_CHANGE_MTU;
262
  if ((i->flags ^ j->flags) & ~IF_UPDATED)
263
    {
264
      f |= IF_CHANGE_FLAGS;
265
      if ((i->flags ^ j->flags) & IF_UP)
266
        if (i->flags & IF_UP)
267
          f |= IF_CHANGE_DOWN;
268
        else
269
          f |= IF_CHANGE_UP;
270
    }
271
  return f;
272
}
273

    
274
static void
275
if_notify_change(unsigned c, struct iface *old, struct iface *new)
276
{
277
  struct proto *p;
278

    
279
  debug("Interface change notification (%x) for %s\n", c, new->name);
280
  if (old)
281
    if_dump(old);
282
  if (new)
283
    if_dump(new);
284

    
285
  if (c & IF_CHANGE_UP)
286
    neigh_if_up(new);
287

    
288
  WALK_LIST(p, proto_list)
289
    if (p->if_notify)
290
      p->if_notify(p, c, new, old);
291

    
292
  if (c & IF_CHANGE_DOWN)
293
    neigh_if_down(old);
294
}
295

    
296
void
297
if_update(struct iface *new)
298
{
299
  struct iface *i;
300
  unsigned c;
301

    
302
  if ((new->flags & IF_LINK_UP) && !(new->flags & IF_ADMIN_DOWN) && ipa_nonzero(new->ip))
303
    new->flags |= IF_UP;
304
  else
305
    new->flags &= ~IF_UP;
306

    
307
  WALK_LIST(i, iface_list)
308
    if (!strcmp(new->name, i->name))
309
      {
310
        if (if_change_too_big_p(i, new)) /* Changed a lot, convert it to down/up */
311
          {
312
            DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
313
            i->flags &= ~IF_UP;
314
            if_notify_change(IF_CHANGE_DOWN | IF_CHANGE_FLAGS, i, NULL);
315
            rem_node(&i->n);
316
            goto newif;
317
          }
318
        c = if_changed(i, new);
319
        if_copy(i, new);                /* Even if c==0 as we might need to update i->index et al. */
320
        i->flags |= IF_UPDATED;
321
        if (c)
322
          if_notify_change(c, i, new);
323
        return;
324
      }
325

    
326
  i = mb_alloc(if_pool, sizeof(struct iface));
327
newif:
328
  memcpy(i, new, sizeof(*i));
329
  i->flags |= IF_UPDATED;
330
  add_tail(&iface_list, &i->n);
331
  if_notify_change(IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0)
332
                   | IF_CHANGE_FLAGS | IF_CHANGE_MTU, NULL, i);
333
}
334

    
335
void
336
if_end_update(void)
337
{
338
  struct iface *i, j;
339

    
340
  if (!config->router_id)
341
    auto_router_id();
342

    
343
  WALK_LIST(i, iface_list)
344
    if (i->flags & IF_UPDATED)
345
      i->flags &= ~IF_UPDATED;
346
    else
347
      {
348
        memcpy(&j, i, sizeof(struct iface));
349
        i->flags = (i->flags & ~(IF_LINK_UP | IF_UP)) | IF_ADMIN_DOWN;
350
        if (i->flags != j.flags)
351
          if_notify_change(IF_CHANGE_DOWN | IF_CHANGE_FLAGS, &j, i);
352
      }
353
}
354

    
355
void
356
if_feed_baby(struct proto *p)
357
{
358
  struct iface *i;
359

    
360
  if (!p->if_notify)
361
    return;
362
  debug("Announcing interfaces to new protocol %s\n", p->name);
363
  WALK_LIST(i, iface_list)
364
    p->if_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i, NULL);
365
}
366

    
367
static void
368
auto_router_id(void)                        /* FIXME: What if we run IPv6??? */
369
{
370
  struct iface *i, *j;
371

    
372
  j = NULL;
373
  WALK_LIST(i, iface_list)
374
    if ((i->flags & IF_UP) &&
375
        !(i->flags & (IF_UNNUMBERED | IF_IGNORE)) &&
376
        (!j || ipa_to_u32(i->ip) < ipa_to_u32(j->ip)))
377
      j = i;
378
  if (!j)
379
    die("Cannot determine router ID (no suitable network interface found), please configure it manually");
380
  debug("Guessed router ID %I (%s)\n", j->ip, j->name);
381
  config->router_id = ipa_to_u32(j->ip);
382
}
383

    
384
void
385
if_init(void)
386
{
387
  if_pool = rp_new(&root_pool, "Interfaces");
388
  init_list(&iface_list);
389
  neigh_slab = sl_new(if_pool, sizeof(neighbor));
390
  init_list(&neigh_list);
391
}
392

    
393
/*
394
 *        Interface Pattern Lists
395
 */
396

    
397
struct iface_patt *
398
iface_patt_match(list *l, struct iface *i)
399
{
400
  struct iface_patt *p;
401

    
402
  WALK_LIST(p, *l)
403
    {
404
      char *t = p->pattern;
405
      int ok = 1;
406
      if (*t == '-')
407
        {
408
          t++;
409
          ok = 0;
410
        }
411
      if (patmatch(t, i->name))
412
        return ok ? p : NULL;
413
    }
414
  return NULL;
415
}
416

    
417
int
418
iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct iface_patt *))
419
{
420
  struct iface_patt *x, *y;
421

    
422
  x = HEAD(*a);
423
  y = HEAD(*b);
424
  while (x->n.next && y->n.next)
425
    {
426
      if (strcmp(x->pattern, y->pattern) || comp && !comp(x, y))
427
        return 0;
428
      x = (void *) x->n.next;
429
      y = (void *) y->n.next;
430
    }
431
  return (!x->n.next && !y->n.next);
432
}