2 * BIRD -- Router Advertisement
5 * Can be freely distributed and used under the terms of the GNU GPL.
13 * DOC: Router Advertisements
15 * The RAdv protocol is implemented in two files: |radv.c| containing the
16 * interface with BIRD core and the protocol logic and |packets.c| handling low
17 * level protocol stuff (RX, TX and packet formats). The protocol does not
20 * The RAdv is structured in the usual way - for each handled interface there is
21 * a structure &radv_iface that contains a state related to that interface
22 * together with its resources (a socket, a timer). There is also a prepared RA
23 * stored in a TX buffer of the socket associated with an iface. These iface
24 * structures are created and removed according to iface events from BIRD core
25 * handled by radv_if_notify() callback.
27 * The main logic of RAdv consists of two functions: radv_iface_notify(), which
28 * processes asynchronous events (specified by RA_EV_* codes), and radv_timer(),
29 * which triggers sending RAs and computes the next timeout.
31 * The RAdv protocol could receive routes (through radv_import_control() and
32 * radv_rt_notify()), but only the configured trigger route is tracked (in
33 * &active var). When a radv protocol is reconfigured, the connected routing
34 * table is examined (in radv_check_active()) to have proper &active value in
35 * case of the specified trigger prefix was changed.
37 * Supported standards:
38 * - RFC 4861 - main RA standard
39 * - RFC 4191 - Default Router Preferences and More-Specific Routes
40 * - RFC 6106 - DNS extensions (RDDNS, DNSSL)
43 static void radv_prune_prefixes(struct radv_iface
*ifa
);
44 static void radv_prune_routes(struct radv_proto
*p
);
46 /* Invalidate cached RA packet */
47 static inline void radv_invalidate(struct radv_iface
*ifa
)
53 struct radv_iface
*ifa
= tm
->data
;
54 struct radv_proto
*p
= ifa
->ra
;
55 btime now
= current_time();
57 RADV_TRACE(D_EVENTS
, "Timer fired on %s", ifa
->iface
->name
);
59 if (ifa
->valid_time
<= now
)
62 if (ifa
->prune_time
<= now
)
63 radv_prune_prefixes(ifa
);
65 if (p
->prune_time
<= now
)
72 btime t
= ifa
->cf
->min_ra_int S
;
73 btime r
= (ifa
->cf
->max_ra_int
- ifa
->cf
->min_ra_int
) S
;
74 t
+= random() % (r
+ 1);
78 t
= MIN(t
, MAX_INITIAL_RTR_ADVERT_INTERVAL
);
82 tm_start(ifa
->timer
, t
);
85 static struct radv_prefix_config default_prefix
= {
88 .valid_lifetime
= DEFAULT_VALID_LIFETIME
,
89 .preferred_lifetime
= DEFAULT_PREFERRED_LIFETIME
92 static struct radv_prefix_config dead_prefix
= {
95 /* Find a corresponding config for the given prefix */
96 static struct radv_prefix_config
*
97 radv_prefix_match(struct radv_iface
*ifa
, net_addr_ip6
*px
)
99 struct radv_proto
*p
= ifa
->ra
;
100 struct radv_config
*cf
= (struct radv_config
*) (p
->p
.cf
);
101 struct radv_prefix_config
*pc
;
103 WALK_LIST(pc
, ifa
->cf
->pref_list
)
104 if (net_in_net_ip6(px
, &pc
->prefix
))
107 WALK_LIST(pc
, cf
->pref_list
)
108 if (net_in_net_ip6(px
, &pc
->prefix
))
111 return &default_prefix
;
115 * Go through the list of prefixes, compare them with configs and decide if we
119 radv_prepare_prefixes(struct radv_iface
*ifa
)
121 struct radv_proto
*p
= ifa
->ra
;
122 struct radv_prefix
*pfx
, *next
;
123 btime now
= current_time();
125 /* First mark all the prefixes as unused */
126 WALK_LIST(pfx
, ifa
->prefixes
)
129 /* Find all the prefixes we want to use and make sure they are in the list. */
131 WALK_LIST(addr
, ifa
->iface
->addrs
)
133 if ((addr
->prefix
.type
!= NET_IP6
) ||
134 (addr
->scope
<= SCOPE_LINK
))
137 net_addr_ip6
*prefix
= (void *) &addr
->prefix
;
138 struct radv_prefix_config
*pc
= radv_prefix_match(ifa
, prefix
);
143 /* Do we have it already? */
144 struct radv_prefix
*existing
= NULL
;
145 WALK_LIST(pfx
, ifa
->prefixes
)
146 if (net_equal_ip6(&pfx
->prefix
, prefix
))
154 RADV_TRACE(D_EVENTS
, "Adding new prefix %N on %s",
155 prefix
, ifa
->iface
->name
);
157 existing
= mb_allocz(ifa
->pool
, sizeof *existing
);
158 net_copy_ip6(&existing
->prefix
, prefix
);
159 add_tail(&ifa
->prefixes
, NODE existing
);
163 * Update the information (it may have changed, or even bring a prefix back
167 existing
->changed
= now
;
172 WALK_LIST_DELSAFE(pfx
, next
, ifa
->prefixes
)
174 if (pfx
->valid
&& !pfx
->mark
)
176 RADV_TRACE(D_EVENTS
, "Invalidating prefix %N on %s",
177 &pfx
->prefix
, ifa
->iface
->name
);
181 pfx
->cf
= &dead_prefix
;
187 radv_prune_prefixes(struct radv_iface
*ifa
)
189 struct radv_proto
*p
= ifa
->ra
;
190 btime now
= current_time();
191 btime next
= TIME_INFINITY
;
194 struct radv_prefix
*px
, *pxn
;
195 WALK_LIST_DELSAFE(px
, pxn
, ifa
->prefixes
)
199 expires
= px
->changed
+ ifa
->cf
->prefix_linger_time S
;
203 RADV_TRACE(D_EVENTS
, "Removing prefix %N on %s",
204 &px
->prefix
, ifa
->iface
->name
);
210 next
= MIN(next
, expires
);
214 ifa
->prune_time
= next
;
217 static char* ev_name
[] = { NULL
, "Init", "Change", "RS" };
220 radv_iface_notify(struct radv_iface
*ifa
, int event
)
222 struct radv_proto
*p
= ifa
->ra
;
227 RADV_TRACE(D_EVENTS
, "Event %s on %s", ev_name
[event
], ifa
->iface
->name
);
232 radv_invalidate(ifa
);
235 ifa
->initial
= MAX_INITIAL_RTR_ADVERTISEMENTS
;
236 radv_prepare_prefixes(ifa
);
237 radv_prune_prefixes(ifa
);
245 btime t
= ifa
->last
+ ifa
->cf
->min_delay S
- current_time();
246 tm_start(ifa
->timer
, t
);
250 radv_iface_notify_all(struct radv_proto
*p
, int event
)
252 struct radv_iface
*ifa
;
254 WALK_LIST(ifa
, p
->iface_list
)
255 radv_iface_notify(ifa
, event
);
258 static struct radv_iface
*
259 radv_iface_find(struct radv_proto
*p
, struct iface
*what
)
261 struct radv_iface
*ifa
;
263 WALK_LIST(ifa
, p
->iface_list
)
264 if (ifa
->iface
== what
)
271 radv_iface_add(struct object_lock
*lock
)
273 struct radv_iface
*ifa
= lock
->data
;
274 struct radv_proto
*p
= ifa
->ra
;
276 if (! radv_sk_open(ifa
))
278 log(L_ERR
"%s: Socket open failed on interface %s", p
->p
.name
, ifa
->iface
->name
);
282 radv_iface_notify(ifa
, RA_EV_INIT
);
286 radv_iface_new(struct radv_proto
*p
, struct iface
*iface
, struct radv_iface_config
*cf
)
288 struct radv_iface
*ifa
;
290 RADV_TRACE(D_EVENTS
, "Adding interface %s", iface
->name
);
292 pool
*pool
= rp_new(p
->p
.pool
, iface
->name
);
293 ifa
= mb_allocz(pool
, sizeof(struct radv_iface
));
298 ifa
->addr
= iface
->llv6
;
299 init_list(&ifa
->prefixes
);
300 ifa
->prune_time
= TIME_INFINITY
;
302 add_tail(&p
->iface_list
, NODE ifa
);
304 ifa
->timer
= tm_new_init(pool
, radv_timer
, ifa
, 0, 0);
306 struct object_lock
*lock
= olock_new(pool
);
307 lock
->type
= OBJLOCK_IP
;
308 lock
->port
= ICMPV6_PROTO
;
311 lock
->hook
= radv_iface_add
;
318 radv_iface_remove(struct radv_iface
*ifa
)
320 struct radv_proto
*p
= ifa
->ra
;
321 RADV_TRACE(D_EVENTS
, "Removing interface %s", ifa
->iface
->name
);
329 radv_if_notify(struct proto
*P
, unsigned flags
, struct iface
*iface
)
331 struct radv_proto
*p
= (struct radv_proto
*) P
;
332 struct radv_config
*cf
= (struct radv_config
*) (P
->cf
);
334 if (iface
->flags
& IF_IGNORE
)
337 if (flags
& IF_CHANGE_UP
)
339 struct radv_iface_config
*ic
= (void *) iface_patt_find(&cf
->patt_list
, iface
, NULL
);
341 /* Ignore non-multicast ifaces */
342 if (!(iface
->flags
& IF_MULTICAST
))
345 /* Ignore ifaces without link-local address */
350 radv_iface_new(p
, iface
, ic
);
355 struct radv_iface
*ifa
= radv_iface_find(p
, iface
);
359 if (flags
& IF_CHANGE_DOWN
)
361 radv_iface_remove(ifa
);
365 if ((flags
& IF_CHANGE_LINK
) && (iface
->flags
& IF_LINK_UP
))
366 radv_iface_notify(ifa
, RA_EV_INIT
);
370 radv_ifa_notify(struct proto
*P
, unsigned flags UNUSED
, struct ifa
*a
)
372 struct radv_proto
*p
= (struct radv_proto
*) P
;
374 if (a
->flags
& IA_SECONDARY
)
377 if (a
->scope
<= SCOPE_LINK
)
380 struct radv_iface
*ifa
= radv_iface_find(p
, a
->iface
);
383 radv_iface_notify(ifa
, RA_EV_CHANGE
);
387 radv_trigger_valid(struct radv_config
*cf
)
389 return cf
->trigger
.type
!= 0;
393 radv_net_match_trigger(struct radv_config
*cf
, net
*n
)
395 return radv_trigger_valid(cf
) && net_equal(n
->n
.addr
, &cf
->trigger
);
399 radv_import_control(struct proto
*P
, rte
**new, struct linpool
*pool UNUSED
)
401 // struct radv_proto *p = (struct radv_proto *) P;
402 struct radv_config
*cf
= (struct radv_config
*) (P
->cf
);
404 if (radv_net_match_trigger(cf
, (*new)->net
))
407 if (cf
->propagate_routes
)
414 radv_rt_notify(struct proto
*P
, struct channel
*ch UNUSED
, net
*n
, rte
*new, rte
*old UNUSED
)
416 struct radv_proto
*p
= (struct radv_proto
*) P
;
417 struct radv_config
*cf
= (struct radv_config
*) (P
->cf
);
418 struct radv_route
*rt
;
421 if (radv_net_match_trigger(cf
, n
))
423 u8 old_active
= p
->active
;
426 if (p
->active
== old_active
)
430 RADV_TRACE(D_EVENTS
, "Triggered");
432 RADV_TRACE(D_EVENTS
, "Suppressed");
434 radv_iface_notify_all(p
, RA_EV_CHANGE
);
438 if (!cf
->propagate_routes
)
442 * Some other route we want to send (or stop sending). Update the cache,
443 * with marking a removed one as dead or creating a new one as needed.
445 * And yes, we exclude the trigger route on purpose.
452 ea
= ea_find(new->attrs
->eattrs
, EA_RA_PREFERENCE
);
453 uint preference
= ea
? ea
->u
.data
: RA_PREF_MEDIUM
;
454 uint preference_set
= !!ea
;
456 ea
= ea_find(new->attrs
->eattrs
, EA_RA_LIFETIME
);
457 uint lifetime
= ea
? ea
->u
.data
: 0;
458 uint lifetime_set
= !!ea
;
460 if ((preference
!= RA_PREF_LOW
) &&
461 (preference
!= RA_PREF_MEDIUM
) &&
462 (preference
!= RA_PREF_HIGH
))
464 log(L_WARN
"%s: Invalid ra_preference value %u on route %N",
465 p
->p
.name
, preference
, n
->n
.addr
);
466 preference
= RA_PREF_MEDIUM
;
472 rt
= fib_get(&p
->routes
, n
->n
.addr
);
474 /* Ignore update if nothing changed */
476 (rt
->preference
== preference
) &&
477 (rt
->preference_set
== preference_set
) &&
478 (rt
->lifetime
== lifetime
) &&
479 (rt
->lifetime_set
== lifetime_set
))
482 if (p
->routes
.entries
== 18)
483 log(L_WARN
"%s: More than 17 routes exported to RAdv", p
->p
.name
);
486 rt
->changed
= current_time();
487 rt
->preference
= preference
;
488 rt
->preference_set
= preference_set
;
489 rt
->lifetime
= lifetime
;
490 rt
->lifetime_set
= lifetime_set
;
495 rt
= fib_find(&p
->routes
, n
->n
.addr
);
497 if (!rt
|| !rt
->valid
)
500 /* Invalidate the route */
502 rt
->changed
= current_time();
504 /* Invalidated route will be pruned eventually */
505 btime expires
= rt
->changed
+ cf
->max_linger_time S
;
506 p
->prune_time
= MIN(p
->prune_time
, expires
);
509 radv_iface_notify_all(p
, RA_EV_CHANGE
);
513 * Cleans up all the dead routes that expired and schedules itself to be run
514 * again if there are more routes waiting for expiration.
517 radv_prune_routes(struct radv_proto
*p
)
519 struct radv_config
*cf
= (struct radv_config
*) (p
->p
.cf
);
520 btime now
= current_time();
521 btime next
= TIME_INFINITY
;
524 /* Should not happen */
528 struct fib_iterator fit
;
529 FIB_ITERATE_INIT(&fit
, &p
->routes
);
532 FIB_ITERATE_START(&p
->routes
, &fit
, struct radv_route
, rt
)
536 expires
= rt
->changed
+ cf
->max_linger_time S
;
538 /* Delete expired nodes */
541 FIB_ITERATE_PUT(&fit
);
542 fib_delete(&p
->routes
, rt
);
546 next
= MIN(next
, expires
);
551 p
->prune_time
= next
;
555 radv_check_active(struct radv_proto
*p
)
557 struct radv_config
*cf
= (struct radv_config
*) (p
->p
.cf
);
559 if (!radv_trigger_valid(cf
))
562 struct channel
*c
= p
->p
.main_channel
;
563 return rt_examine(c
->table
, &cf
->trigger
, &p
->p
, c
->out_filter
);
567 radv_postconfig(struct proto_config
*CF
)
569 // struct radv_config *cf = (void *) CF;
571 /* Define default channel */
572 if (EMPTY_LIST(CF
->channels
))
573 channel_config_new(NULL
, net_label
[NET_IP6
], NET_IP6
, CF
);
576 static struct proto
*
577 radv_init(struct proto_config
*CF
)
579 struct proto
*P
= proto_new(CF
);
581 P
->main_channel
= proto_add_channel(P
, proto_cf_main_channel(CF
));
583 P
->import_control
= radv_import_control
;
584 P
->rt_notify
= radv_rt_notify
;
585 P
->if_notify
= radv_if_notify
;
586 P
->ifa_notify
= radv_ifa_notify
;
592 radv_set_fib(struct radv_proto
*p
, int up
)
598 fib_init(&p
->routes
, p
->p
.pool
, NET_IP6
, sizeof(struct radv_route
),
599 OFFSETOF(struct radv_route
, n
), 4, NULL
);
601 fib_free(&p
->routes
);
604 p
->prune_time
= TIME_INFINITY
;
608 radv_start(struct proto
*P
)
610 struct radv_proto
*p
= (struct radv_proto
*) P
;
611 struct radv_config
*cf
= (struct radv_config
*) (P
->cf
);
613 init_list(&(p
->iface_list
));
615 p
->active
= !radv_trigger_valid(cf
);
618 radv_set_fib(p
, cf
->propagate_routes
);
619 p
->prune_time
= TIME_INFINITY
;
625 radv_iface_shutdown(struct radv_iface
*ifa
)
629 radv_invalidate(ifa
);
635 radv_shutdown(struct proto
*P
)
637 struct radv_proto
*p
= (struct radv_proto
*) P
;
641 struct radv_iface
*ifa
;
642 WALK_LIST(ifa
, p
->iface_list
)
643 radv_iface_shutdown(ifa
);
649 radv_reconfigure(struct proto
*P
, struct proto_config
*CF
)
651 struct radv_proto
*p
= (struct radv_proto
*) P
;
652 struct radv_config
*old
= (struct radv_config
*) (P
->cf
);
653 struct radv_config
*new = (struct radv_config
*) CF
;
655 if (!proto_configure_channel(P
, &P
->main_channel
, proto_cf_main_channel(CF
)))
658 P
->cf
= CF
; /* radv_check_active() requires proper P->cf */
659 p
->active
= radv_check_active(p
);
661 /* Allocate or free FIB */
662 radv_set_fib(p
, new->propagate_routes
);
664 /* We started to accept routes so we need to refeed them */
665 if (!old
->propagate_routes
&& new->propagate_routes
)
666 channel_request_feeding(p
->p
.main_channel
);
669 WALK_LIST(iface
, iface_list
)
671 if (!(iface
->flags
& IF_UP
))
674 /* Ignore non-multicast ifaces */
675 if (!(iface
->flags
& IF_MULTICAST
))
678 /* Ignore ifaces without link-local address */
682 struct radv_iface
*ifa
= radv_iface_find(p
, iface
);
683 struct radv_iface_config
*ic
= (struct radv_iface_config
*)
684 iface_patt_find(&new->patt_list
, iface
, NULL
);
690 /* We cheat here - always notify the change even if there isn't
691 any. That would leads just to a few unnecessary RAs. */
692 radv_iface_notify(ifa
, RA_EV_CHANGE
);
697 radv_iface_shutdown(ifa
);
698 radv_iface_remove(ifa
);
702 radv_iface_new(p
, iface
, ic
);
709 radv_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
711 struct radv_config
*d
= (struct radv_config
*) dest
;
712 struct radv_config
*s
= (struct radv_config
*) src
;
714 /* We clean up patt_list, ifaces are non-sharable */
715 init_list(&d
->patt_list
);
717 /* We copy pref_list, shallow copy suffices */
718 cfg_copy_list(&d
->pref_list
, &s
->pref_list
, sizeof(struct radv_prefix_config
));
722 radv_get_status(struct proto
*P
, byte
*buf
)
724 struct radv_proto
*p
= (struct radv_proto
*) P
;
727 strcpy(buf
, "Suppressed");
731 radv_pref_str(u32 pref
)
746 /* The buffer has some minimal size */
748 radv_get_attr(eattr
*a
, byte
*buf
, int buflen UNUSED
)
752 case EA_RA_PREFERENCE
:
753 bsprintf(buf
, "preference: %s", radv_pref_str(a
->u
.data
));
756 bsprintf(buf
, "lifetime");
763 struct protocol proto_radv
= {
765 .template = "radv%d",
766 .class = PROTOCOL_RADV
,
767 .channel_mask
= NB_IP6
,
768 .proto_size
= sizeof(struct radv_proto
),
769 .config_size
= sizeof(struct radv_config
),
770 .postconfig
= radv_postconfig
,
773 .shutdown
= radv_shutdown
,
774 .reconfigure
= radv_reconfigure
,
775 .copy_config
= radv_copy_config
,
776 .get_status
= radv_get_status
,
777 .get_attr
= radv_get_attr