]>
git.ipfire.org Git - thirdparty/bird.git/blob - nest/iface.c
2 * BIRD -- Management of Interfaces and Neighbor Cache
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
12 * The interface module keeps track of all network interfaces in the
13 * system and their addresses.
15 * Each interface is represented by an &iface structure which carries
16 * interface capability flags (%IF_MULTIACCESS, %IF_BROADCAST etc.),
17 * MTU, interface name and index and finally a linked list of network
18 * prefixes assigned to the interface, each one represented by
21 * The interface module keeps a `soft-up' state for each &iface which
22 * is a conjunction of link being up, the interface being of a `sane'
23 * type and at least one IP address assigned to it.
28 #include "nest/bird.h"
29 #include "nest/iface.h"
30 #include "nest/protocol.h"
32 #include "lib/resource.h"
33 #include "lib/string.h"
34 #include "conf/conf.h"
41 * ifa_dump - dump interface address
42 * @a: interface address descriptor
44 * This function dumps contents of an &ifa to the debug output.
47 ifa_dump(struct ifa
*a
)
49 debug("\t%I, net %I/%-2d bc %I -> %I%s%s%s\n", a
->ip
, a
->prefix
, a
->pxlen
, a
->brd
, a
->opposite
,
50 (a
->flags
& IF_UP
) ? "" : " DOWN",
51 (a
->flags
& IA_PRIMARY
) ? "" : " SEC",
52 (a
->flags
& IA_PEER
) ? "PEER" : "");
56 * if_dump - dump interface
57 * @i: interface to dump
59 * This function dumps all information associated with a given
60 * network interface to the debug output.
63 if_dump(struct iface
*i
)
67 debug("IF%d: %s", i
->index
, i
->name
);
68 if (i
->flags
& IF_SHUTDOWN
)
74 if (i
->flags
& IF_ADMIN_UP
)
76 if (i
->flags
& IF_MULTIACCESS
)
78 if (i
->flags
& IF_BROADCAST
)
80 if (i
->flags
& IF_MULTICAST
)
82 if (i
->flags
& IF_LOOPBACK
)
84 if (i
->flags
& IF_IGNORE
)
86 if (i
->flags
& IF_TMP_DOWN
)
88 debug(" MTU=%d\n", i
->mtu
);
89 WALK_LIST(a
, i
->addrs
)
92 ASSERT((a
!= i
->addr
) == !(a
->flags
& IA_PRIMARY
));
97 * if_dump_all - dump all interfaces
99 * This function dumps information about all known network
100 * interfaces to the debug output.
107 debug("Known network interfaces:\n");
108 WALK_LIST(i
, iface_list
)
110 debug("Router ID: %08x\n", config
->router_id
);
113 static inline unsigned
114 if_what_changed(struct iface
*i
, struct iface
*j
)
118 if (((i
->flags
^ j
->flags
) & ~(IF_UP
| IF_SHUTDOWN
| IF_UPDATED
| IF_ADMIN_UP
| IF_LINK_UP
| IF_TMP_DOWN
| IF_JUST_CREATED
))
119 || (i
->index
!= j
->index
) || (i
->master
!= j
->master
))
120 return IF_CHANGE_TOO_MUCH
;
122 if ((i
->flags
^ j
->flags
) & IF_UP
)
123 c
|= (i
->flags
& IF_UP
) ? IF_CHANGE_DOWN
: IF_CHANGE_UP
;
124 if ((i
->flags
^ j
->flags
) & IF_LINK_UP
)
126 if (i
->mtu
!= j
->mtu
)
132 if_copy(struct iface
*to
, struct iface
*from
)
134 to
->flags
= from
->flags
| (to
->flags
& IF_TMP_DOWN
);
136 to
->master_index
= from
->master_index
;
137 to
->master
= from
->master
;
141 ifa_send_notify(struct proto
*p
, unsigned c
, struct ifa
*a
)
143 if (p
->ifa_notify
&& (!p
->vrf
|| p
->vrf
== a
->iface
->master
))
145 if (p
->debug
& D_IFACES
)
146 log(L_TRACE
"%s <%s address %I/%d on interface %s %s",
147 p
->name
, (a
->flags
& IA_PRIMARY
) ? " primary" : "",
148 a
->prefix
, a
->pxlen
, a
->iface
->name
,
149 (c
& IF_CHANGE_UP
) ? "added" : "removed");
150 p
->ifa_notify(p
, c
, a
);
155 ifa_notify_change_(unsigned c
, struct ifa
*a
)
159 DBG("IFA change notification (%x) for %s:%I\n", c
, a
->iface
->name
, a
->ip
);
161 WALK_LIST(p
, active_proto_list
)
162 ifa_send_notify(p
, c
, a
);
166 ifa_notify_change(unsigned c
, struct ifa
*a
)
168 if (c
& IF_CHANGE_DOWN
)
171 ifa_notify_change_(c
, a
);
173 if (c
& IF_CHANGE_UP
)
178 if_send_notify(struct proto
*p
, unsigned c
, struct iface
*i
)
180 if (p
->if_notify
&& (!p
->vrf
|| p
->vrf
== i
->master
))
182 if (p
->debug
& D_IFACES
)
183 log(L_TRACE
"%s < interface %s %s", p
->name
, i
->name
,
184 (c
& IF_CHANGE_UP
) ? "goes up" :
185 (c
& IF_CHANGE_DOWN
) ? "goes down" :
186 (c
& IF_CHANGE_MTU
) ? "changes MTU" :
187 (c
& IF_CHANGE_LINK
) ? "changes link" :
188 (c
& IF_CHANGE_CREATE
) ? "created" :
189 "sends unknown event");
190 p
->if_notify(p
, c
, i
);
195 if_notify_change(unsigned c
, struct iface
*i
)
200 if (i
->flags
& IF_JUST_CREATED
)
202 i
->flags
&= ~IF_JUST_CREATED
;
203 c
|= IF_CHANGE_CREATE
| IF_CHANGE_MTU
;
206 DBG("Interface change notification (%x) for %s\n", c
, i
->name
);
211 if (c
& IF_CHANGE_DOWN
)
214 if (c
& IF_CHANGE_DOWN
)
215 WALK_LIST(a
, i
->addrs
)
217 a
->flags
= (i
->flags
& ~IA_FLAGS
) | (a
->flags
& IA_FLAGS
);
218 ifa_notify_change_(IF_CHANGE_DOWN
, a
);
221 WALK_LIST(p
, active_proto_list
)
222 if_send_notify(p
, c
, i
);
224 if (c
& IF_CHANGE_UP
)
225 WALK_LIST(a
, i
->addrs
)
227 a
->flags
= (i
->flags
& ~IA_FLAGS
) | (a
->flags
& IA_FLAGS
);
228 ifa_notify_change_(IF_CHANGE_UP
, a
);
231 if (c
& IF_CHANGE_UP
)
234 if ((c
& (IF_CHANGE_UP
| IF_CHANGE_DOWN
| IF_CHANGE_LINK
)) == IF_CHANGE_LINK
)
239 if_recalc_flags(struct iface
*i
, unsigned flags
)
241 if ((flags
& (IF_SHUTDOWN
| IF_TMP_DOWN
)) ||
242 !(flags
& IF_ADMIN_UP
) ||
244 (i
->master_index
&& !i
->master
))
252 if_change_flags(struct iface
*i
, unsigned flags
)
254 unsigned of
= i
->flags
;
256 i
->flags
= if_recalc_flags(i
, flags
);
257 if ((i
->flags
^ of
) & IF_UP
)
258 if_notify_change((i
->flags
& IF_UP
) ? IF_CHANGE_UP
: IF_CHANGE_DOWN
, i
);
262 * if_delete - remove interface
265 * This function is called by the low-level platform dependent code
266 * whenever it notices an interface disappears. It is just a shorthand
271 if_delete(struct iface
*old
)
274 strncpy(f
.name
, old
->name
, sizeof(f
.name
)-1);
275 f
.flags
= IF_SHUTDOWN
;
280 * if_update - update interface status
281 * @new: new interface status
283 * if_update() is called by the low-level platform dependent code
284 * whenever it notices an interface change.
286 * There exist two types of interface updates -- synchronous and asynchronous
287 * ones. In the synchronous case, the low-level code calls if_start_update(),
288 * scans all interfaces reported by the OS, uses if_update() and ifa_update()
289 * to pass them to the core and then it finishes the update sequence by
290 * calling if_end_update(). When working asynchronously, the sysdep code
291 * calls if_update() and ifa_update() whenever it notices a change.
293 * if_update() will automatically notify all other modules about the change.
296 if_update(struct iface
*new)
301 WALK_LIST(i
, iface_list
)
302 if (!strcmp(new->name
, i
->name
))
305 new->flags
= if_recalc_flags(new, new->flags
);
306 c
= if_what_changed(i
, new);
307 if (c
& IF_CHANGE_TOO_MUCH
) /* Changed a lot, convert it to down/up */
309 DBG("Interface %s changed too much -- forcing down/up transition\n", i
->name
);
310 if_change_flags(i
, i
->flags
| IF_TMP_DOWN
);
313 memcpy(&new->addrs
, &i
->addrs
, sizeof(i
->addrs
));
314 memcpy(i
, new, sizeof(*i
));
315 i
->flags
&= ~IF_UP
; /* IF_TMP_DOWN will be added later */
321 if_notify_change(c
, i
);
323 i
->flags
|= IF_UPDATED
;
326 i
= mb_alloc(if_pool
, sizeof(struct iface
));
327 memcpy(i
, new, sizeof(*i
));
328 init_list(&i
->addrs
);
330 init_list(&i
->neighbors
);
331 i
->flags
|= IF_UPDATED
| IF_TMP_DOWN
; /* Tmp down as we don't have addresses yet */
332 add_tail(&iface_list
, &i
->n
);
337 if_start_update(void)
342 WALK_LIST(i
, iface_list
)
344 i
->flags
&= ~IF_UPDATED
;
345 WALK_LIST(a
, i
->addrs
)
346 a
->flags
&= ~IF_UPDATED
;
351 if_end_partial_update(struct iface
*i
)
353 if (i
->flags
& IF_TMP_DOWN
)
354 if_change_flags(i
, i
->flags
& ~IF_TMP_DOWN
);
363 WALK_LIST(i
, iface_list
)
365 if (!(i
->flags
& IF_UPDATED
))
366 if_change_flags(i
, (i
->flags
& ~IF_ADMIN_UP
) | IF_SHUTDOWN
);
369 WALK_LIST_DELSAFE(a
, b
, i
->addrs
)
370 if (!(a
->flags
& IF_UPDATED
))
372 if_end_partial_update(i
);
378 if_flush_ifaces(struct proto
*p
)
380 if (p
->debug
& D_EVENTS
)
381 log(L_TRACE
"%s: Flushing interfaces", p
->name
);
387 * if_feed_baby - advertise interfaces to a new protocol
388 * @p: protocol to feed
390 * When a new protocol starts, this function sends it a series
391 * of notifications about all existing interfaces.
394 if_feed_baby(struct proto
*p
)
399 if (!p
->if_notify
&& !p
->ifa_notify
) /* shortcut */
401 DBG("Announcing interfaces to new protocol %s\n", p
->name
);
402 WALK_LIST(i
, iface_list
)
404 if_send_notify(p
, IF_CHANGE_CREATE
| ((i
->flags
& IF_UP
) ? IF_CHANGE_UP
: 0), i
);
405 if (i
->flags
& IF_UP
)
406 WALK_LIST(a
, i
->addrs
)
407 ifa_send_notify(p
, IF_CHANGE_CREATE
| IF_CHANGE_UP
, a
);
412 * if_find_by_index - find interface by ifindex
415 * This function finds an &iface structure corresponding to an interface
416 * of the given index @idx. Returns a pointer to the structure or %NULL
417 * if no such structure exists.
420 if_find_by_index(unsigned idx
)
424 WALK_LIST(i
, iface_list
)
425 if (i
->index
== idx
&& !(i
->flags
& IF_SHUTDOWN
))
431 * if_find_by_name - find interface by name
432 * @name: interface name
434 * This function finds an &iface structure corresponding to an interface
435 * of the given name @name. Returns a pointer to the structure or %NULL
436 * if no such structure exists.
439 if_find_by_name(char *name
)
443 WALK_LIST(i
, iface_list
)
444 if (!strcmp(i
->name
, name
) && !(i
->flags
& IF_SHUTDOWN
))
450 if_get_by_name(char *name
)
454 WALK_LIST(i
, iface_list
)
455 if (!strcmp(i
->name
, name
))
458 /* No active iface, create a dummy */
459 i
= mb_allocz(if_pool
, sizeof(struct iface
));
460 strncpy(i
->name
, name
, sizeof(i
->name
)-1);
461 i
->flags
= IF_SHUTDOWN
;
462 init_list(&i
->addrs
);
463 init_list(&i
->neighbors
);
464 add_tail(&iface_list
, &i
->n
);
468 struct ifa
*kif_choose_primary(struct iface
*i
);
471 ifa_recalc_primary(struct iface
*i
)
477 struct ifa
*ll
= NULL
;
479 WALK_LIST(a
, i
->addrs
)
480 if (ipa_is_link_local(a
->ip
) && (!ll
|| (a
== i
->llv6
)))
487 a
= kif_choose_primary(i
);
493 i
->addr
->flags
&= ~IA_PRIMARY
;
497 a
->flags
|= IA_PRIMARY
;
499 add_head(&i
->addrs
, &a
->n
);
507 ifa_recalc_all_primary_addresses(void)
511 WALK_LIST(i
, iface_list
)
513 if (ifa_recalc_primary(i
))
514 if_change_flags(i
, i
->flags
| IF_TMP_DOWN
);
519 ifa_same(struct ifa
*a
, struct ifa
*b
)
521 return ipa_equal(a
->ip
, b
->ip
) && ipa_equal(a
->prefix
, b
->prefix
) &&
522 a
->pxlen
== b
->pxlen
;
527 * ifa_update - update interface address
528 * @a: new interface address
530 * This function adds address information to a network
531 * interface. It's called by the platform dependent code during
532 * the interface update process described under if_update().
535 ifa_update(struct ifa
*a
)
537 struct iface
*i
= a
->iface
;
540 WALK_LIST(b
, i
->addrs
)
543 if (ipa_equal(b
->brd
, a
->brd
) &&
544 ipa_equal(b
->opposite
, a
->opposite
) &&
545 b
->scope
== a
->scope
&&
546 !((b
->flags
^ a
->flags
) & IA_PEER
))
548 b
->flags
|= IF_UPDATED
;
556 if ((i
->flags
& IF_BROADCAST
) && !ipa_nonzero(a
->brd
))
557 log(L_ERR
"Missing broadcast address for interface %s", i
->name
);
560 b
= mb_alloc(if_pool
, sizeof(struct ifa
));
561 memcpy(b
, a
, sizeof(struct ifa
));
562 add_tail(&i
->addrs
, &b
->n
);
563 b
->flags
= (i
->flags
& ~IA_FLAGS
) | (a
->flags
& IA_FLAGS
);
564 if (ifa_recalc_primary(i
))
565 if_change_flags(i
, i
->flags
| IF_TMP_DOWN
);
566 if (b
->flags
& IF_UP
)
567 ifa_notify_change(IF_CHANGE_CREATE
| IF_CHANGE_UP
, b
);
572 * ifa_delete - remove interface address
573 * @a: interface address
575 * This function removes address information from a network
576 * interface. It's called by the platform dependent code during
577 * the interface update process described under if_update().
580 ifa_delete(struct ifa
*a
)
582 struct iface
*i
= a
->iface
;
585 WALK_LIST(b
, i
->addrs
)
589 if (b
->flags
& IF_UP
)
592 ifa_notify_change(IF_CHANGE_DOWN
, b
);
594 if ((b
->flags
& IA_PRIMARY
) || (b
== ifa_llv6(i
)))
596 if_change_flags(i
, i
->flags
| IF_TMP_DOWN
);
597 ifa_recalc_primary(i
);
605 if_choose_router_id(struct iface_patt
*mask UNUSED6
, u32 old_id UNUSED6
)
612 WALK_LIST(i
, iface_list
)
614 if (!(i
->flags
& IF_ADMIN_UP
) ||
615 (i
->flags
& IF_SHUTDOWN
))
618 WALK_LIST(a
, i
->addrs
)
620 if (a
->flags
& IA_SECONDARY
)
623 if (a
->scope
<= SCOPE_LINK
)
626 /* Check pattern if specified */
627 if (mask
&& !iface_patt_match(mask
, i
, a
))
630 /* No pattern or pattern matched */
631 if (!b
|| ipa_to_u32(a
->ip
) < ipa_to_u32(b
->ip
))
639 u32 id
= ipa_to_u32(b
->ip
);
641 log(L_INFO
"Chosen router ID %R according to interface %s", id
, b
->iface
->name
);
651 * if_init - initialize interface module
653 * This function is called during BIRD startup to initialize
654 * all data structures of the interface module.
659 if_pool
= rp_new(&root_pool
, "Interfaces");
660 init_list(&iface_list
);
665 * Interface Pattern Lists
669 iface_patt_match(struct iface_patt
*ifp
, struct iface
*i
, struct ifa
*a
)
671 struct iface_patt_node
*p
;
673 WALK_LIST(p
, ifp
->ipn_list
)
675 char *t
= p
->pattern
;
676 int pos
= p
->positive
;
686 if (!patmatch(t
, i
->name
))
696 if (ipa_in_net(a
->ip
, p
->prefix
, p
->pxlen
))
699 if ((a
->flags
& IA_PEER
) &&
700 ipa_in_net(a
->opposite
, p
->prefix
, p
->pxlen
))
710 iface_patt_find(list
*l
, struct iface
*i
, struct ifa
*a
)
712 struct iface_patt
*p
;
715 if (iface_patt_match(p
, i
, a
))
722 iface_plists_equal(struct iface_patt
*pa
, struct iface_patt
*pb
)
724 struct iface_patt_node
*x
, *y
;
726 x
= HEAD(pa
->ipn_list
);
727 y
= HEAD(pb
->ipn_list
);
728 while (x
->n
.next
&& y
->n
.next
)
730 if ((x
->positive
!= y
->positive
) ||
731 (!x
->pattern
&& y
->pattern
) || /* This nasty lines where written by me... :-( Feela */
732 (!y
->pattern
&& x
->pattern
) ||
733 ((x
->pattern
!= y
->pattern
) && strcmp(x
->pattern
, y
->pattern
)) ||
734 !ipa_equal(x
->prefix
, y
->prefix
) ||
735 (x
->pxlen
!= y
->pxlen
))
737 x
= (void *) x
->n
.next
;
738 y
= (void *) y
->n
.next
;
740 return (!x
->n
.next
&& !y
->n
.next
);
744 iface_patts_equal(list
*a
, list
*b
, int (*comp
)(struct iface_patt
*, struct iface_patt
*))
746 struct iface_patt
*x
, *y
;
750 while (x
->n
.next
&& y
->n
.next
)
752 if (!iface_plists_equal(x
, y
) ||
753 (comp
&& !comp(x
, y
)))
755 x
= (void *) x
->n
.next
;
756 y
= (void *) y
->n
.next
;
758 return (!x
->n
.next
&& !y
->n
.next
);
766 if_show_addr(struct ifa
*a
)
768 byte opp
[STD_ADDRESS_P_LENGTH
+ 16];
770 if (ipa_nonzero(a
->opposite
))
771 bsprintf(opp
, ", opposite %I", a
->opposite
);
774 cli_msg(-1003, "\t%I/%d (%s%s, scope %s)",
776 (a
->flags
& IA_PRIMARY
) ? "Primary" : (a
->flags
& IA_SECONDARY
) ? "Secondary" : "Unselected",
777 opp
, ip_scope_text(a
->scope
));
787 WALK_LIST(i
, iface_list
)
789 if (i
->flags
& IF_SHUTDOWN
)
792 char mbuf
[16 + sizeof(i
->name
)] = {};
794 bsprintf(mbuf
, " master=%s", i
->master
->name
);
795 else if (i
->master_index
)
796 bsprintf(mbuf
, " master=#%u", i
->master_index
);
798 cli_msg(-1001, "%s %s (index=%d%s)", i
->name
, (i
->flags
& IF_UP
) ? "up" : "DOWN", i
->index
, mbuf
);
799 if (!(i
->flags
& IF_MULTIACCESS
))
802 type
= "MultiAccess";
803 cli_msg(-1004, "\t%s%s%s Admin%s Link%s%s%s MTU=%d",
805 (i
->flags
& IF_BROADCAST
) ? " Broadcast" : "",
806 (i
->flags
& IF_MULTICAST
) ? " Multicast" : "",
807 (i
->flags
& IF_ADMIN_UP
) ? "Up" : "Down",
808 (i
->flags
& IF_LINK_UP
) ? "Up" : "Down",
809 (i
->flags
& IF_LOOPBACK
) ? " Loopback" : "",
810 (i
->flags
& IF_IGNORE
) ? " Ignored" : "",
813 if_show_addr(i
->addr
);
814 WALK_LIST(a
, i
->addrs
)
822 if_show_summary(void)
825 byte addr
[STD_ADDRESS_P_LENGTH
+ 16];
827 cli_msg(-2005, "interface state address");
828 WALK_LIST(i
, iface_list
)
830 if (i
->flags
& IF_SHUTDOWN
)
834 bsprintf(addr
, "%I/%d", i
->addr
->ip
, i
->addr
->pxlen
);
837 cli_msg(-1005, "%-9s %-5s %s", i
->name
, (i
->flags
& IF_UP
) ? "up" : "DOWN", addr
);