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
16 * the interface with BIRD core and the protocol logic and |packets.c|
17 * handling low level protocol stuff (RX, TX and packet formats).
18 * The protocol does not export any routes.
20 * The RAdv is structured in the usual way - for each handled interface
21 * there is a structure &radv_iface that contains a state related to
22 * that interface together with its resources (a socket, a timer).
23 * There is also a prepared RA stored in a TX buffer of the socket
24 * associated with an iface. These iface structures are created
25 * and removed according to iface events from BIRD core handled by
26 * radv_if_notify() callback.
28 * The main logic of RAdv consists of two functions:
29 * radv_iface_notify(), which processes asynchronous events (specified
30 * by RA_EV_* codes), and radv_timer(), which triggers sending RAs and
31 * computes the next timeout.
33 * The RAdv protocol could receive routes (through
34 * radv_import_control() and radv_rt_notify()), but only the
35 * configured trigger route is tracked (in &active var). When a radv
36 * protocol is reconfigured, the connected routing table is examined
37 * (in radv_check_active()) to have proper &active value in case of
38 * the specified trigger prefix was changed.
40 * Supported standards:
41 * - RFC 4861 - main RA standard
42 * - RFC 6106 - DNS extensions (RDDNS, DNSSL)
43 * - RFC 4191 (partial) - Default Router Preference
49 struct radv_iface
*ifa
= tm
->data
;
50 struct radv_proto
*p
= ifa
->ra
;
52 RADV_TRACE(D_EVENTS
, "Timer fired on %s", ifa
->iface
->name
);
58 unsigned after
= ifa
->cf
->min_ra_int
;
59 after
+= random() % (ifa
->cf
->max_ra_int
- ifa
->cf
->min_ra_int
+ 1);
65 after
= MIN(after
, MAX_INITIAL_RTR_ADVERT_INTERVAL
);
67 tm_start(ifa
->timer
, after
);
70 static char* ev_name
[] = { NULL
, "Init", "Change", "RS" };
73 radv_iface_notify(struct radv_iface
*ifa
, int event
)
75 struct radv_proto
*p
= ifa
->ra
;
80 RADV_TRACE(D_EVENTS
, "Event %s on %s", ev_name
[event
], ifa
->iface
->name
);
87 ifa
->initial
= MAX_INITIAL_RTR_ADVERTISEMENTS
;
95 unsigned delta
= now
- ifa
->last
;
98 if (delta
< ifa
->cf
->min_delay
)
99 after
= ifa
->cf
->min_delay
- delta
;
101 tm_start(ifa
->timer
, after
);
105 radv_iface_notify_all(struct radv_proto
*p
, int event
)
107 struct radv_iface
*ifa
;
109 WALK_LIST(ifa
, p
->iface_list
)
110 radv_iface_notify(ifa
, event
);
114 static struct radv_iface
*
115 radv_iface_find(struct radv_proto
*p
, struct iface
*what
)
117 struct radv_iface
*ifa
;
119 WALK_LIST(ifa
, p
->iface_list
)
120 if (ifa
->iface
== what
)
127 radv_iface_add(struct object_lock
*lock
)
129 struct radv_iface
*ifa
= lock
->data
;
130 struct radv_proto
*p
= ifa
->ra
;
132 if (! radv_sk_open(ifa
))
134 log(L_ERR
"%s: Socket open failed on interface %s", p
->p
.name
, ifa
->iface
->name
);
138 radv_iface_notify(ifa
, RA_EV_INIT
);
141 static inline struct ifa
*
142 find_lladdr(struct iface
*iface
)
145 WALK_LIST(a
, iface
->addrs
)
146 if ((a
->prefix
.type
== NET_IP6
) && (a
->scope
== SCOPE_LINK
))
153 radv_iface_new(struct radv_proto
*p
, struct iface
*iface
, struct radv_iface_config
*cf
)
155 pool
*pool
= p
->p
.pool
;
156 struct radv_iface
*ifa
;
158 RADV_TRACE(D_EVENTS
, "Adding interface %s", iface
->name
);
160 ifa
= mb_allocz(pool
, sizeof(struct radv_iface
));
165 add_tail(&p
->iface_list
, NODE ifa
);
167 ifa
->addr
= find_lladdr(iface
);
170 log(L_ERR
"%s: Cannot find link-locad addr on interface %s", p
->p
.name
, iface
->name
);
174 timer
*tm
= tm_new(pool
);
175 tm
->hook
= radv_timer
;
181 struct object_lock
*lock
= olock_new(pool
);
182 lock
->addr
= IPA_NONE
;
183 lock
->type
= OBJLOCK_IP
;
184 lock
->port
= ICMPV6_PROTO
;
187 lock
->hook
= radv_iface_add
;
194 radv_iface_remove(struct radv_iface
*ifa
)
196 struct radv_proto
*p
= ifa
->ra
;
197 RADV_TRACE(D_EVENTS
, "Removing interface %s", ifa
->iface
->name
);
209 radv_if_notify(struct proto
*P
, unsigned flags
, struct iface
*iface
)
211 struct radv_proto
*p
= (struct radv_proto
*) P
;
212 struct radv_config
*cf
= (struct radv_config
*) (P
->cf
);
214 if (iface
->flags
& IF_IGNORE
)
217 if (flags
& IF_CHANGE_UP
)
219 struct radv_iface_config
*ic
= (struct radv_iface_config
*)
220 iface_patt_find(&cf
->patt_list
, iface
, NULL
);
223 radv_iface_new(p
, iface
, ic
);
228 struct radv_iface
*ifa
= radv_iface_find(p
, iface
);
232 if (flags
& IF_CHANGE_DOWN
)
234 radv_iface_remove(ifa
);
238 if ((flags
& IF_CHANGE_LINK
) && (iface
->flags
& IF_LINK_UP
))
239 radv_iface_notify(ifa
, RA_EV_INIT
);
243 radv_ifa_notify(struct proto
*P
, unsigned flags UNUSED
, struct ifa
*a
)
245 struct radv_proto
*p
= (struct radv_proto
*) P
;
247 if (a
->flags
& IA_SECONDARY
)
250 if (a
->scope
<= SCOPE_LINK
)
253 struct radv_iface
*ifa
= radv_iface_find(p
, a
->iface
);
256 radv_iface_notify(ifa
, RA_EV_CHANGE
);
260 radv_trigger_valid(struct radv_config
*cf
)
262 return cf
->trigger
.type
!= 0;
266 radv_net_match_trigger(struct radv_config
*cf
, net
*n
)
268 return radv_trigger_valid(cf
) && net_equal(n
->n
.addr
, &cf
->trigger
);
272 radv_import_control(struct proto
*P
, rte
**new, ea_list
**attrs UNUSED
, struct linpool
*pool UNUSED
)
274 // struct radv_proto *p = (struct radv_proto *) P;
275 struct radv_config
*cf
= (struct radv_config
*) (P
->cf
);
277 if (radv_net_match_trigger(cf
, (*new)->net
))
284 radv_rt_notify(struct proto
*P
, struct channel
*ch UNUSED
, net
*n
, rte
*new, rte
*old UNUSED
, ea_list
*attrs UNUSED
)
286 struct radv_proto
*p
= (struct radv_proto
*) P
;
287 struct radv_config
*cf
= (struct radv_config
*) (P
->cf
);
289 if (radv_net_match_trigger(cf
, n
))
291 u8 old_active
= p
->active
;
294 if (p
->active
== old_active
)
298 RADV_TRACE(D_EVENTS
, "Triggered");
300 RADV_TRACE(D_EVENTS
, "Suppressed");
302 radv_iface_notify_all(p
, RA_EV_CHANGE
);
307 radv_check_active(struct radv_proto
*p
)
309 struct radv_config
*cf
= (struct radv_config
*) (p
->p
.cf
);
311 if (!radv_trigger_valid(cf
))
314 struct channel
*c
= p
->p
.main_channel
;
315 return rt_examine(c
->table
, &cf
->trigger
, &p
->p
, c
->out_filter
);
319 radv_postconfig(struct proto_config
*CF
)
321 // struct radv_config *cf = (void *) CF;
323 /* Define default channel */
324 if (EMPTY_LIST(CF
->channels
))
325 channel_config_new(NULL
, NET_IP6
, CF
);
328 static struct proto
*
329 radv_init(struct proto_config
*CF
)
331 struct proto
*P
= proto_new(CF
);
333 P
->main_channel
= proto_add_channel(P
, proto_cf_main_channel(CF
));
335 P
->import_control
= radv_import_control
;
336 P
->rt_notify
= radv_rt_notify
;
337 P
->if_notify
= radv_if_notify
;
338 P
->ifa_notify
= radv_ifa_notify
;
344 radv_start(struct proto
*P
)
346 struct radv_proto
*p
= (struct radv_proto
*) P
;
347 struct radv_config
*cf
= (struct radv_config
*) (P
->cf
);
349 init_list(&(p
->iface_list
));
350 p
->active
= !radv_trigger_valid(cf
);
356 radv_iface_shutdown(struct radv_iface
*ifa
)
359 radv_send_ra(ifa
, 1);
363 radv_shutdown(struct proto
*P
)
365 struct radv_proto
*p
= (struct radv_proto
*) P
;
367 struct radv_iface
*ifa
;
368 WALK_LIST(ifa
, p
->iface_list
)
369 radv_iface_shutdown(ifa
);
375 radv_reconfigure(struct proto
*P
, struct proto_config
*CF
)
377 struct radv_proto
*p
= (struct radv_proto
*) P
;
378 // struct radv_config *old = (struct radv_config *) (p->cf);
379 struct radv_config
*new = (struct radv_config
*) CF
;
382 * The question is why there is a reconfigure function for RAdv if
383 * it has almost none internal state so restarting the protocol
384 * would probably suffice. One small reason is that restarting the
385 * protocol would lead to sending a RA with Router Lifetime 0
386 * causing nodes to temporary remove their default routes.
389 if (!proto_configure_channel(P
, &P
->main_channel
, proto_cf_main_channel(CF
)))
392 P
->cf
= CF
; /* radv_check_active() requires proper p->cf */
393 p
->active
= radv_check_active(p
);
396 WALK_LIST(iface
, iface_list
)
398 struct radv_iface
*ifa
= radv_iface_find(p
, iface
);
399 struct radv_iface_config
*ic
= (struct radv_iface_config
*)
400 iface_patt_find(&new->patt_list
, iface
, NULL
);
406 /* We cheat here - always notify the change even if there isn't
407 any. That would leads just to a few unnecessary RAs. */
408 radv_iface_notify(ifa
, RA_EV_CHANGE
);
413 radv_iface_shutdown(ifa
);
414 radv_iface_remove(ifa
);
418 radv_iface_new(p
, iface
, ic
);
425 radv_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
427 struct radv_config
*d
= (struct radv_config
*) dest
;
428 struct radv_config
*s
= (struct radv_config
*) src
;
430 /* We clean up patt_list, ifaces are non-sharable */
431 init_list(&d
->patt_list
);
433 /* We copy pref_list, shallow copy suffices */
434 cfg_copy_list(&d
->pref_list
, &s
->pref_list
, sizeof(struct radv_prefix_config
));
438 radv_get_status(struct proto
*P
, byte
*buf
)
440 struct radv_proto
*p
= (struct radv_proto
*) P
;
443 strcpy(buf
, "Suppressed");
446 struct protocol proto_radv
= {
448 .template = "radv%d",
449 .channel_mask
= NB_IP6
,
450 .proto_size
= sizeof(struct radv_proto
),
451 .config_size
= sizeof(struct radv_config
),
452 .postconfig
= radv_postconfig
,
455 .shutdown
= radv_shutdown
,
456 .reconfigure
= radv_reconfigure
,
457 .copy_config
= radv_copy_config
,
458 .get_status
= radv_get_status