]>
git.ipfire.org Git - thirdparty/bird.git/blob - nest/iface.c
2 * BIRD -- Management of Interfaces and Neighbor Cache
4 * (c) 1998--1999 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
11 #include "nest/bird.h"
12 #include "nest/iface.h"
13 #include "nest/protocol.h"
15 #include "lib/resource.h"
16 #include "lib/string.h"
17 #include "conf/conf.h"
21 static void auto_router_id(void);
26 * FIXME: Use hashing to get some real speed.
29 static slab
*neigh_slab
;
30 static list neigh_list
;
33 if_connected(ip_addr
*a
, struct iface
*i
) /* -1=error, 1=match, 0=no match */
37 if (!(i
->flags
& IF_UP
))
39 if ((i
->flags
& IF_UNNUMBERED
) && ipa_equal(*a
, i
->addr
->opposite
))
41 WALK_LIST(b
, i
->addrs
)
42 if (ipa_in_net(*a
, b
->prefix
, b
->pxlen
))
44 if (ipa_equal(*a
, b
->prefix
) || /* Network address */
45 ipa_equal(*a
, b
->brd
) || /* Broadcast */
46 ipa_equal(*a
, b
->ip
)) /* Our own address */
54 neigh_find(struct proto
*p
, ip_addr
*a
, unsigned flags
)
60 WALK_LIST(n
, neigh_list
)
61 if (n
->proto
== p
&& ipa_equal(*a
, n
->addr
))
64 class = ipa_classify(*a
);
65 if (class < 0) /* Invalid address */
67 if ((class & IADDR_SCOPE_MASK
) < SCOPE_SITE
||
68 !(class & IADDR_HOST
))
69 return NULL
; /* Bad scope or a somecast */
72 WALK_LIST(i
, iface_list
)
73 switch (if_connected(a
, i
))
78 if (!j
) /* FIXME: Search for _optimal_ iface route? */
82 if (!j
&& !(flags
& NEF_STICKY
))
85 n
= sl_alloc(neigh_slab
);
88 add_tail(&neigh_list
, &n
->n
);
91 n
->sibling
= j
->neigh
;
103 neigh_dump(neighbor
*n
)
105 debug("%p %I ", n
, n
->addr
);
107 debug("%s ", n
->iface
->name
);
110 debug("%s %p", n
->proto
->name
, n
->data
);
111 if (n
->flags
& NEF_STICKY
)
121 debug("Known neighbors:\n");
122 WALK_LIST(n
, neigh_list
)
128 neigh_if_up(struct iface
*i
)
132 WALK_LIST(n
, neigh_list
)
134 if_connected(&n
->addr
, i
) > 0)
137 n
->sibling
= i
->neigh
;
139 DBG("Waking up sticky neighbor %I\n", n
->addr
);
140 if (n
->proto
->neigh_notify
&& n
->proto
->core_state
!= FS_FLUSHING
)
141 n
->proto
->neigh_notify(n
);
146 neigh_if_down(struct iface
*i
)
150 for(m
=i
->neigh
; n
= m
;)
153 DBG("Flushing neighbor %I on %s\n", n
->addr
, i
->name
);
155 if (n
->proto
->neigh_notify
&& n
->proto
->core_state
!= FS_FLUSHING
)
156 n
->proto
->neigh_notify(n
);
157 if (!(n
->flags
& NEF_STICKY
))
160 sl_free(neigh_slab
, n
);
169 neighbor
*n
, *m
, **N
;
172 DBG("Pruning neighbors\n");
173 WALK_LIST(i
, iface_list
)
178 if (n
->proto
->core_state
== FS_FLUSHING
)
182 sl_free(neigh_slab
, n
);
197 ifa_dump(struct ifa
*a
)
199 debug("\t%I, net %I/%-2d bc %I -> %I%s%s\n", a
->ip
, a
->prefix
, a
->pxlen
, a
->brd
, a
->opposite
,
200 (a
->flags
& IF_UP
) ? "" : " DOWN",
201 (a
->flags
& IA_PRIMARY
) ? "" : " SEC");
205 if_dump(struct iface
*i
)
209 debug("IF%d: %s", i
->index
, i
->name
);
210 if (i
->flags
& IF_ADMIN_DOWN
)
211 debug(" ADMIN-DOWN");
212 if (i
->flags
& IF_UP
)
216 if (i
->flags
& IF_LINK_UP
)
218 if (i
->flags
& IF_MULTIACCESS
)
220 if (i
->flags
& IF_UNNUMBERED
)
222 if (i
->flags
& IF_BROADCAST
)
224 if (i
->flags
& IF_MULTICAST
)
226 if (i
->flags
& IF_TUNNEL
)
228 if (i
->flags
& IF_LOOPBACK
)
230 if (i
->flags
& IF_IGNORE
)
232 if (i
->flags
& IF_TMP_DOWN
)
234 debug(" MTU=%d\n", i
->mtu
);
235 WALK_LIST(a
, i
->addrs
)
238 ASSERT((a
!= i
->addr
) == !(a
->flags
& IA_PRIMARY
));
247 debug("Known network interfaces:\n");
248 WALK_LIST(i
, iface_list
)
250 debug("Router ID: %08x\n", config
->router_id
);
253 static inline unsigned
254 if_what_changed(struct iface
*i
, struct iface
*j
)
258 if (((i
->flags
^ j
->flags
) & ~(IF_UP
| IF_ADMIN_DOWN
| IF_UPDATED
| IF_LINK_UP
| IF_TMP_DOWN
| IF_JUST_CREATED
))
259 || i
->index
!= j
->index
)
260 return IF_CHANGE_TOO_MUCH
;
262 if ((i
->flags
^ j
->flags
) & IF_UP
)
263 c
|= (i
->flags
& IF_UP
) ? IF_CHANGE_DOWN
: IF_CHANGE_UP
;
264 if (i
->mtu
!= j
->mtu
)
270 if_copy(struct iface
*to
, struct iface
*from
)
272 to
->flags
= from
->flags
| (to
->flags
& IF_TMP_DOWN
);
277 ifa_notify_change(unsigned c
, struct ifa
*a
)
281 debug("IFA change notification (%x) for %s:%I\n", c
, a
->iface
->name
, a
->ip
);
282 WALK_LIST(p
, proto_list
)
284 p
->ifa_notify(p
, c
, a
);
288 if_notify_change(unsigned c
, struct iface
*i
)
293 if (i
->flags
& IF_JUST_CREATED
)
295 i
->flags
&= ~IF_JUST_CREATED
;
296 c
|= IF_CHANGE_CREATE
| IF_CHANGE_MTU
;
299 debug("Interface change notification (%x) for %s\n", c
, i
->name
);
302 if (c
& IF_CHANGE_UP
)
304 if (c
& IF_CHANGE_DOWN
)
305 WALK_LIST(a
, i
->addrs
)
307 a
->flags
= (i
->flags
& ~IA_FLAGS
) | (a
->flags
& IA_FLAGS
);
308 ifa_notify_change(IF_CHANGE_DOWN
, a
);
311 WALK_LIST(p
, proto_list
)
313 p
->if_notify(p
, c
, i
);
315 if (c
& IF_CHANGE_UP
)
316 WALK_LIST(a
, i
->addrs
)
318 a
->flags
= (i
->flags
& ~IA_FLAGS
) | (a
->flags
& IA_FLAGS
);
319 ifa_notify_change(IF_CHANGE_UP
, a
);
321 if (c
& IF_CHANGE_DOWN
)
326 if_recalc_flags(struct iface
*i
, unsigned flags
)
328 if ((flags
& (IF_ADMIN_DOWN
| IF_TMP_DOWN
)) ||
329 !(flags
& IF_LINK_UP
) ||
338 if_change_flags(struct iface
*i
, unsigned flags
)
340 unsigned of
= i
->flags
;
342 i
->flags
= if_recalc_flags(i
, flags
);
343 if ((i
->flags
^ of
) & IF_UP
)
344 if_notify_change((i
->flags
& IF_UP
) ? IF_CHANGE_UP
: IF_CHANGE_DOWN
, i
);
348 if_update(struct iface
*new)
354 WALK_LIST(i
, iface_list
)
355 if (!strcmp(new->name
, i
->name
))
358 new->flags
= if_recalc_flags(new, new->flags
);
359 c
= if_what_changed(i
, new);
360 if (c
& IF_CHANGE_TOO_MUCH
) /* Changed a lot, convert it to down/up */
362 DBG("Interface %s changed too much -- forcing down/up transition\n", i
->name
);
363 if_change_flags(i
, i
->flags
| IF_TMP_DOWN
);
366 memcpy(&new->addrs
, &i
->addrs
, sizeof(i
->addrs
));
367 memcpy(i
, new, sizeof(*i
));
373 if_notify_change(c
, i
);
375 i
->flags
|= IF_UPDATED
;
378 i
= mb_alloc(if_pool
, sizeof(struct iface
));
379 memcpy(i
, new, sizeof(*i
));
380 init_list(&i
->addrs
);
382 i
->flags
|= IF_UPDATED
| IF_TMP_DOWN
; /* Tmp down as we don't have addresses yet */
383 add_tail(&iface_list
, &i
->n
);
388 if_start_update(void)
393 WALK_LIST(i
, iface_list
)
395 i
->flags
&= ~IF_UPDATED
;
396 WALK_LIST(a
, i
->addrs
)
397 a
->flags
&= ~IF_UPDATED
;
402 if_end_partial_update(struct iface
*i
)
404 if (i
->flags
& IF_TMP_DOWN
)
405 if_change_flags(i
, i
->flags
& ~IF_TMP_DOWN
);
414 if (!config
->router_id
)
417 WALK_LIST(i
, iface_list
)
419 if (!(i
->flags
& IF_UPDATED
))
420 if_change_flags(i
, (i
->flags
& ~IF_LINK_UP
) | IF_ADMIN_DOWN
);
423 WALK_LIST_DELSAFE(a
, b
, i
->addrs
)
424 if (!(a
->flags
& IF_UPDATED
))
426 if_end_partial_update(i
);
432 if_feed_baby(struct proto
*p
)
437 if (!p
->if_notify
&& !p
->ifa_notify
)
439 debug("Announcing interfaces to new protocol %s\n", p
->name
);
440 WALK_LIST(i
, iface_list
)
443 p
->if_notify(p
, IF_CHANGE_CREATE
| ((i
->flags
& IF_UP
) ? IF_CHANGE_UP
: 0), i
);
444 if (p
->ifa_notify
&& (i
->flags
& IF_UP
))
445 WALK_LIST(a
, i
->addrs
)
446 p
->ifa_notify(p
, IF_CHANGE_CREATE
| IF_CHANGE_UP
, a
);
451 if_find_by_index(unsigned idx
)
455 WALK_LIST(i
, iface_list
)
462 if_find_by_name(char *name
)
466 WALK_LIST(i
, iface_list
)
467 if (!strcmp(i
->name
, name
))
473 ifa_recalc_primary(struct iface
*i
)
475 struct ifa
*a
, *b
= NULL
;
478 WALK_LIST(a
, i
->addrs
)
480 if (!(a
->flags
& IA_SECONDARY
) && (!b
|| a
->scope
> b
->scope
))
482 a
->flags
&= ~IA_PRIMARY
;
484 res
= (b
!= i
->addr
);
488 b
->flags
|= IA_PRIMARY
;
490 add_head(&i
->addrs
, &b
->n
);
496 ifa_update(struct ifa
*a
)
498 struct iface
*i
= a
->iface
;
501 WALK_LIST(b
, i
->addrs
)
502 if (ipa_equal(b
->ip
, a
->ip
))
504 if (ipa_equal(b
->prefix
, a
->prefix
) &&
505 b
->pxlen
== a
->pxlen
&&
506 ipa_equal(b
->brd
, a
->brd
) &&
507 ipa_equal(b
->opposite
, a
->opposite
) &&
508 b
->scope
== a
->scope
)
510 b
->flags
|= IF_UPDATED
;
516 b
= mb_alloc(if_pool
, sizeof(struct ifa
));
517 memcpy(b
, a
, sizeof(struct ifa
));
518 add_tail(&i
->addrs
, &b
->n
);
519 b
->flags
= (i
->flags
& ~IA_FLAGS
) | (a
->flags
& IA_FLAGS
);
520 if ((!i
->addr
|| i
->addr
->scope
< b
->scope
) && ifa_recalc_primary(i
))
521 if_change_flags(i
, i
->flags
| IF_TMP_DOWN
);
522 if (b
->flags
& IF_UP
)
523 ifa_notify_change(IF_CHANGE_CREATE
| IF_CHANGE_UP
, b
);
528 ifa_delete(struct ifa
*a
)
530 struct iface
*i
= a
->iface
;
533 WALK_LIST(b
, i
->addrs
)
534 if (ipa_equal(b
->ip
, a
->ip
))
537 if (b
->flags
& IF_UP
)
540 ifa_notify_change(IF_CHANGE_DOWN
, b
);
542 if (b
->flags
& IA_PRIMARY
)
544 if_change_flags(i
, i
->flags
| IF_TMP_DOWN
);
545 ifa_recalc_primary(i
);
559 WALK_LIST(i
, iface_list
)
560 if ((i
->flags
& IF_LINK_UP
) &&
561 !(i
->flags
& (IF_UNNUMBERED
| IF_IGNORE
| IF_ADMIN_DOWN
)) &&
563 (!j
|| ipa_to_u32(i
->addr
->ip
) < ipa_to_u32(j
->addr
->ip
)))
566 die("Cannot determine router ID (no suitable network interface found), please configure it manually");
567 debug("Guessed router ID %I (%s)\n", j
->addr
->ip
, j
->name
);
568 config
->router_id
= ipa_to_u32(j
->addr
->ip
);
575 if_pool
= rp_new(&root_pool
, "Interfaces");
576 init_list(&iface_list
);
577 neigh_slab
= sl_new(if_pool
, sizeof(neighbor
));
578 init_list(&neigh_list
);
582 * Interface Pattern Lists
586 iface_patt_match(list
*l
, struct iface
*i
)
588 struct iface_patt
*p
;
592 char *t
= p
->pattern
;
601 if (!patmatch(t
, i
->name
))
604 if (!i
->addr
|| !ipa_in_net(i
->addr
->ip
, p
->prefix
, p
->pxlen
))
606 return ok
? p
: NULL
;
612 iface_patts_equal(list
*a
, list
*b
, int (*comp
)(struct iface_patt
*, struct iface_patt
*))
614 struct iface_patt
*x
, *y
;
618 while (x
->n
.next
&& y
->n
.next
)
620 if (strcmp(x
->pattern
, y
->pattern
) ||
621 !ipa_equal(x
->prefix
, y
->prefix
) ||
622 x
->pxlen
!= y
->pxlen
||
625 x
= (void *) x
->n
.next
;
626 y
= (void *) y
->n
.next
;
628 return (!x
->n
.next
&& !y
->n
.next
);
636 if_show_addr(struct ifa
*a
)
638 byte broad
[STD_ADDRESS_P_LENGTH
+ 16];
639 byte opp
[STD_ADDRESS_P_LENGTH
+ 16];
641 if (ipa_nonzero(a
->brd
))
642 bsprintf(broad
, ", broadcast %I", a
->brd
);
645 if (ipa_nonzero(a
->opposite
))
646 bsprintf(opp
, ", opposite %I", a
->opposite
);
649 cli_msg(-1003, "\t%I/%d (%s%s%s, scope %s)",
651 (a
->flags
& IA_PRIMARY
) ? "Primary" : (a
->flags
& IA_SECONDARY
) ? "Secondary" : "???",
653 ip_scope_text(a
->scope
));
663 WALK_LIST(i
, iface_list
)
665 cli_msg(-1001, "%s %s (index=%d)", i
->name
, (i
->flags
& IF_UP
) ? "up" : "DOWN", i
->index
);
666 if (i
->flags
& IF_UNNUMBERED
)
668 else if (!(i
->flags
& IF_MULTIACCESS
))
671 type
= "MultiAccess";
672 cli_msg(-1004, "\t%s%s%s Admin%s Link%s%s%s MTU=%d",
674 (i
->flags
& IF_BROADCAST
) ? " Broadcast" : "",
675 (i
->flags
& IF_MULTICAST
) ? " Multicast" : "",
676 (i
->flags
& IF_ADMIN_DOWN
) ? "Down" : "Up",
677 (i
->flags
& IF_LINK_UP
) ? "Up" : "Down",
678 (i
->flags
& IF_LOOPBACK
) ? " Loopback" : "",
679 (i
->flags
& IF_IGNORE
) ? " Ignored" : "",
682 if_show_addr(i
->addr
);
683 WALK_LIST(a
, i
->addrs
)
691 if_show_summary(void)
694 byte addr
[STD_ADDRESS_P_LENGTH
+ 16];
696 cli_msg(-2005, "interface state address");
697 WALK_LIST(i
, iface_list
)
700 bsprintf(addr
, "%I/%d", i
->addr
->ip
, i
->addr
->pxlen
);
703 cli_msg(-1005, "%-9s %-5s %s", i
->name
, (i
->flags
& IF_UP
) ? "up" : "DOWN", addr
);