]> git.ipfire.org Git - thirdparty/bird.git/blob - proto/radv/radv.c
No more warnings ...
[thirdparty/bird.git] / proto / radv / radv.c
1 /*
2 * BIRD -- Router Advertisement
3 *
4 *
5 * Can be freely distributed and used under the terms of the GNU GPL.
6 */
7
8
9 #include <stdlib.h>
10 #include "radv.h"
11
12 /**
13 * DOC: Router Advertisements
14 *
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
18 * export any routes.
19 *
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.
26 *
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.
30 *
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.
36 *
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)
41 */
42
43 static void radv_prune_prefixes(struct radv_iface *ifa);
44 static void radv_prune_routes(struct radv_proto *p);
45
46 /* Invalidate cached RA packet */
47 static inline void radv_invalidate(struct radv_iface *ifa)
48 { ifa->plen = 0; }
49
50 static void
51 radv_timer(timer *tm)
52 {
53 struct radv_iface *ifa = tm->data;
54 struct radv_proto *p = ifa->ra;
55 btime now = current_time();
56
57 RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
58
59 if (ifa->valid_time <= now)
60 radv_invalidate(ifa);
61
62 if (ifa->prune_time <= now)
63 radv_prune_prefixes(ifa);
64
65 if (p->prune_time <= now)
66 radv_prune_routes(p);
67
68 radv_send_ra(ifa);
69
70 /* Update timer */
71 ifa->last = 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);
75
76 if (ifa->initial)
77 {
78 t = MIN(t, MAX_INITIAL_RTR_ADVERT_INTERVAL);
79 ifa->initial--;
80 }
81
82 tm_start(ifa->timer, t);
83 }
84
85 static struct radv_prefix_config default_prefix = {
86 .onlink = 1,
87 .autonomous = 1,
88 .valid_lifetime = DEFAULT_VALID_LIFETIME,
89 .preferred_lifetime = DEFAULT_PREFERRED_LIFETIME
90 };
91
92 static struct radv_prefix_config dead_prefix = {
93 };
94
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)
98 {
99 struct radv_proto *p = ifa->ra;
100 struct radv_config *cf = (struct radv_config *) (p->p.cf);
101 struct radv_prefix_config *pc;
102
103 WALK_LIST(pc, ifa->cf->pref_list)
104 if (net_in_net_ip6(px, &pc->prefix))
105 return pc;
106
107 WALK_LIST(pc, cf->pref_list)
108 if (net_in_net_ip6(px, &pc->prefix))
109 return pc;
110
111 return &default_prefix;
112 }
113
114 /*
115 * Go through the list of prefixes, compare them with configs and decide if we
116 * want them or not.
117 */
118 static void
119 radv_prepare_prefixes(struct radv_iface *ifa)
120 {
121 struct radv_proto *p = ifa->ra;
122 struct radv_prefix *pfx, *next;
123 btime now = current_time();
124
125 /* First mark all the prefixes as unused */
126 WALK_LIST(pfx, ifa->prefixes)
127 pfx->mark = 0;
128
129 /* Find all the prefixes we want to use and make sure they are in the list. */
130 struct ifa *addr;
131 WALK_LIST(addr, ifa->iface->addrs)
132 {
133 if ((addr->prefix.type != NET_IP6) ||
134 (addr->scope <= SCOPE_LINK))
135 continue;
136
137 net_addr_ip6 *prefix = (void *) &addr->prefix;
138 struct radv_prefix_config *pc = radv_prefix_match(ifa, prefix);
139
140 if (!pc || pc->skip)
141 continue;
142
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))
147 {
148 existing = pfx;
149 break;
150 }
151
152 if (!existing)
153 {
154 RADV_TRACE(D_EVENTS, "Adding new prefix %N on %s",
155 prefix, ifa->iface->name);
156
157 existing = mb_allocz(ifa->pool, sizeof *existing);
158 net_copy_ip6(&existing->prefix, prefix);
159 add_tail(&ifa->prefixes, NODE existing);
160 }
161
162 /*
163 * Update the information (it may have changed, or even bring a prefix back
164 * to life).
165 */
166 existing->valid = 1;
167 existing->changed = now;
168 existing->mark = 1;
169 existing->cf = pc;
170 }
171
172 WALK_LIST_DELSAFE(pfx, next, ifa->prefixes)
173 {
174 if (pfx->valid && !pfx->mark)
175 {
176 RADV_TRACE(D_EVENTS, "Invalidating prefix %N on %s",
177 &pfx->prefix, ifa->iface->name);
178
179 pfx->valid = 0;
180 pfx->changed = now;
181 pfx->cf = &dead_prefix;
182 }
183 }
184 }
185
186 static void
187 radv_prune_prefixes(struct radv_iface *ifa)
188 {
189 struct radv_proto *p = ifa->ra;
190 btime now = current_time();
191 btime next = TIME_INFINITY;
192 btime expires = 0;
193
194 struct radv_prefix *px, *pxn;
195 WALK_LIST_DELSAFE(px, pxn, ifa->prefixes)
196 {
197 if (!px->valid)
198 {
199 expires = px->changed + ifa->cf->prefix_linger_time S;
200
201 if (expires <= now)
202 {
203 RADV_TRACE(D_EVENTS, "Removing prefix %N on %s",
204 &px->prefix, ifa->iface->name);
205
206 rem_node(NODE px);
207 mb_free(px);
208 }
209 else
210 next = MIN(next, expires);
211 }
212 }
213
214 ifa->prune_time = next;
215 }
216
217 static char* ev_name[] = { NULL, "Init", "Change", "RS" };
218
219 void
220 radv_iface_notify(struct radv_iface *ifa, int event)
221 {
222 struct radv_proto *p = ifa->ra;
223
224 if (!ifa->sk)
225 return;
226
227 RADV_TRACE(D_EVENTS, "Event %s on %s", ev_name[event], ifa->iface->name);
228
229 switch (event)
230 {
231 case RA_EV_CHANGE:
232 radv_invalidate(ifa);
233 /* fallthrough */
234 case RA_EV_INIT:
235 ifa->initial = MAX_INITIAL_RTR_ADVERTISEMENTS;
236 radv_prepare_prefixes(ifa);
237 radv_prune_prefixes(ifa);
238 break;
239
240 case RA_EV_RS:
241 break;
242 }
243
244 /* Update timer */
245 btime t = ifa->last + ifa->cf->min_delay S - current_time();
246 tm_start(ifa->timer, t);
247 }
248
249 static void
250 radv_iface_notify_all(struct radv_proto *p, int event)
251 {
252 struct radv_iface *ifa;
253
254 WALK_LIST(ifa, p->iface_list)
255 radv_iface_notify(ifa, event);
256 }
257
258 static struct radv_iface *
259 radv_iface_find(struct radv_proto *p, struct iface *what)
260 {
261 struct radv_iface *ifa;
262
263 WALK_LIST(ifa, p->iface_list)
264 if (ifa->iface == what)
265 return ifa;
266
267 return NULL;
268 }
269
270 static void
271 radv_iface_add(struct object_lock *lock)
272 {
273 struct radv_iface *ifa = lock->data;
274 struct radv_proto *p = ifa->ra;
275
276 if (! radv_sk_open(ifa))
277 {
278 log(L_ERR "%s: Socket open failed on interface %s", p->p.name, ifa->iface->name);
279 return;
280 }
281
282 radv_iface_notify(ifa, RA_EV_INIT);
283 }
284
285 static void
286 radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_config *cf)
287 {
288 struct radv_iface *ifa;
289
290 RADV_TRACE(D_EVENTS, "Adding interface %s", iface->name);
291
292 pool *pool = rp_new(p->p.pool, iface->name);
293 ifa = mb_allocz(pool, sizeof(struct radv_iface));
294 ifa->pool = pool;
295 ifa->ra = p;
296 ifa->cf = cf;
297 ifa->iface = iface;
298 ifa->addr = iface->llv6;
299 init_list(&ifa->prefixes);
300 ifa->prune_time = TIME_INFINITY;
301
302 add_tail(&p->iface_list, NODE ifa);
303
304 ifa->timer = tm_new_init(pool, radv_timer, ifa, 0, 0);
305
306 struct object_lock *lock = olock_new(pool);
307 lock->type = OBJLOCK_IP;
308 lock->port = ICMPV6_PROTO;
309 lock->iface = iface;
310 lock->data = ifa;
311 lock->hook = radv_iface_add;
312 ifa->lock = lock;
313
314 olock_acquire(lock);
315 }
316
317 static void
318 radv_iface_remove(struct radv_iface *ifa)
319 {
320 struct radv_proto *p = ifa->ra;
321 RADV_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
322
323 rem_node(NODE ifa);
324
325 rfree(ifa->pool);
326 }
327
328 static void
329 radv_if_notify(struct proto *P, unsigned flags, struct iface *iface)
330 {
331 struct radv_proto *p = (struct radv_proto *) P;
332 struct radv_config *cf = (struct radv_config *) (P->cf);
333
334 if (iface->flags & IF_IGNORE)
335 return;
336
337 if (flags & IF_CHANGE_UP)
338 {
339 struct radv_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
340
341 /* Ignore non-multicast ifaces */
342 if (!(iface->flags & IF_MULTICAST))
343 return;
344
345 /* Ignore ifaces without link-local address */
346 if (!iface->llv6)
347 return;
348
349 if (ic)
350 radv_iface_new(p, iface, ic);
351
352 return;
353 }
354
355 struct radv_iface *ifa = radv_iface_find(p, iface);
356 if (!ifa)
357 return;
358
359 if (flags & IF_CHANGE_DOWN)
360 {
361 radv_iface_remove(ifa);
362 return;
363 }
364
365 if ((flags & IF_CHANGE_LINK) && (iface->flags & IF_LINK_UP))
366 radv_iface_notify(ifa, RA_EV_INIT);
367 }
368
369 static void
370 radv_ifa_notify(struct proto *P, unsigned flags UNUSED, struct ifa *a)
371 {
372 struct radv_proto *p = (struct radv_proto *) P;
373
374 if (a->flags & IA_SECONDARY)
375 return;
376
377 if (a->scope <= SCOPE_LINK)
378 return;
379
380 struct radv_iface *ifa = radv_iface_find(p, a->iface);
381
382 if (ifa)
383 radv_iface_notify(ifa, RA_EV_CHANGE);
384 }
385
386 static inline int
387 radv_trigger_valid(struct radv_config *cf)
388 {
389 return cf->trigger.type != 0;
390 }
391
392 static inline int
393 radv_net_match_trigger(struct radv_config *cf, net *n)
394 {
395 return radv_trigger_valid(cf) && net_equal(n->n.addr, &cf->trigger);
396 }
397
398 int
399 radv_import_control(struct proto *P, rte **new, struct linpool *pool UNUSED)
400 {
401 // struct radv_proto *p = (struct radv_proto *) P;
402 struct radv_config *cf = (struct radv_config *) (P->cf);
403
404 if (radv_net_match_trigger(cf, (*new)->net))
405 return RIC_PROCESS;
406
407 if (cf->propagate_routes)
408 return RIC_PROCESS;
409 else
410 return RIC_DROP;
411 }
412
413 static void
414 radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED)
415 {
416 struct radv_proto *p = (struct radv_proto *) P;
417 struct radv_config *cf = (struct radv_config *) (P->cf);
418 struct radv_route *rt;
419 eattr *ea;
420
421 if (radv_net_match_trigger(cf, n))
422 {
423 u8 old_active = p->active;
424 p->active = !!new;
425
426 if (p->active == old_active)
427 return;
428
429 if (p->active)
430 RADV_TRACE(D_EVENTS, "Triggered");
431 else
432 RADV_TRACE(D_EVENTS, "Suppressed");
433
434 radv_iface_notify_all(p, RA_EV_CHANGE);
435 return;
436 }
437
438 if (!cf->propagate_routes)
439 return;
440
441 /*
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.
444 *
445 * And yes, we exclude the trigger route on purpose.
446 */
447
448 if (new)
449 {
450 /* Update */
451
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;
455
456 ea = ea_find(new->attrs->eattrs, EA_RA_LIFETIME);
457 uint lifetime = ea ? ea->u.data : 0;
458 uint lifetime_set = !!ea;
459
460 if ((preference != RA_PREF_LOW) &&
461 (preference != RA_PREF_MEDIUM) &&
462 (preference != RA_PREF_HIGH))
463 {
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;
467 preference_set = 1;
468 lifetime = 0;
469 lifetime_set = 1;
470 }
471
472 rt = fib_get(&p->routes, n->n.addr);
473
474 /* Ignore update if nothing changed */
475 if (rt->valid &&
476 (rt->preference == preference) &&
477 (rt->preference_set == preference_set) &&
478 (rt->lifetime == lifetime) &&
479 (rt->lifetime_set == lifetime_set))
480 return;
481
482 if (p->routes.entries == 18)
483 log(L_WARN "%s: More than 17 routes exported to RAdv", p->p.name);
484
485 rt->valid = 1;
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;
491 }
492 else
493 {
494 /* Withdraw */
495 rt = fib_find(&p->routes, n->n.addr);
496
497 if (!rt || !rt->valid)
498 return;
499
500 /* Invalidate the route */
501 rt->valid = 0;
502 rt->changed = current_time();
503
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);
507 }
508
509 radv_iface_notify_all(p, RA_EV_CHANGE);
510 }
511
512 /*
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.
515 */
516 static void
517 radv_prune_routes(struct radv_proto *p)
518 {
519 struct radv_config *cf = (struct radv_config *) (p->p.cf);
520 btime now = current_time();
521 btime next = TIME_INFINITY;
522 btime expires = 0;
523
524 /* Should not happen */
525 if (!p->fib_up)
526 return;
527
528 struct fib_iterator fit;
529 FIB_ITERATE_INIT(&fit, &p->routes);
530
531 again:
532 FIB_ITERATE_START(&p->routes, &fit, struct radv_route, rt)
533 {
534 if (!rt->valid)
535 {
536 expires = rt->changed + cf->max_linger_time S;
537
538 /* Delete expired nodes */
539 if (expires <= now)
540 {
541 FIB_ITERATE_PUT(&fit);
542 fib_delete(&p->routes, rt);
543 goto again;
544 }
545 else
546 next = MIN(next, expires);
547 }
548 }
549 FIB_ITERATE_END;
550
551 p->prune_time = next;
552 }
553
554 static int
555 radv_check_active(struct radv_proto *p)
556 {
557 struct radv_config *cf = (struct radv_config *) (p->p.cf);
558
559 if (!radv_trigger_valid(cf))
560 return 1;
561
562 struct channel *c = p->p.main_channel;
563 return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter);
564 }
565
566 static void
567 radv_postconfig(struct proto_config *CF)
568 {
569 // struct radv_config *cf = (void *) CF;
570
571 /* Define default channel */
572 if (EMPTY_LIST(CF->channels))
573 channel_config_new(NULL, net_label[NET_IP6], NET_IP6, CF);
574 }
575
576 static struct proto *
577 radv_init(struct proto_config *CF)
578 {
579 struct proto *P = proto_new(CF);
580
581 P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
582
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;
587
588 return P;
589 }
590
591 static void
592 radv_set_fib(struct radv_proto *p, int up)
593 {
594 if (up == p->fib_up)
595 return;
596
597 if (up)
598 fib_init(&p->routes, p->p.pool, NET_IP6, sizeof(struct radv_route),
599 OFFSETOF(struct radv_route, n), 4, NULL);
600 else
601 fib_free(&p->routes);
602
603 p->fib_up = up;
604 p->prune_time = TIME_INFINITY;
605 }
606
607 static int
608 radv_start(struct proto *P)
609 {
610 struct radv_proto *p = (struct radv_proto *) P;
611 struct radv_config *cf = (struct radv_config *) (P->cf);
612
613 init_list(&(p->iface_list));
614 p->valid = 1;
615 p->active = !radv_trigger_valid(cf);
616
617 p->fib_up = 0;
618 radv_set_fib(p, cf->propagate_routes);
619 p->prune_time = TIME_INFINITY;
620
621 return PS_UP;
622 }
623
624 static inline void
625 radv_iface_shutdown(struct radv_iface *ifa)
626 {
627 if (ifa->sk)
628 {
629 radv_invalidate(ifa);
630 radv_send_ra(ifa);
631 }
632 }
633
634 static int
635 radv_shutdown(struct proto *P)
636 {
637 struct radv_proto *p = (struct radv_proto *) P;
638
639 p->valid = 0;
640
641 struct radv_iface *ifa;
642 WALK_LIST(ifa, p->iface_list)
643 radv_iface_shutdown(ifa);
644
645 return PS_DOWN;
646 }
647
648 static int
649 radv_reconfigure(struct proto *P, struct proto_config *CF)
650 {
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;
654
655 if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
656 return 0;
657
658 P->cf = CF; /* radv_check_active() requires proper P->cf */
659 p->active = radv_check_active(p);
660
661 /* Allocate or free FIB */
662 radv_set_fib(p, new->propagate_routes);
663
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);
667
668 struct iface *iface;
669 WALK_LIST(iface, iface_list)
670 {
671 if (!(iface->flags & IF_UP))
672 continue;
673
674 /* Ignore non-multicast ifaces */
675 if (!(iface->flags & IF_MULTICAST))
676 continue;
677
678 /* Ignore ifaces without link-local address */
679 if (!iface->llv6)
680 continue;
681
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);
685
686 if (ifa && ic)
687 {
688 ifa->cf = ic;
689
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);
693 }
694
695 if (ifa && !ic)
696 {
697 radv_iface_shutdown(ifa);
698 radv_iface_remove(ifa);
699 }
700
701 if (!ifa && ic)
702 radv_iface_new(p, iface, ic);
703 }
704
705 return 1;
706 }
707
708 static void
709 radv_copy_config(struct proto_config *dest, struct proto_config *src)
710 {
711 struct radv_config *d = (struct radv_config *) dest;
712 struct radv_config *s = (struct radv_config *) src;
713
714 /* We clean up patt_list, ifaces are non-sharable */
715 init_list(&d->patt_list);
716
717 /* We copy pref_list, shallow copy suffices */
718 cfg_copy_list(&d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config));
719 }
720
721 static void
722 radv_get_status(struct proto *P, byte *buf)
723 {
724 struct radv_proto *p = (struct radv_proto *) P;
725
726 if (!p->active)
727 strcpy(buf, "Suppressed");
728 }
729
730 static const char *
731 radv_pref_str(u32 pref)
732 {
733 switch (pref)
734 {
735 case RA_PREF_LOW:
736 return "low";
737 case RA_PREF_MEDIUM:
738 return "medium";
739 case RA_PREF_HIGH:
740 return "high";
741 default:
742 return "??";
743 }
744 }
745
746 /* The buffer has some minimal size */
747 static int
748 radv_get_attr(eattr *a, byte *buf, int buflen UNUSED)
749 {
750 switch (a->id)
751 {
752 case EA_RA_PREFERENCE:
753 bsprintf(buf, "preference: %s", radv_pref_str(a->u.data));
754 return GA_FULL;
755 case EA_RA_LIFETIME:
756 bsprintf(buf, "lifetime");
757 return GA_NAME;
758 default:
759 return GA_UNKNOWN;
760 }
761 }
762
763 struct protocol proto_radv = {
764 .name = "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,
771 .init = radv_init,
772 .start = radv_start,
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
778 };