Statistics
| Branch: | Revision:

iof-bird-daemon / nest / iface.c @ 08c69a77

History | View | Annotate | Download (7.96 KB)

1
/*
2
 *        BIRD -- Management of Interfaces and Neighbor Cache
3
 *
4
 *        (c) 1998 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

    
17
static pool *if_pool;
18

    
19
u32 router_id;
20

    
21
/*
22
 *        Neighbor Cache
23
 *
24
 *        FIXME: Use hashing to get some real speed.
25
 *        FIXME: Cleanup when a protocol goes down.
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_ADMIN_DOWN | IF_IGNORE))
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
  if (!(i->flags & IF_UP))
45
    return 0;
46
  return 1;
47
}
48

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

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

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

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

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

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

    
112
void
113
neigh_dump_all(void)
114
{
115
  neighbor *n;
116

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

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

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

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

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

    
162
/*
163
 *        The Interface List
164
 */
165

    
166
list iface_list;
167

    
168
void
169
if_dump(struct iface *i)
170
{
171
  debug("IF%d: %s", i->index, i->name);
172
  if (i->flags & IF_ADMIN_DOWN)
173
    debug(" ADMIN-DOWN");
174
  if (i->flags & IF_UP)
175
    debug(" UP");
176
  if (i->flags & IF_MULTIACCESS)
177
    debug(" MA");
178
  if (i->flags & IF_UNNUMBERED)
179
    debug(" UNNUM");
180
  if (i->flags & IF_BROADCAST)
181
    debug(" BC");
182
  if (i->flags & IF_MULTICAST)
183
    debug(" MC");
184
  if (i->flags & IF_TUNNEL)
185
    debug(" TUNL");
186
  if (i->flags & IF_LOOPBACK)
187
    debug(" LOOP");
188
  if (i->flags & IF_IGNORE)
189
    debug(" IGN");
190
  debug(" MTU=%d\n", i->mtu);
191
  debug("\t%I, net %I/%-2d bc %I -> %I\n", i->ip, i->prefix, i->pxlen, i->brd, i->opposite);
192
}
193

    
194
void
195
if_dump_all(void)
196
{
197
  struct iface *i;
198

    
199
  debug("Known network interfaces:\n");
200
  WALK_LIST(i, iface_list)
201
    if_dump(i);
202
  debug("\nRouter ID: %08x\n\n", router_id);
203
}
204

    
205
static inline int
206
if_change_too_big_p(struct iface *i, struct iface *j)
207
{
208
  if (!ipa_equal(i->ip, j->ip) ||
209
      !ipa_equal(i->prefix, j->prefix) ||
210
      i->pxlen != j->pxlen ||
211
      !ipa_equal(i->brd, j->brd) ||
212
      !ipa_equal(i->opposite, j->opposite))
213
    return 1;                                /* Changed addresses */
214
  if ((i->flags ^ j->flags) & ~(IF_UP | IF_ADMIN_DOWN | IF_UPDATED))
215
    return 1;
216
  return 0;
217
}
218

    
219
static inline void
220
if_copy(struct iface *to, struct iface *from)
221
{
222
  to->flags = from->flags;
223
  to->mtu = from->mtu;
224
  to->index = from->index;
225
}
226

    
227
static unsigned
228
if_changed(struct iface *i, struct iface *j)
229
{
230
  unsigned f = 0;
231

    
232
  if (i->mtu != j->mtu)
233
    f |= IF_CHANGE_MTU;
234
  if ((i->flags ^ j->flags) & ~IF_UPDATED)
235
    {
236
      f |= IF_CHANGE_FLAGS;
237
      if ((i->flags ^ j->flags) & IF_UP)
238
        if (i->flags & IF_UP)
239
          f |= IF_CHANGE_DOWN;
240
        else
241
          f |= IF_CHANGE_UP;
242
    }
243
  return f;
244
}
245

    
246
static void
247
if_notify_change(unsigned c, struct iface *old, struct iface *new)
248
{
249
  struct proto *p;
250

    
251
  debug("Interface change notification (%x) for %s\n", c, new->name);
252
  if (old)
253
    if_dump(old);
254
  if (new)
255
    if_dump(new);
256

    
257
  if (c & IF_CHANGE_UP)
258
    neigh_if_up(new);
259

    
260
  WALK_LIST(p, proto_list)
261
    if (p->if_notify)
262
      p->if_notify(p, c, old, new);
263

    
264
  if (c & IF_CHANGE_DOWN)
265
    neigh_if_down(old);
266
}
267

    
268
void
269
if_update(struct iface *new)
270
{
271
  struct iface *i;
272
  unsigned c;
273

    
274
  WALK_LIST(i, iface_list)
275
    if (!strcmp(new->name, i->name))
276
      {
277
        if (if_change_too_big_p(i, new)) /* Changed a lot, convert it to down/up */
278
          {
279
            DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
280
            i->flags &= ~IF_UP;
281
            if_notify_change(IF_CHANGE_DOWN | IF_CHANGE_FLAGS, i, NULL);
282
            rem_node(&i->n);
283
            goto newif;
284
          }
285
        c = if_changed(i, new);
286
        if_copy(i, new);                /* Even if c==0 as we might need to update i->index et al. */
287
        i->flags |= IF_UPDATED;
288
        if (c)
289
          if_notify_change(c, i, new);
290
        return;
291
      }
292

    
293
  i = mb_alloc(if_pool, sizeof(struct iface));
294
newif:
295
  memcpy(i, new, sizeof(*i));
296
  i->flags |= IF_UPDATED;
297
  add_tail(&iface_list, &i->n);
298
  if_notify_change(IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0)
299
                   | IF_CHANGE_FLAGS | IF_CHANGE_MTU, NULL, i);
300
}
301

    
302
void
303
if_end_update(void)
304
{
305
  struct iface *i, j;
306

    
307
  WALK_LIST(i, iface_list)
308
    if (i->flags & IF_UPDATED)
309
      i->flags &= ~IF_UPDATED;
310
    else
311
      {
312
        memcpy(&j, i, sizeof(struct iface));
313
        i->flags = (i->flags & ~IF_UP) | IF_ADMIN_DOWN;
314
        if_notify_change(IF_CHANGE_DOWN | IF_CHANGE_FLAGS, &j, i);
315
      }
316
}
317

    
318
void
319
if_feed_baby(struct proto *p)
320
{
321
  struct iface *i;
322

    
323
  if (!p->if_notify)
324
    return;
325
  debug("Announcing interfaces to new protocol %s\n", p->name);
326
  WALK_LIST(i, iface_list)
327
    p->if_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), NULL, i);
328
}
329

    
330
void
331
auto_router_id(void)                        /* FIXME: What if we run IPv6??? */
332
{
333
  struct iface *i, *j;
334

    
335
  if (router_id)
336
    return;
337
  j = NULL;
338
  WALK_LIST(i, iface_list)
339
    if ((i->flags & IF_UP) &&
340
        !(i->flags & (IF_UNNUMBERED | IF_LOOPBACK | IF_IGNORE)) &&
341
        (!j || ipa_to_u32(i->ip) < ipa_to_u32(j->ip)))
342
      j = i;
343
  if (!j)                                /* FIXME: allow configuration or running without RID */
344
    bug("Cannot determine router ID, please configure manually");
345
  router_id = ipa_to_u32(j->ip);
346
  debug("Router ID set to %08x (%s)\n", router_id, j->name);
347
}
348

    
349
void
350
if_init(void)
351
{
352
  if_pool = rp_new(&root_pool, "Interfaces");
353
  init_list(&iface_list);
354
  neigh_slab = sl_new(if_pool, sizeof(neighbor));
355
  init_list(&neigh_list);
356
}
357

    
358
/*
359
 *        Interface Pattern Lists
360
 */
361

    
362
struct iface_patt *
363
iface_patt_match(list *l, struct iface *i)
364
{
365
  struct iface_patt *p;
366

    
367
  WALK_LIST(p, *l)
368
    {
369
      char *t = p->pattern;
370
      int ok = 1;
371
      if (*t == '-')
372
        {
373
          t++;
374
          ok = 0;
375
        }
376
      if (patmatch(t, i->name))
377
        return ok ? p : NULL;
378
    }
379
  return NULL;
380
}
381

    
382
int
383
iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct iface_patt *))
384
{
385
  struct iface_patt *x, *y;
386

    
387
  x = HEAD(*a);
388
  y = HEAD(*b);
389
  while (x->n.next && y->n.next)
390
    {
391
      if (strcmp(x->pattern, y->pattern) || comp && !comp(x, y))
392
        return 0;
393
      x = (void *) x->n.next;
394
      y = (void *) y->n.next;
395
    }
396
  return (!x->n.next && !y->n.next);
397
}