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