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 |
} |