Annotation of embedaddon/bird/proto/radv/radv.c, revision 1.1.1.2
1.1 misho 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: *
1.1.1.2 ! misho 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.
1.1 misho 19: *
1.1.1.2 ! misho 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.
1.1 misho 26: *
1.1.1.2 ! misho 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.
1.1 misho 30: *
1.1.1.2 ! misho 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.
1.1 misho 36: *
37: * Supported standards:
38: * - RFC 4861 - main RA standard
1.1.1.2 ! misho 39: * - RFC 4191 - Default Router Preferences and More-Specific Routes
1.1 misho 40: * - RFC 6106 - DNS extensions (RDDNS, DNSSL)
41: */
42:
1.1.1.2 ! misho 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:
1.1 misho 50: static void
51: radv_timer(timer *tm)
52: {
53: struct radv_iface *ifa = tm->data;
1.1.1.2 ! misho 54: struct radv_proto *p = ifa->ra;
1.1 misho 55:
56: RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
57:
1.1.1.2 ! misho 58: if (ifa->valid_time <= now)
! 59: radv_invalidate(ifa);
! 60:
! 61: if (ifa->prune_time <= now)
! 62: radv_prune_prefixes(ifa);
! 63:
! 64: if (p->prune_time <= now)
! 65: radv_prune_routes(p);
! 66:
! 67: radv_send_ra(ifa);
1.1 misho 68:
69: /* Update timer */
70: ifa->last = now;
71: unsigned after = ifa->cf->min_ra_int;
72: after += random() % (ifa->cf->max_ra_int - ifa->cf->min_ra_int + 1);
73:
74: if (ifa->initial)
75: ifa->initial--;
76:
77: if (ifa->initial)
78: after = MIN(after, MAX_INITIAL_RTR_ADVERT_INTERVAL);
79:
80: tm_start(ifa->timer, after);
81: }
82:
1.1.1.2 ! misho 83: static struct radv_prefix_config default_prefix = {
! 84: .onlink = 1,
! 85: .autonomous = 1,
! 86: .valid_lifetime = DEFAULT_VALID_LIFETIME,
! 87: .preferred_lifetime = DEFAULT_PREFERRED_LIFETIME
! 88: };
! 89:
! 90: static struct radv_prefix_config dead_prefix = {
! 91: };
! 92:
! 93: /* Find a corresponding config for the given prefix */
! 94: static struct radv_prefix_config *
! 95: radv_prefix_match(struct radv_iface *ifa, struct ifa *a)
! 96: {
! 97: struct radv_proto *p = ifa->ra;
! 98: struct radv_config *cf = (struct radv_config *) (p->p.cf);
! 99: struct radv_prefix_config *pc;
! 100:
! 101: if (a->scope <= SCOPE_LINK)
! 102: return NULL;
! 103:
! 104: WALK_LIST(pc, ifa->cf->pref_list)
! 105: if ((a->pxlen >= pc->pxlen) && ipa_in_net(a->prefix, pc->prefix, pc->pxlen))
! 106: return pc;
! 107:
! 108: WALK_LIST(pc, cf->pref_list)
! 109: if ((a->pxlen >= pc->pxlen) && ipa_in_net(a->prefix, pc->prefix, pc->pxlen))
! 110: return pc;
! 111:
! 112: return &default_prefix;
! 113: }
! 114:
! 115: /*
! 116: * Go through the list of prefixes, compare them with configs and decide if we
! 117: * want them or not.
! 118: */
! 119: static void
! 120: radv_prepare_prefixes(struct radv_iface *ifa)
! 121: {
! 122: struct radv_proto *p = ifa->ra;
! 123: struct radv_prefix *pfx, *next;
! 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: struct radv_prefix_config *pc = radv_prefix_match(ifa, addr);
! 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 ((pfx->len == addr->pxlen) && ipa_equal(pfx->prefix, addr->prefix))
! 142: {
! 143: existing = pfx;
! 144: break;
! 145: }
! 146:
! 147: if (!existing)
! 148: {
! 149: RADV_TRACE(D_EVENTS, "Adding new prefix %I/%d on %s",
! 150: addr->prefix, addr->pxlen, ifa->iface->name);
! 151:
! 152: existing = mb_allocz(ifa->pool, sizeof *existing);
! 153: existing->prefix = addr->prefix;
! 154: existing->len = addr->pxlen;
! 155: add_tail(&ifa->prefixes, NODE existing);
! 156: }
! 157:
! 158: /*
! 159: * Update the information (it may have changed, or even bring a prefix back
! 160: * to life).
! 161: */
! 162: existing->valid = 1;
! 163: existing->changed = now;
! 164: existing->mark = 1;
! 165: existing->cf = pc;
! 166: }
! 167:
! 168: WALK_LIST_DELSAFE(pfx, next, ifa->prefixes)
! 169: {
! 170: if (pfx->valid && !pfx->mark)
! 171: {
! 172: RADV_TRACE(D_EVENTS, "Invalidating prefix %I/%d on %s",
! 173: pfx->prefix, pfx->len, ifa->iface->name);
! 174:
! 175: pfx->valid = 0;
! 176: pfx->changed = now;
! 177: pfx->cf = &dead_prefix;
! 178: }
! 179: }
! 180: }
! 181:
! 182: static void
! 183: radv_prune_prefixes(struct radv_iface *ifa)
! 184: {
! 185: struct radv_proto *p = ifa->ra;
! 186: bird_clock_t next = TIME_INFINITY;
! 187: bird_clock_t 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;
! 195:
! 196: if (expires <= now)
! 197: {
! 198: RADV_TRACE(D_EVENTS, "Removing prefix %I/%d on %s",
! 199: px->prefix, px->len, 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:
1.1 misho 212: static char* ev_name[] = { NULL, "Init", "Change", "RS" };
213:
214: void
215: radv_iface_notify(struct radv_iface *ifa, int event)
216: {
1.1.1.2 ! misho 217: struct radv_proto *p = ifa->ra;
1.1 misho 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:
1.1.1.2 ! misho 227: radv_invalidate(ifa);
1.1 misho 228: case RA_EV_INIT:
229: ifa->initial = MAX_INITIAL_RTR_ADVERTISEMENTS;
1.1.1.2 ! misho 230: radv_prepare_prefixes(ifa);
! 231: radv_prune_prefixes(ifa);
1.1 misho 232: break;
233:
234: case RA_EV_RS:
235: break;
236: }
237:
238: /* Update timer */
239: unsigned delta = now - ifa->last;
240: unsigned after = 0;
241:
242: if (delta < ifa->cf->min_delay)
243: after = ifa->cf->min_delay - delta;
244:
245: tm_start(ifa->timer, after);
246: }
247:
248: static void
1.1.1.2 ! misho 249: radv_iface_notify_all(struct radv_proto *p, int event)
1.1 misho 250: {
251: struct radv_iface *ifa;
252:
1.1.1.2 ! misho 253: WALK_LIST(ifa, p->iface_list)
1.1 misho 254: radv_iface_notify(ifa, event);
255: }
256:
257: static struct radv_iface *
1.1.1.2 ! misho 258: radv_iface_find(struct radv_proto *p, struct iface *what)
1.1 misho 259: {
260: struct radv_iface *ifa;
261:
1.1.1.2 ! misho 262: WALK_LIST(ifa, p->iface_list)
1.1 misho 263: if (ifa->iface == what)
264: return ifa;
265:
266: return NULL;
267: }
268:
269: static void
270: radv_iface_add(struct object_lock *lock)
271: {
272: struct radv_iface *ifa = lock->data;
1.1.1.2 ! misho 273: struct radv_proto *p = ifa->ra;
1.1 misho 274:
275: if (! radv_sk_open(ifa))
276: {
1.1.1.2 ! misho 277: log(L_ERR "%s: Socket open failed on interface %s", p->p.name, ifa->iface->name);
1.1 misho 278: return;
279: }
280:
281: radv_iface_notify(ifa, RA_EV_INIT);
282: }
283:
284: static void
1.1.1.2 ! misho 285: radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_config *cf)
1.1 misho 286: {
287: struct radv_iface *ifa;
288:
289: RADV_TRACE(D_EVENTS, "Adding interface %s", iface->name);
290:
1.1.1.2 ! misho 291: pool *pool = rp_new(p->p.pool, iface->name);
1.1 misho 292: ifa = mb_allocz(pool, sizeof(struct radv_iface));
1.1.1.2 ! misho 293: ifa->pool = pool;
! 294: ifa->ra = p;
1.1 misho 295: ifa->cf = cf;
296: ifa->iface = iface;
1.1.1.2 ! misho 297: ifa->addr = iface->llv6;
! 298: init_list(&ifa->prefixes);
! 299: ifa->prune_time = TIME_INFINITY;
1.1 misho 300:
1.1.1.2 ! misho 301: add_tail(&p->iface_list, NODE ifa);
1.1 misho 302:
303: timer *tm = tm_new(pool);
304: tm->hook = radv_timer;
305: tm->data = ifa;
306: tm->randomize = 0;
307: tm->recurrent = 0;
308: ifa->timer = tm;
309:
310: struct object_lock *lock = olock_new(pool);
311: lock->type = OBJLOCK_IP;
312: lock->port = ICMPV6_PROTO;
313: lock->iface = iface;
314: lock->data = ifa;
315: lock->hook = radv_iface_add;
316: ifa->lock = lock;
317:
318: olock_acquire(lock);
319: }
320:
321: static void
322: radv_iface_remove(struct radv_iface *ifa)
323: {
1.1.1.2 ! misho 324: struct radv_proto *p = ifa->ra;
1.1 misho 325: RADV_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
326:
327: rem_node(NODE ifa);
328:
1.1.1.2 ! misho 329: rfree(ifa->pool);
1.1 misho 330: }
331:
332: static void
1.1.1.2 ! misho 333: radv_if_notify(struct proto *P, unsigned flags, struct iface *iface)
1.1 misho 334: {
1.1.1.2 ! misho 335: struct radv_proto *p = (struct radv_proto *) P;
! 336: struct radv_config *cf = (struct radv_config *) (P->cf);
1.1 misho 337:
338: if (iface->flags & IF_IGNORE)
339: return;
340:
341: if (flags & IF_CHANGE_UP)
342: {
343: struct radv_iface_config *ic = (struct radv_iface_config *)
344: iface_patt_find(&cf->patt_list, iface, NULL);
345:
1.1.1.2 ! misho 346: /* Ignore ifaces without link-local address */
! 347: if (!iface->llv6)
! 348: return;
! 349:
1.1 misho 350: if (ic)
1.1.1.2 ! misho 351: radv_iface_new(p, iface, ic);
1.1 misho 352:
353: return;
354: }
355:
1.1.1.2 ! misho 356: struct radv_iface *ifa = radv_iface_find(p, iface);
1.1 misho 357: if (!ifa)
358: return;
359:
360: if (flags & IF_CHANGE_DOWN)
361: {
362: radv_iface_remove(ifa);
363: return;
364: }
365:
366: if ((flags & IF_CHANGE_LINK) && (iface->flags & IF_LINK_UP))
367: radv_iface_notify(ifa, RA_EV_INIT);
368: }
369:
370: static void
1.1.1.2 ! misho 371: radv_ifa_notify(struct proto *P, unsigned flags UNUSED, struct ifa *a)
1.1 misho 372: {
1.1.1.2 ! misho 373: struct radv_proto *p = (struct radv_proto *) P;
1.1 misho 374:
375: if (a->flags & IA_SECONDARY)
376: return;
377:
378: if (a->scope <= SCOPE_LINK)
379: return;
380:
1.1.1.2 ! misho 381: struct radv_iface *ifa = radv_iface_find(p, a->iface);
1.1 misho 382:
383: if (ifa)
384: radv_iface_notify(ifa, RA_EV_CHANGE);
385: }
386:
387: static inline int radv_net_match_trigger(struct radv_config *cf, net *n)
388: {
389: return cf->trigger_valid &&
390: (n->n.pxlen == cf->trigger_pxlen) &&
391: ipa_equal(n->n.prefix, cf->trigger_prefix);
392: }
393:
394: int
1.1.1.2 ! misho 395: radv_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
1.1 misho 396: {
1.1.1.2 ! misho 397: // struct radv_proto *p = (struct radv_proto *) P;
! 398: struct radv_config *cf = (struct radv_config *) (P->cf);
1.1 misho 399:
400: if (radv_net_match_trigger(cf, (*new)->net))
401: return RIC_PROCESS;
402:
1.1.1.2 ! misho 403: if (cf->propagate_routes)
! 404: return RIC_PROCESS;
! 405: else
! 406: return RIC_DROP;
1.1 misho 407: }
408:
409: static void
1.1.1.2 ! misho 410: radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
1.1 misho 411: {
1.1.1.2 ! misho 412: struct radv_proto *p = (struct radv_proto *) P;
! 413: struct radv_config *cf = (struct radv_config *) (P->cf);
! 414: struct radv_route *rt;
! 415: eattr *ea;
1.1 misho 416:
417: if (radv_net_match_trigger(cf, n))
418: {
1.1.1.2 ! misho 419: u8 old_active = p->active;
! 420: p->active = !!new;
1.1 misho 421:
1.1.1.2 ! misho 422: if (p->active == old_active)
1.1 misho 423: return;
424:
1.1.1.2 ! misho 425: if (p->active)
1.1 misho 426: RADV_TRACE(D_EVENTS, "Triggered");
427: else
428: RADV_TRACE(D_EVENTS, "Suppressed");
429:
1.1.1.2 ! misho 430: radv_iface_notify_all(p, RA_EV_CHANGE);
! 431: return;
! 432: }
! 433:
! 434: if (!cf->propagate_routes)
! 435: return;
! 436:
! 437: /*
! 438: * Some other route we want to send (or stop sending). Update the cache,
! 439: * with marking a removed one as dead or creating a new one as needed.
! 440: *
! 441: * And yes, we exclude the trigger route on purpose.
! 442: */
! 443:
! 444: if (new)
! 445: {
! 446: /* Update */
! 447:
! 448: ea = ea_find(attrs, EA_RA_PREFERENCE);
! 449: uint preference = ea ? ea->u.data : RA_PREF_MEDIUM;
! 450: uint preference_set = !!ea;
! 451:
! 452: ea = ea_find(attrs, EA_RA_LIFETIME);
! 453: uint lifetime = ea ? ea->u.data : 0;
! 454: uint lifetime_set = !!ea;
! 455:
! 456: if ((preference != RA_PREF_LOW) &&
! 457: (preference != RA_PREF_MEDIUM) &&
! 458: (preference != RA_PREF_HIGH))
! 459: {
! 460: log(L_WARN "%s: Invalid ra_preference value %u on route %I/%d",
! 461: p->p.name, preference, n->n.prefix, n->n.pxlen);
! 462: preference = RA_PREF_MEDIUM;
! 463: preference_set = 1;
! 464: lifetime = 0;
! 465: lifetime_set = 1;
! 466: }
! 467:
! 468: rt = fib_get(&p->routes, &n->n.prefix, n->n.pxlen);
! 469:
! 470: /* Ignore update if nothing changed */
! 471: if (rt->valid &&
! 472: (rt->preference == preference) &&
! 473: (rt->preference_set == preference_set) &&
! 474: (rt->lifetime == lifetime) &&
! 475: (rt->lifetime_set == lifetime_set))
! 476: return;
! 477:
! 478: if (p->routes.entries == 18)
! 479: log(L_WARN "%s: More than 17 routes exported to RAdv", p->p.name);
! 480:
! 481: rt->valid = 1;
! 482: rt->changed = now;
! 483: rt->preference = preference;
! 484: rt->preference_set = preference_set;
! 485: rt->lifetime = lifetime;
! 486: rt->lifetime_set = lifetime_set;
1.1 misho 487: }
1.1.1.2 ! misho 488: else
! 489: {
! 490: /* Withdraw */
! 491: rt = fib_find(&p->routes, &n->n.prefix, n->n.pxlen);
! 492:
! 493: if (!rt || !rt->valid)
! 494: return;
! 495:
! 496: /* Invalidate the route */
! 497: rt->valid = 0;
! 498: rt->changed = now;
! 499:
! 500: /* Invalidated route will be pruned eventually */
! 501: bird_clock_t expires = rt->changed + cf->max_linger_time;
! 502: p->prune_time = MIN(p->prune_time, expires);
! 503: }
! 504:
! 505: radv_iface_notify_all(p, RA_EV_CHANGE);
! 506: }
! 507:
! 508: /*
! 509: * Cleans up all the dead routes that expired and schedules itself to be run
! 510: * again if there are more routes waiting for expiration.
! 511: */
! 512: static void
! 513: radv_prune_routes(struct radv_proto *p)
! 514: {
! 515: struct radv_config *cf = (struct radv_config *) (p->p.cf);
! 516: bird_clock_t next = TIME_INFINITY;
! 517: bird_clock_t 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, node)
! 528: {
! 529: struct radv_route *rt = (void *) node;
! 530:
! 531: if (!rt->valid)
! 532: {
! 533: expires = rt->changed + cf->max_linger_time;
! 534:
! 535: /* Delete expired nodes */
! 536: if (expires <= now)
! 537: {
! 538: FIB_ITERATE_PUT(&fit, node);
! 539: fib_delete(&p->routes, node);
! 540: goto again;
! 541: }
! 542: else
! 543: next = MIN(next, expires);
! 544: }
! 545: }
! 546: FIB_ITERATE_END(node);
! 547:
! 548: p->prune_time = next;
1.1 misho 549: }
550:
551: static int
1.1.1.2 ! misho 552: radv_check_active(struct radv_proto *p)
1.1 misho 553: {
1.1.1.2 ! misho 554: struct radv_config *cf = (struct radv_config *) (p->p.cf);
1.1 misho 555:
556: if (! cf->trigger_valid)
557: return 1;
558:
1.1.1.2 ! misho 559: return rt_examine(p->p.table, cf->trigger_prefix, cf->trigger_pxlen,
! 560: &(p->p), p->p.cf->out_filter);
1.1 misho 561: }
562:
563: static struct proto *
564: radv_init(struct proto_config *c)
565: {
1.1.1.2 ! misho 566: struct proto *P = proto_new(c, sizeof(struct radv_proto));
! 567:
! 568: P->accept_ra_types = RA_OPTIMAL;
! 569: P->import_control = radv_import_control;
! 570: P->rt_notify = radv_rt_notify;
! 571: P->if_notify = radv_if_notify;
! 572: P->ifa_notify = radv_ifa_notify;
! 573:
! 574: return P;
! 575: }
! 576:
! 577: static void
! 578: radv_set_fib(struct radv_proto *p, int up)
! 579: {
! 580: if (up == p->fib_up)
! 581: return;
! 582:
! 583: if (up)
! 584: fib_init(&p->routes, p->p.pool, sizeof(struct radv_route), 4, NULL);
! 585: else
! 586: fib_free(&p->routes);
1.1 misho 587:
1.1.1.2 ! misho 588: p->fib_up = up;
! 589: p->prune_time = TIME_INFINITY;
1.1 misho 590: }
591:
592: static int
1.1.1.2 ! misho 593: radv_start(struct proto *P)
1.1 misho 594: {
1.1.1.2 ! misho 595: struct radv_proto *p = (struct radv_proto *) P;
! 596: struct radv_config *cf = (struct radv_config *) (P->cf);
1.1 misho 597:
1.1.1.2 ! misho 598: init_list(&(p->iface_list));
! 599: p->valid = 1;
! 600: p->active = !cf->trigger_valid;
! 601:
! 602: p->fib_up = 0;
! 603: radv_set_fib(p, cf->propagate_routes);
! 604: p->prune_time = TIME_INFINITY;
1.1 misho 605:
606: return PS_UP;
607: }
608:
609: static inline void
610: radv_iface_shutdown(struct radv_iface *ifa)
611: {
612: if (ifa->sk)
1.1.1.2 ! misho 613: {
! 614: radv_invalidate(ifa);
! 615: radv_send_ra(ifa);
! 616: }
1.1 misho 617: }
618:
619: static int
1.1.1.2 ! misho 620: radv_shutdown(struct proto *P)
1.1 misho 621: {
1.1.1.2 ! misho 622: struct radv_proto *p = (struct radv_proto *) P;
! 623:
! 624: p->valid = 0;
1.1 misho 625:
626: struct radv_iface *ifa;
1.1.1.2 ! misho 627: WALK_LIST(ifa, p->iface_list)
1.1 misho 628: radv_iface_shutdown(ifa);
629:
630: return PS_DOWN;
631: }
632:
633: static int
1.1.1.2 ! misho 634: radv_reconfigure(struct proto *P, struct proto_config *c)
1.1 misho 635: {
1.1.1.2 ! misho 636: struct radv_proto *p = (struct radv_proto *) P;
! 637: struct radv_config *old = (struct radv_config *) (P->cf);
1.1 misho 638: struct radv_config *new = (struct radv_config *) c;
639:
1.1.1.2 ! misho 640: P->cf = c; /* radv_check_active() requires proper P->cf */
! 641: p->active = radv_check_active(p);
! 642:
! 643: /* Allocate or free FIB */
! 644: radv_set_fib(p, new->propagate_routes);
1.1 misho 645:
1.1.1.2 ! misho 646: /* We started to accept routes so we need to refeed them */
! 647: if (!old->propagate_routes && new->propagate_routes)
! 648: proto_request_feeding(&p->p);
1.1 misho 649:
650: struct iface *iface;
651: WALK_LIST(iface, iface_list)
652: {
1.1.1.2 ! misho 653: struct radv_iface *ifa = radv_iface_find(p, iface);
1.1 misho 654: struct radv_iface_config *ic = (struct radv_iface_config *)
655: iface_patt_find(&new->patt_list, iface, NULL);
656:
657: if (ifa && ic)
658: {
659: ifa->cf = ic;
660:
661: /* We cheat here - always notify the change even if there isn't
662: any. That would leads just to a few unnecessary RAs. */
663: radv_iface_notify(ifa, RA_EV_CHANGE);
664: }
665:
666: if (ifa && !ic)
667: {
668: radv_iface_shutdown(ifa);
669: radv_iface_remove(ifa);
670: }
671:
672: if (!ifa && ic)
1.1.1.2 ! misho 673: radv_iface_new(p, iface, ic);
1.1 misho 674: }
675:
676: return 1;
677: }
678:
679: static void
680: radv_copy_config(struct proto_config *dest, struct proto_config *src)
681: {
682: struct radv_config *d = (struct radv_config *) dest;
683: struct radv_config *s = (struct radv_config *) src;
684:
685: /* We clean up patt_list, ifaces are non-sharable */
686: init_list(&d->patt_list);
687:
688: /* We copy pref_list, shallow copy suffices */
689: cfg_copy_list(&d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config));
690: }
691:
692: static void
1.1.1.2 ! misho 693: radv_get_status(struct proto *P, byte *buf)
1.1 misho 694: {
1.1.1.2 ! misho 695: struct radv_proto *p = (struct radv_proto *) P;
1.1 misho 696:
1.1.1.2 ! misho 697: if (!p->active)
1.1 misho 698: strcpy(buf, "Suppressed");
699: }
700:
1.1.1.2 ! misho 701: static const char *
! 702: radv_pref_str(u32 pref)
! 703: {
! 704: switch (pref)
! 705: {
! 706: case RA_PREF_LOW:
! 707: return "low";
! 708: case RA_PREF_MEDIUM:
! 709: return "medium";
! 710: case RA_PREF_HIGH:
! 711: return "high";
! 712: default:
! 713: return "??";
! 714: }
! 715: }
! 716:
! 717: /* The buffer has some minimal size */
! 718: static int
! 719: radv_get_attr(eattr *a, byte *buf, int buflen UNUSED)
! 720: {
! 721: switch (a->id)
! 722: {
! 723: case EA_RA_PREFERENCE:
! 724: bsprintf(buf, "preference: %s", radv_pref_str(a->u.data));
! 725: return GA_FULL;
! 726: case EA_RA_LIFETIME:
! 727: bsprintf(buf, "lifetime");
! 728: return GA_NAME;
! 729: default:
! 730: return GA_UNKNOWN;
! 731: }
! 732: }
! 733:
1.1 misho 734: struct protocol proto_radv = {
735: .name = "RAdv",
736: .template = "radv%d",
1.1.1.2 ! misho 737: .attr_class = EAP_RADV,
1.1 misho 738: .config_size = sizeof(struct radv_config),
739: .init = radv_init,
740: .start = radv_start,
741: .shutdown = radv_shutdown,
742: .reconfigure = radv_reconfigure,
743: .copy_config = radv_copy_config,
1.1.1.2 ! misho 744: .get_status = radv_get_status,
! 745: .get_attr = radv_get_attr
1.1 misho 746: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>