]>
git.ipfire.org Git - thirdparty/bird.git/blob - nest/iface.c
c1966ac65f59ad4f28822c62a437cfd3ac3b54e4
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"
35 #include "sysdep/unix/krt.h"
41 static void if_recalc_preferred(struct iface
*i
);
44 * ifa_dump - dump interface address
45 * @a: interface address descriptor
47 * This function dumps contents of an &ifa to the debug output.
50 ifa_dump(struct ifa
*a
)
52 debug("\t%I, net %N bc %I -> %I%s%s%s%s\n", a
->ip
, &a
->prefix
, a
->brd
, a
->opposite
,
53 (a
->flags
& IA_PRIMARY
) ? " PRIMARY" : "",
54 (a
->flags
& IA_SECONDARY
) ? " SEC" : "",
55 (a
->flags
& IA_HOST
) ? " HOST" : "",
56 (a
->flags
& IA_PEER
) ? " PEER" : "");
60 * if_dump - dump interface
61 * @i: interface to dump
63 * This function dumps all information associated with a given
64 * network interface to the debug output.
67 if_dump(struct iface
*i
)
71 debug("IF%d: %s", i
->index
, i
->name
);
72 if (i
->flags
& IF_SHUTDOWN
)
78 if (i
->flags
& IF_ADMIN_UP
)
80 if (i
->flags
& IF_MULTIACCESS
)
82 if (i
->flags
& IF_BROADCAST
)
84 if (i
->flags
& IF_MULTICAST
)
86 if (i
->flags
& IF_LOOPBACK
)
88 if (i
->flags
& IF_IGNORE
)
90 if (i
->flags
& IF_TMP_DOWN
)
92 debug(" MTU=%d\n", i
->mtu
);
93 WALK_LIST(a
, i
->addrs
)
96 ASSERT(!!(a
->flags
& IA_PRIMARY
) ==
97 ((a
== i
->addr4
) || (a
== i
->addr6
) || (a
== i
->llv6
)));
102 * if_dump_all - dump all interfaces
104 * This function dumps information about all known network
105 * interfaces to the debug output.
112 debug("Known network interfaces:\n");
113 WALK_LIST(i
, iface_list
)
115 debug("Router ID: %08x\n", config
->router_id
);
118 static inline unsigned
119 if_what_changed(struct iface
*i
, struct iface
*j
)
123 if (((i
->flags
^ j
->flags
) & ~(IF_UP
| IF_SHUTDOWN
| IF_UPDATED
| IF_ADMIN_UP
| IF_LINK_UP
| IF_TMP_DOWN
| IF_JUST_CREATED
))
124 || (i
->index
!= j
->index
) || (i
->master
!= j
->master
))
125 return IF_CHANGE_TOO_MUCH
;
127 if ((i
->flags
^ j
->flags
) & IF_UP
)
128 c
|= (i
->flags
& IF_UP
) ? IF_CHANGE_DOWN
: IF_CHANGE_UP
;
129 if ((i
->flags
^ j
->flags
) & IF_LINK_UP
)
131 if (i
->mtu
!= j
->mtu
)
137 if_copy(struct iface
*to
, struct iface
*from
)
139 to
->flags
= from
->flags
| (to
->flags
& IF_TMP_DOWN
);
141 to
->master_index
= from
->master_index
;
142 to
->master
= from
->master
;
146 ifa_send_notify(struct proto
*p
, unsigned c
, struct ifa
*a
)
149 (p
->proto_state
!= PS_DOWN
) &&
150 (!p
->vrf
|| p
->vrf
== a
->iface
->master
))
152 if (p
->debug
& D_IFACES
)
153 log(L_TRACE
"%s < address %N on interface %s %s",
154 p
->name
, &a
->prefix
, a
->iface
->name
,
155 (c
& IF_CHANGE_UP
) ? "added" : "removed");
156 p
->ifa_notify(p
, c
, a
);
161 ifa_notify_change_(unsigned c
, struct ifa
*a
)
165 DBG("IFA change notification (%x) for %s:%I\n", c
, a
->iface
->name
, a
->ip
);
167 WALK_LIST(p
, proto_list
)
168 ifa_send_notify(p
, c
, a
);
172 ifa_notify_change(unsigned c
, struct ifa
*a
)
174 if (c
& IF_CHANGE_DOWN
)
177 ifa_notify_change_(c
, a
);
179 if (c
& IF_CHANGE_UP
)
184 if_send_notify(struct proto
*p
, unsigned c
, struct iface
*i
)
187 (p
->proto_state
!= PS_DOWN
) &&
188 (!p
->vrf
|| p
->vrf
== i
->master
))
190 if (p
->debug
& D_IFACES
)
191 log(L_TRACE
"%s < interface %s %s", p
->name
, i
->name
,
192 (c
& IF_CHANGE_UP
) ? "goes up" :
193 (c
& IF_CHANGE_DOWN
) ? "goes down" :
194 (c
& IF_CHANGE_MTU
) ? "changes MTU" :
195 (c
& IF_CHANGE_LINK
) ? "changes link" :
196 (c
& IF_CHANGE_PREFERRED
) ? "changes preferred address" :
197 (c
& IF_CHANGE_CREATE
) ? "created" :
198 "sends unknown event");
199 p
->if_notify(p
, c
, i
);
204 if_notify_change(unsigned c
, struct iface
*i
)
209 if (i
->flags
& IF_JUST_CREATED
)
211 i
->flags
&= ~IF_JUST_CREATED
;
212 c
|= IF_CHANGE_CREATE
| IF_CHANGE_MTU
;
215 DBG("Interface change notification (%x) for %s\n", c
, i
->name
);
220 if (c
& IF_CHANGE_DOWN
)
223 if (c
& IF_CHANGE_DOWN
)
224 WALK_LIST(a
, i
->addrs
)
225 ifa_notify_change_(IF_CHANGE_DOWN
, a
);
227 WALK_LIST(p
, proto_list
)
228 if_send_notify(p
, c
, i
);
230 if (c
& IF_CHANGE_UP
)
231 WALK_LIST(a
, i
->addrs
)
232 ifa_notify_change_(IF_CHANGE_UP
, a
);
234 if (c
& IF_CHANGE_UP
)
237 if ((c
& (IF_CHANGE_UP
| IF_CHANGE_DOWN
| IF_CHANGE_LINK
)) == IF_CHANGE_LINK
)
242 if_recalc_flags(struct iface
*i UNUSED
, uint flags
)
244 if ((flags
& IF_ADMIN_UP
) &&
245 !(flags
& (IF_SHUTDOWN
| IF_TMP_DOWN
)) &&
246 !(i
->master_index
&& !i
->master
))
255 if_change_flags(struct iface
*i
, uint flags
)
258 i
->flags
= if_recalc_flags(i
, flags
);
260 if ((i
->flags
^ of
) & IF_UP
)
261 if_notify_change((i
->flags
& IF_UP
) ? IF_CHANGE_UP
: IF_CHANGE_DOWN
, i
);
265 * if_delete - remove interface
268 * This function is called by the low-level platform dependent code
269 * whenever it notices an interface disappears. It is just a shorthand
274 if_delete(struct iface
*old
)
277 strncpy(f
.name
, old
->name
, sizeof(f
.name
)-1);
278 f
.flags
= IF_SHUTDOWN
;
283 * if_update - update interface status
284 * @new: new interface status
286 * if_update() is called by the low-level platform dependent code
287 * whenever it notices an interface change.
289 * There exist two types of interface updates -- synchronous and asynchronous
290 * ones. In the synchronous case, the low-level code calls if_start_update(),
291 * scans all interfaces reported by the OS, uses if_update() and ifa_update()
292 * to pass them to the core and then it finishes the update sequence by
293 * calling if_end_update(). When working asynchronously, the sysdep code
294 * calls if_update() and ifa_update() whenever it notices a change.
296 * if_update() will automatically notify all other modules about the change.
299 if_update(struct iface
*new)
304 WALK_LIST(i
, iface_list
)
305 if (!strcmp(new->name
, i
->name
))
307 new->flags
= if_recalc_flags(new, new->flags
);
308 c
= if_what_changed(i
, new);
309 if (c
& IF_CHANGE_TOO_MUCH
) /* Changed a lot, convert it to down/up */
311 DBG("Interface %s changed too much -- forcing down/up transition\n", i
->name
);
312 if_change_flags(i
, i
->flags
| IF_TMP_DOWN
);
314 new->addr4
= i
->addr4
;
315 new->addr6
= i
->addr6
;
317 new->sysdep
= i
->sysdep
;
318 memcpy(&new->addrs
, &i
->addrs
, sizeof(i
->addrs
));
319 memcpy(i
, new, sizeof(*i
));
320 i
->flags
&= ~IF_UP
; /* IF_TMP_DOWN will be added later */
326 if_notify_change(c
, i
);
328 i
->flags
|= IF_UPDATED
;
331 i
= mb_alloc(if_pool
, sizeof(struct iface
));
332 memcpy(i
, new, sizeof(*i
));
333 init_list(&i
->addrs
);
335 init_list(&i
->neighbors
);
336 i
->flags
|= IF_UPDATED
| IF_TMP_DOWN
; /* Tmp down as we don't have addresses yet */
337 add_tail(&iface_list
, &i
->n
);
342 if_start_update(void)
347 WALK_LIST(i
, iface_list
)
349 i
->flags
&= ~IF_UPDATED
;
350 WALK_LIST(a
, i
->addrs
)
351 a
->flags
&= ~IA_UPDATED
;
356 if_end_partial_update(struct iface
*i
)
358 if (i
->flags
& IF_NEEDS_RECALC
)
359 if_recalc_preferred(i
);
361 if (i
->flags
& IF_TMP_DOWN
)
362 if_change_flags(i
, i
->flags
& ~IF_TMP_DOWN
);
371 WALK_LIST(i
, iface_list
)
373 if (!(i
->flags
& IF_UPDATED
))
374 if_change_flags(i
, (i
->flags
& ~IF_ADMIN_UP
) | IF_SHUTDOWN
);
377 WALK_LIST_DELSAFE(a
, b
, i
->addrs
)
378 if (!(a
->flags
& IA_UPDATED
))
380 if_end_partial_update(i
);
386 if_flush_ifaces(struct proto
*p
)
388 if (p
->debug
& D_EVENTS
)
389 log(L_TRACE
"%s: Flushing interfaces", p
->name
);
395 * if_feed_baby - advertise interfaces to a new protocol
396 * @p: protocol to feed
398 * When a new protocol starts, this function sends it a series
399 * of notifications about all existing interfaces.
402 if_feed_baby(struct proto
*p
)
407 if (!p
->if_notify
&& !p
->ifa_notify
) /* shortcut */
409 DBG("Announcing interfaces to new protocol %s\n", p
->name
);
410 WALK_LIST(i
, iface_list
)
412 if_send_notify(p
, IF_CHANGE_CREATE
| ((i
->flags
& IF_UP
) ? IF_CHANGE_UP
: 0), i
);
413 if (i
->flags
& IF_UP
)
414 WALK_LIST(a
, i
->addrs
)
415 ifa_send_notify(p
, IF_CHANGE_CREATE
| IF_CHANGE_UP
, a
);
420 * if_find_by_index - find interface by ifindex
423 * This function finds an &iface structure corresponding to an interface
424 * of the given index @idx. Returns a pointer to the structure or %NULL
425 * if no such structure exists.
428 if_find_by_index(unsigned idx
)
432 WALK_LIST(i
, iface_list
)
433 if (i
->index
== idx
&& !(i
->flags
& IF_SHUTDOWN
))
439 * if_find_by_name - find interface by name
440 * @name: interface name
442 * This function finds an &iface structure corresponding to an interface
443 * of the given name @name. Returns a pointer to the structure or %NULL
444 * if no such structure exists.
447 if_find_by_name(char *name
)
451 WALK_LIST(i
, iface_list
)
452 if (!strcmp(i
->name
, name
) && !(i
->flags
& IF_SHUTDOWN
))
458 if_get_by_name(char *name
)
462 WALK_LIST(i
, iface_list
)
463 if (!strcmp(i
->name
, name
))
466 /* No active iface, create a dummy */
467 i
= mb_allocz(if_pool
, sizeof(struct iface
));
468 strncpy(i
->name
, name
, sizeof(i
->name
)-1);
469 i
->flags
= IF_SHUTDOWN
;
470 init_list(&i
->addrs
);
471 init_list(&i
->neighbors
);
472 add_tail(&iface_list
, &i
->n
);
477 if_set_preferred(struct ifa
**pos
, struct ifa
*new)
480 (*pos
)->flags
&= ~IA_PRIMARY
;
482 new->flags
|= IA_PRIMARY
;
488 if_recalc_preferred(struct iface
*i
)
491 * Preferred address selection priority:
492 * 1) Address configured in Device protocol
493 * 2) Sysdep IPv4 address (BSD)
494 * 3) Old preferred address
495 * 4) First address in list
498 struct kif_iface_config
*ic
= kif_get_iface_config(i
);
499 struct ifa
*a4
= i
->addr4
, *a6
= i
->addr6
, *ll
= i
->llv6
;
500 ip_addr pref_v4
= ic
->pref_v4
;
503 if (kif_update_sysdep_addr(i
))
504 change
|= IF_CHANGE_SYSDEP
;
506 /* BSD sysdep address */
507 if (ipa_zero(pref_v4
) && ip4_nonzero(i
->sysdep
))
508 pref_v4
= ipa_from_ip4(i
->sysdep
);
511 WALK_LIST(a
, i
->addrs
)
513 /* Secondary address is never selected */
514 if (a
->flags
& IA_SECONDARY
)
517 if (ipa_is_ip4(a
->ip
)) {
518 if (!a4
|| ipa_equal(a
->ip
, pref_v4
))
520 } else if (!ipa_is_link_local(a
->ip
)) {
521 if (!a6
|| ipa_equal(a
->ip
, ic
->pref_v6
))
524 if (!ll
|| ipa_equal(a
->ip
, ic
->pref_ll
))
529 if ((a4
!= i
->addr4
) || (i
->flags
& IF_LOST_ADDR4
))
531 if_set_preferred(&i
->addr4
, a4
);
532 change
|= IF_CHANGE_ADDR4
;
535 if ((a6
!= i
->addr6
) || (i
->flags
& IF_LOST_ADDR6
))
537 if_set_preferred(&i
->addr6
, a6
);
538 change
|= IF_CHANGE_ADDR6
;
541 if ((ll
!= i
->llv6
) || (i
->flags
& IF_LOST_LLV6
))
543 if_set_preferred(&i
->llv6
, ll
);
544 change
|= IF_CHANGE_LLV6
;
547 i
->flags
&= ~(IF_NEEDS_RECALC
| IF_LOST_ADDR4
| IF_LOST_ADDR6
| IF_LOST_LLV6
);
550 if_notify_change(change
, i
);
554 if_recalc_all_preferred_addresses(void)
558 WALK_LIST(i
, iface_list
)
560 if_recalc_preferred(i
);
562 if (i
->flags
& IF_TMP_DOWN
)
563 if_change_flags(i
, i
->flags
& ~IF_TMP_DOWN
);
568 ifa_same(struct ifa
*a
, struct ifa
*b
)
570 return ipa_equal(a
->ip
, b
->ip
) && net_equal(&a
->prefix
, &b
->prefix
);
575 * ifa_update - update interface address
576 * @a: new interface address
578 * This function adds address information to a network
579 * interface. It's called by the platform dependent code during
580 * the interface update process described under if_update().
583 ifa_update(struct ifa
*a
)
585 struct iface
*i
= a
->iface
;
588 WALK_LIST(b
, i
->addrs
)
591 if (ipa_equal(b
->brd
, a
->brd
) &&
592 ipa_equal(b
->opposite
, a
->opposite
) &&
593 b
->scope
== a
->scope
&&
594 !((b
->flags
^ a
->flags
) & IA_PEER
))
596 b
->flags
|= IA_UPDATED
;
603 if ((a
->prefix
.type
== NET_IP4
) && (i
->flags
& IF_BROADCAST
) && ipa_zero(a
->brd
))
604 log(L_WARN
"Missing broadcast address for interface %s", i
->name
);
606 b
= mb_alloc(if_pool
, sizeof(struct ifa
));
607 memcpy(b
, a
, sizeof(struct ifa
));
608 add_tail(&i
->addrs
, &b
->n
);
609 b
->flags
|= IA_UPDATED
;
611 i
->flags
|= IF_NEEDS_RECALC
;
612 if (i
->flags
& IF_UP
)
613 ifa_notify_change(IF_CHANGE_CREATE
| IF_CHANGE_UP
, b
);
618 * ifa_delete - remove interface address
619 * @a: interface address
621 * This function removes address information from a network
622 * interface. It's called by the platform dependent code during
623 * the interface update process described under if_update().
626 ifa_delete(struct ifa
*a
)
628 struct iface
*i
= a
->iface
;
631 WALK_LIST(b
, i
->addrs
)
636 if (b
->flags
& IA_PRIMARY
)
639 * We unlink deleted preferred address and mark for recalculation.
640 * FIXME: This could break if we make iface scan non-atomic, as
641 * protocols still could use the freed address until they get
642 * if_notify from preferred route recalculation. We should fix and
643 * simplify this in the future by having struct ifa refcounted
645 if (b
== i
->addr4
) { i
->addr4
= NULL
; i
->flags
|= IF_LOST_ADDR4
; }
646 if (b
== i
->addr6
) { i
->addr6
= NULL
; i
->flags
|= IF_LOST_ADDR6
; }
647 if (b
== i
->llv6
) { i
->llv6
= NULL
; i
->flags
|= IF_LOST_LLV6
; }
648 i
->flags
|= IF_NEEDS_RECALC
;
651 if (i
->flags
& IF_UP
)
652 ifa_notify_change(IF_CHANGE_DOWN
, b
);
660 if_choose_router_id(struct iface_patt
*mask
, u32 old_id
)
666 WALK_LIST(i
, iface_list
)
668 if (!(i
->flags
& IF_ADMIN_UP
) ||
669 (i
->flags
& IF_SHUTDOWN
))
672 WALK_LIST(a
, i
->addrs
)
674 if (a
->prefix
.type
!= NET_IP4
)
677 if (a
->flags
& IA_SECONDARY
)
680 if (a
->scope
<= SCOPE_LINK
)
683 /* Check pattern if specified */
684 if (mask
&& !iface_patt_match(mask
, i
, a
))
687 /* No pattern or pattern matched */
688 if (!b
|| ipa_to_u32(a
->ip
) < ipa_to_u32(b
->ip
))
696 u32 id
= ipa_to_u32(b
->ip
);
698 log(L_INFO
"Chosen router ID %R according to interface %s", id
, b
->iface
->name
);
704 * if_init - initialize interface module
706 * This function is called during BIRD startup to initialize
707 * all data structures of the interface module.
712 if_pool
= rp_new(&root_pool
, "Interfaces");
713 init_list(&iface_list
);
718 * Interface Pattern Lists
722 iface_patt_match(struct iface_patt
*ifp
, struct iface
*i
, struct ifa
*a
)
724 struct iface_patt_node
*p
;
726 WALK_LIST(p
, ifp
->ipn_list
)
728 char *t
= p
->pattern
;
729 int pos
= p
->positive
;
739 if (!patmatch(t
, i
->name
))
743 if (p
->prefix
.pxlen
== 0)
749 if (ipa_in_netX(a
->ip
, &p
->prefix
))
752 if ((a
->flags
& IA_PEER
) &&
753 ipa_in_netX(a
->opposite
, &p
->prefix
))
763 iface_patt_find(list
*l
, struct iface
*i
, struct ifa
*a
)
765 struct iface_patt
*p
;
768 if (iface_patt_match(p
, i
, a
))
775 iface_plists_equal(struct iface_patt
*pa
, struct iface_patt
*pb
)
777 struct iface_patt_node
*x
, *y
;
779 x
= HEAD(pa
->ipn_list
);
780 y
= HEAD(pb
->ipn_list
);
781 while (x
->n
.next
&& y
->n
.next
)
783 if ((x
->positive
!= y
->positive
) ||
784 (!x
->pattern
&& y
->pattern
) || /* This nasty lines where written by me... :-( Feela */
785 (!y
->pattern
&& x
->pattern
) ||
786 ((x
->pattern
!= y
->pattern
) && strcmp(x
->pattern
, y
->pattern
)) ||
787 !net_equal(&x
->prefix
, &y
->prefix
))
789 x
= (void *) x
->n
.next
;
790 y
= (void *) y
->n
.next
;
792 return (!x
->n
.next
&& !y
->n
.next
);
796 iface_patts_equal(list
*a
, list
*b
, int (*comp
)(struct iface_patt
*, struct iface_patt
*))
798 struct iface_patt
*x
, *y
;
802 while (x
->n
.next
&& y
->n
.next
)
804 if (!iface_plists_equal(x
, y
) ||
805 (comp
&& !comp(x
, y
)))
807 x
= (void *) x
->n
.next
;
808 y
= (void *) y
->n
.next
;
810 return (!x
->n
.next
&& !y
->n
.next
);
818 if_show_addr(struct ifa
*a
)
820 byte
*flg
, opp
[IPA_MAX_TEXT_LENGTH
+ 16];
822 flg
= (a
->flags
& IA_PRIMARY
) ? "Preferred, " : (a
->flags
& IA_SECONDARY
) ? "Secondary, " : "";
824 if (ipa_nonzero(a
->opposite
))
825 bsprintf(opp
, "opposite %I, ", a
->opposite
);
829 cli_msg(-1003, "\t%I/%d (%s%sscope %s)",
830 a
->ip
, a
->prefix
.pxlen
, flg
, opp
, ip_scope_text(a
->scope
));
840 WALK_LIST(i
, iface_list
)
842 if (i
->flags
& IF_SHUTDOWN
)
845 char mbuf
[16 + sizeof(i
->name
)] = {};
847 bsprintf(mbuf
, " master=%s", i
->master
->name
);
848 else if (i
->master_index
)
849 bsprintf(mbuf
, " master=#%u", i
->master_index
);
851 cli_msg(-1001, "%s %s (index=%d%s)", i
->name
, (i
->flags
& IF_UP
) ? "up" : "down", i
->index
, mbuf
);
852 if (!(i
->flags
& IF_MULTIACCESS
))
855 type
= "MultiAccess";
856 cli_msg(-1004, "\t%s%s%s Admin%s Link%s%s%s MTU=%d",
858 (i
->flags
& IF_BROADCAST
) ? " Broadcast" : "",
859 (i
->flags
& IF_MULTICAST
) ? " Multicast" : "",
860 (i
->flags
& IF_ADMIN_UP
) ? "Up" : "Down",
861 (i
->flags
& IF_LINK_UP
) ? "Up" : "Down",
862 (i
->flags
& IF_LOOPBACK
) ? " Loopback" : "",
863 (i
->flags
& IF_IGNORE
) ? " Ignored" : "",
866 WALK_LIST(a
, i
->addrs
)
867 if (a
->prefix
.type
== NET_IP4
)
870 WALK_LIST(a
, i
->addrs
)
871 if (a
->prefix
.type
== NET_IP6
)
878 if_show_summary(void)
882 cli_msg(-2005, "%-10s %-6s %-18s %s", "Interface", "State", "IPv4 address", "IPv6 address");
883 WALK_LIST(i
, iface_list
)
885 byte a4
[IPA_MAX_TEXT_LENGTH
+ 17];
886 byte a6
[IPA_MAX_TEXT_LENGTH
+ 17];
888 if (i
->flags
& IF_SHUTDOWN
)
892 bsprintf(a4
, "%I/%d", i
->addr4
->ip
, i
->addr4
->prefix
.pxlen
);
897 bsprintf(a6
, "%I/%d", i
->addr6
->ip
, i
->addr6
->prefix
.pxlen
);
901 cli_msg(-1005, "%-10s %-6s %-18s %s",
902 i
->name
, (i
->flags
& IF_UP
) ? "up" : "down", a4
, a6
);