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 import or 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 * Supported standards:
34 * - RFC 4861 - main RA standard
35 * - RFC 6106 - DNS extensions (RDDNS, DNSSL)
41 struct radv_iface
*ifa
= tm
->data
;
42 struct proto_radv
*ra
= ifa
->ra
;
44 RADV_TRACE(D_EVENTS
, "Timer fired on %s", ifa
->iface
->name
);
50 unsigned after
= ifa
->cf
->min_ra_int
;
51 after
+= random() % (ifa
->cf
->max_ra_int
- ifa
->cf
->min_ra_int
+ 1);
57 after
= MIN(after
, MAX_INITIAL_RTR_ADVERT_INTERVAL
);
59 tm_start(ifa
->timer
, after
);
62 static char* ev_name
[] = { NULL
, "Init", "Change", "RS" };
65 radv_iface_notify(struct radv_iface
*ifa
, int event
)
67 struct proto_radv
*ra
= ifa
->ra
;
72 RADV_TRACE(D_EVENTS
, "Event %s on %s", ev_name
[event
], ifa
->iface
->name
);
79 ifa
->initial
= MAX_INITIAL_RTR_ADVERTISEMENTS
;
87 unsigned delta
= now
- ifa
->last
;
90 if (delta
< ifa
->cf
->min_delay
)
91 after
= ifa
->cf
->min_delay
- delta
;
93 tm_start(ifa
->timer
, after
);
96 static struct radv_iface
*
97 radv_iface_find(struct proto_radv
*ra
, struct iface
*what
)
99 struct radv_iface
*ifa
;
101 WALK_LIST(ifa
, ra
->iface_list
)
102 if (ifa
->iface
== what
)
109 radv_iface_add(struct object_lock
*lock
)
111 struct radv_iface
*ifa
= lock
->data
;
112 struct proto_radv
*ra
= ifa
->ra
;
114 if (! radv_sk_open(ifa
))
116 log(L_ERR
"%s: Socket open failed on interface %s", ra
->p
.name
, ifa
->iface
->name
);
120 radv_iface_notify(ifa
, RA_EV_INIT
);
123 static inline struct ifa
*
124 find_lladdr(struct iface
*iface
)
127 WALK_LIST(a
, iface
->addrs
)
128 if (a
->scope
== SCOPE_LINK
)
135 radv_iface_new(struct proto_radv
*ra
, struct iface
*iface
, struct radv_iface_config
*cf
)
137 pool
*pool
= ra
->p
.pool
;
138 struct radv_iface
*ifa
;
140 RADV_TRACE(D_EVENTS
, "Adding interface %s", iface
->name
);
142 ifa
= mb_allocz(pool
, sizeof(struct radv_iface
));
147 add_tail(&ra
->iface_list
, NODE ifa
);
149 ifa
->addr
= find_lladdr(iface
);
152 log(L_ERR
"%s: Cannot find link-locad addr on interface %s", ra
->p
.name
, iface
->name
);
156 timer
*tm
= tm_new(pool
);
157 tm
->hook
= radv_timer
;
163 struct object_lock
*lock
= olock_new(pool
);
164 lock
->addr
= IPA_NONE
;
165 lock
->type
= OBJLOCK_IP
;
166 lock
->port
= ICMPV6_PROTO
;
169 lock
->hook
= radv_iface_add
;
176 radv_iface_remove(struct radv_iface
*ifa
)
178 struct proto_radv
*ra
= ifa
->ra
;
179 RADV_TRACE(D_EVENTS
, "Removing interface %s", ifa
->iface
->name
);
191 radv_if_notify(struct proto
*p
, unsigned flags
, struct iface
*iface
)
193 struct proto_radv
*ra
= (struct proto_radv
*) p
;
194 struct radv_config
*cf
= (struct radv_config
*) (p
->cf
);
196 if (iface
->flags
& IF_IGNORE
)
199 if (flags
& IF_CHANGE_UP
)
201 struct radv_iface_config
*ic
= (struct radv_iface_config
*)
202 iface_patt_find(&cf
->patt_list
, iface
, NULL
);
205 radv_iface_new(ra
, iface
, ic
);
210 struct radv_iface
*ifa
= radv_iface_find(ra
, iface
);
214 if (flags
& IF_CHANGE_DOWN
)
216 radv_iface_remove(ifa
);
220 if ((flags
& IF_CHANGE_LINK
) && (iface
->flags
& IF_LINK_UP
))
221 radv_iface_notify(ifa
, RA_EV_INIT
);
225 radv_ifa_notify(struct proto
*p
, unsigned flags
, struct ifa
*a
)
227 struct proto_radv
*ra
= (struct proto_radv
*) p
;
229 if (a
->flags
& IA_SECONDARY
)
232 if (a
->scope
<= SCOPE_LINK
)
235 struct radv_iface
*ifa
= radv_iface_find(ra
, a
->iface
);
238 radv_iface_notify(ifa
, RA_EV_CHANGE
);
241 static struct proto
*
242 radv_init(struct proto_config
*c
)
244 struct proto
*p
= proto_new(c
, sizeof(struct proto_radv
));
246 p
->if_notify
= radv_if_notify
;
247 p
->ifa_notify
= radv_ifa_notify
;
252 radv_start(struct proto
*p
)
254 struct proto_radv
*ra
= (struct proto_radv
*) p
;
255 // struct radv_config *cf = (struct radv_config *) (p->cf);
257 init_list(&(ra
->iface_list
));
263 radv_iface_shutdown(struct radv_iface
*ifa
)
266 radv_send_ra(ifa
, 1);
270 radv_shutdown(struct proto
*p
)
272 struct proto_radv
*ra
= (struct proto_radv
*) p
;
274 struct radv_iface
*ifa
;
275 WALK_LIST(ifa
, ra
->iface_list
)
276 radv_iface_shutdown(ifa
);
282 radv_reconfigure(struct proto
*p
, struct proto_config
*c
)
284 struct proto_radv
*ra
= (struct proto_radv
*) p
;
285 // struct radv_config *old = (struct radv_config *) (p->cf);
286 struct radv_config
*new = (struct radv_config
*) c
;
289 * The question is why there is a reconfigure function for RAdv if
290 * it has almost none internal state so restarting the protocol
291 * would probably suffice. One small reason is that restarting the
292 * protocol would lead to sending a RA with Router Lifetime 0
293 * causing nodes to temporary remove their default routes.
297 WALK_LIST(iface
, iface_list
)
299 struct radv_iface
*ifa
= radv_iface_find(ra
, iface
);
300 struct radv_iface_config
*ic
= (struct radv_iface_config
*)
301 iface_patt_find(&new->patt_list
, iface
, NULL
);
307 /* We cheat here - always notify the change even if there isn't
308 any. That would leads just to a few unnecessary RAs. */
309 radv_iface_notify(ifa
, RA_EV_CHANGE
);
314 radv_iface_shutdown(ifa
);
315 radv_iface_remove(ifa
);
319 radv_iface_new(ra
, iface
, ic
);
326 radv_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
328 struct radv_config
*d
= (struct radv_config
*) dest
;
329 struct radv_config
*s
= (struct radv_config
*) src
;
331 /* We clean up patt_list, ifaces are non-sharable */
332 init_list(&d
->patt_list
);
334 /* We copy pref_list, shallow copy suffices */
335 cfg_copy_list(&d
->pref_list
, &s
->pref_list
, sizeof(struct radv_prefix_config
));
339 struct protocol proto_radv
= {
341 .template = "radv%d",
344 .shutdown
= radv_shutdown
,
345 .reconfigure
= radv_reconfigure
,
346 .copy_config
= radv_copy_config