diff options
Diffstat (limited to 'proto/radv/radv.c')
-rw-r--r-- | proto/radv/radv.c | 200 |
1 files changed, 109 insertions, 91 deletions
diff --git a/proto/radv/radv.c b/proto/radv/radv.c index 7e8950c5..8a79dfaf 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -52,6 +52,7 @@ radv_timer(timer *tm) { struct radv_iface *ifa = tm->data; struct radv_proto *p = ifa->ra; + btime now = current_time(); RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name); @@ -68,16 +69,17 @@ radv_timer(timer *tm) /* Update timer */ ifa->last = now; - unsigned after = ifa->cf->min_ra_int; - after += random() % (ifa->cf->max_ra_int - ifa->cf->min_ra_int + 1); + btime t = ifa->cf->min_ra_int S; + btime r = (ifa->cf->max_ra_int - ifa->cf->min_ra_int) S; + t += random() % (r + 1); if (ifa->initial) + { + t = MIN(t, MAX_INITIAL_RTR_ADVERT_INTERVAL); ifa->initial--; + } - if (ifa->initial) - after = MIN(after, MAX_INITIAL_RTR_ADVERT_INTERVAL); - - tm_start(ifa->timer, after); + tm_start(ifa->timer, t); } static struct radv_prefix_config default_prefix = { @@ -92,21 +94,18 @@ static struct radv_prefix_config dead_prefix = { /* Find a corresponding config for the given prefix */ static struct radv_prefix_config * -radv_prefix_match(struct radv_iface *ifa, struct ifa *a) +radv_prefix_match(struct radv_iface *ifa, net_addr_ip6 *px) { struct radv_proto *p = ifa->ra; struct radv_config *cf = (struct radv_config *) (p->p.cf); struct radv_prefix_config *pc; - if (a->scope <= SCOPE_LINK) - return NULL; - WALK_LIST(pc, ifa->cf->pref_list) - if ((a->pxlen >= pc->pxlen) && ipa_in_net(a->prefix, pc->prefix, pc->pxlen)) + if (net_in_net_ip6(px, &pc->prefix)) return pc; WALK_LIST(pc, cf->pref_list) - if ((a->pxlen >= pc->pxlen) && ipa_in_net(a->prefix, pc->prefix, pc->pxlen)) + if (net_in_net_ip6(px, &pc->prefix)) return pc; return &default_prefix; @@ -121,6 +120,7 @@ radv_prepare_prefixes(struct radv_iface *ifa) { struct radv_proto *p = ifa->ra; struct radv_prefix *pfx, *next; + btime now = current_time(); /* First mark all the prefixes as unused */ WALK_LIST(pfx, ifa->prefixes) @@ -130,7 +130,12 @@ radv_prepare_prefixes(struct radv_iface *ifa) struct ifa *addr; WALK_LIST(addr, ifa->iface->addrs) { - struct radv_prefix_config *pc = radv_prefix_match(ifa, addr); + if ((addr->prefix.type != NET_IP6) || + (addr->scope <= SCOPE_LINK)) + continue; + + net_addr_ip6 *prefix = (void *) &addr->prefix; + struct radv_prefix_config *pc = radv_prefix_match(ifa, prefix); if (!pc || pc->skip) continue; @@ -138,7 +143,7 @@ radv_prepare_prefixes(struct radv_iface *ifa) /* Do we have it already? */ struct radv_prefix *existing = NULL; WALK_LIST(pfx, ifa->prefixes) - if ((pfx->len == addr->pxlen) && ipa_equal(pfx->prefix, addr->prefix)) + if (net_equal_ip6(&pfx->prefix, prefix)) { existing = pfx; break; @@ -146,12 +151,11 @@ radv_prepare_prefixes(struct radv_iface *ifa) if (!existing) { - RADV_TRACE(D_EVENTS, "Adding new prefix %I/%d on %s", - addr->prefix, addr->pxlen, ifa->iface->name); + RADV_TRACE(D_EVENTS, "Adding new prefix %N on %s", + prefix, ifa->iface->name); existing = mb_allocz(ifa->pool, sizeof *existing); - existing->prefix = addr->prefix; - existing->len = addr->pxlen; + net_copy_ip6(&existing->prefix, prefix); add_tail(&ifa->prefixes, NODE existing); } @@ -169,8 +173,8 @@ radv_prepare_prefixes(struct radv_iface *ifa) { if (pfx->valid && !pfx->mark) { - RADV_TRACE(D_EVENTS, "Invalidating prefix %I/%d on %s", - pfx->prefix, pfx->len, ifa->iface->name); + RADV_TRACE(D_EVENTS, "Invalidating prefix %N on %s", + pfx->prefix, ifa->iface->name); pfx->valid = 0; pfx->changed = now; @@ -183,20 +187,21 @@ static void radv_prune_prefixes(struct radv_iface *ifa) { struct radv_proto *p = ifa->ra; - bird_clock_t next = TIME_INFINITY; - bird_clock_t expires = 0; + btime now = current_time(); + btime next = TIME_INFINITY; + btime expires = 0; struct radv_prefix *px, *pxn; WALK_LIST_DELSAFE(px, pxn, ifa->prefixes) { if (!px->valid) { - expires = px->changed + ifa->cf->prefix_linger_time; + expires = px->changed + ifa->cf->prefix_linger_time S; if (expires <= now) { - RADV_TRACE(D_EVENTS, "Removing prefix %I/%d on %s", - px->prefix, px->len, ifa->iface->name); + RADV_TRACE(D_EVENTS, "Removing prefix %N on %s", + px->prefix, ifa->iface->name); rem_node(NODE px); mb_free(px); @@ -236,13 +241,8 @@ radv_iface_notify(struct radv_iface *ifa, int event) } /* Update timer */ - unsigned delta = now - ifa->last; - unsigned after = 0; - - if (delta < ifa->cf->min_delay) - after = ifa->cf->min_delay - delta; - - tm_start(ifa->timer, after); + btime t = ifa->last + ifa->cf->min_delay S - current_time(); + tm_start(ifa->timer, t); } static void @@ -281,17 +281,6 @@ radv_iface_add(struct object_lock *lock) radv_iface_notify(ifa, RA_EV_INIT); } -static inline struct ifa * -find_lladdr(struct iface *iface) -{ - struct ifa *a; - WALK_LIST(a, iface->addrs) - if (a->scope == SCOPE_LINK) - return a; - - return NULL; -} - static void radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_config *cf) { @@ -305,24 +294,13 @@ radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_conf ifa->ra = p; ifa->cf = cf; ifa->iface = iface; + ifa->addr = iface->llv6; init_list(&ifa->prefixes); ifa->prune_time = TIME_INFINITY; add_tail(&p->iface_list, NODE ifa); - ifa->addr = find_lladdr(iface); - if (!ifa->addr) - { - log(L_ERR "%s: Missing link-local address on interface %s", p->p.name, iface->name); - return; - } - - timer *tm = tm_new(pool); - tm->hook = radv_timer; - tm->data = ifa; - tm->randomize = 0; - tm->recurrent = 0; - ifa->timer = tm; + ifa->timer = tm_new_init(pool, radv_timer, ifa, 0, 0); struct object_lock *lock = olock_new(pool); lock->type = OBJLOCK_IP; @@ -357,8 +335,15 @@ radv_if_notify(struct proto *P, unsigned flags, struct iface *iface) if (flags & IF_CHANGE_UP) { - struct radv_iface_config *ic = (struct radv_iface_config *) - iface_patt_find(&cf->patt_list, iface, NULL); + struct radv_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL); + + /* Ignore non-multicast ifaces */ + if (!(iface->flags & IF_MULTICAST)) + return; + + /* Ignore ifaces without link-local address */ + if (!iface->llv6) + return; if (ic) radv_iface_new(p, iface, ic); @@ -397,11 +382,16 @@ radv_ifa_notify(struct proto *P, unsigned flags UNUSED, struct ifa *a) radv_iface_notify(ifa, RA_EV_CHANGE); } -static inline int radv_net_match_trigger(struct radv_config *cf, net *n) +static inline int +radv_trigger_valid(struct radv_config *cf) +{ + return cf->trigger.type != 0; +} + +static inline int +radv_net_match_trigger(struct radv_config *cf, net *n) { - return cf->trigger_valid && - (n->n.pxlen == cf->trigger_pxlen) && - ipa_equal(n->n.prefix, cf->trigger_prefix); + return radv_trigger_valid(cf) && net_equal(n->n.addr, &cf->trigger); } int @@ -420,7 +410,7 @@ radv_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct l } static void -radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs) +radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs) { struct radv_proto *p = (struct radv_proto *) P; struct radv_config *cf = (struct radv_config *) (P->cf); @@ -470,15 +460,15 @@ radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U (preference != RA_PREF_MEDIUM) && (preference != RA_PREF_HIGH)) { - log(L_WARN "%s: Invalid ra_preference value %u on route %I/%d", - p->p.name, preference, n->n.prefix, n->n.pxlen); + log(L_WARN "%s: Invalid ra_preference value %u on route %N", + p->p.name, preference, n->n.addr); preference = RA_PREF_MEDIUM; preference_set = 1; lifetime = 0; lifetime_set = 1; } - rt = fib_get(&p->routes, &n->n.prefix, n->n.pxlen); + rt = fib_get(&p->routes, n->n.addr); /* Ignore update if nothing changed */ if (rt->valid && @@ -492,7 +482,7 @@ radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U log(L_WARN "%s: More than 17 routes exported to RAdv", p->p.name); rt->valid = 1; - rt->changed = now; + rt->changed = current_time(); rt->preference = preference; rt->preference_set = preference_set; rt->lifetime = lifetime; @@ -501,17 +491,17 @@ radv_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old U else { /* Withdraw */ - rt = fib_find(&p->routes, &n->n.prefix, n->n.pxlen); + rt = fib_find(&p->routes, n->n.addr); if (!rt || !rt->valid) return; /* Invalidate the route */ rt->valid = 0; - rt->changed = now; + rt->changed = current_time(); /* Invalidated route will be pruned eventually */ - bird_clock_t expires = rt->changed + cf->max_linger_time; + btime expires = rt->changed + cf->max_linger_time S; p->prune_time = MIN(p->prune_time, expires); } @@ -526,8 +516,9 @@ static void radv_prune_routes(struct radv_proto *p) { struct radv_config *cf = (struct radv_config *) (p->p.cf); - bird_clock_t next = TIME_INFINITY; - bird_clock_t expires = 0; + btime now = current_time(); + btime next = TIME_INFINITY; + btime expires = 0; /* Should not happen */ if (!p->fib_up) @@ -537,26 +528,24 @@ radv_prune_routes(struct radv_proto *p) FIB_ITERATE_INIT(&fit, &p->routes); again: - FIB_ITERATE_START(&p->routes, &fit, node) + FIB_ITERATE_START(&p->routes, &fit, struct radv_route, rt) { - struct radv_route *rt = (void *) node; - if (!rt->valid) { - expires = rt->changed + cf->max_linger_time; + expires = rt->changed + cf->max_linger_time S; /* Delete expired nodes */ if (expires <= now) { - FIB_ITERATE_PUT(&fit, node); - fib_delete(&p->routes, node); + FIB_ITERATE_PUT(&fit); + fib_delete(&p->routes, rt); goto again; } else next = MIN(next, expires); } } - FIB_ITERATE_END(node); + FIB_ITERATE_END; p->prune_time = next; } @@ -566,19 +555,30 @@ radv_check_active(struct radv_proto *p) { struct radv_config *cf = (struct radv_config *) (p->p.cf); - if (! cf->trigger_valid) + if (!radv_trigger_valid(cf)) return 1; - return rt_examine(p->p.table, cf->trigger_prefix, cf->trigger_pxlen, - &(p->p), p->p.cf->out_filter); + struct channel *c = p->p.main_channel; + return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter); +} + +static void +radv_postconfig(struct proto_config *CF) +{ + // struct radv_config *cf = (void *) CF; + + /* Define default channel */ + if (EMPTY_LIST(CF->channels)) + channel_config_new(NULL, net_label[NET_IP6], NET_IP6, CF); } static struct proto * -radv_init(struct proto_config *c) +radv_init(struct proto_config *CF) { - struct proto *P = proto_new(c, sizeof(struct radv_proto)); + struct proto *P = proto_new(CF); + + P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF)); - P->accept_ra_types = RA_OPTIMAL; P->import_control = radv_import_control; P->rt_notify = radv_rt_notify; P->if_notify = radv_if_notify; @@ -594,7 +594,8 @@ radv_set_fib(struct radv_proto *p, int up) return; if (up) - fib_init(&p->routes, p->p.pool, sizeof(struct radv_route), 4, NULL); + fib_init(&p->routes, p->p.pool, NET_IP6, sizeof(struct radv_route), + OFFSETOF(struct radv_route, n), 4, NULL); else fib_free(&p->routes); @@ -610,7 +611,7 @@ radv_start(struct proto *P) init_list(&(p->iface_list)); p->valid = 1; - p->active = !cf->trigger_valid; + p->active = !radv_trigger_valid(cf); p->fib_up = 0; radv_set_fib(p, cf->propagate_routes); @@ -644,13 +645,16 @@ radv_shutdown(struct proto *P) } static int -radv_reconfigure(struct proto *P, struct proto_config *c) +radv_reconfigure(struct proto *P, struct proto_config *CF) { struct radv_proto *p = (struct radv_proto *) P; struct radv_config *old = (struct radv_config *) (P->cf); - struct radv_config *new = (struct radv_config *) c; + struct radv_config *new = (struct radv_config *) CF; - P->cf = c; /* radv_check_active() requires proper P->cf */ + if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF))) + return 0; + + P->cf = CF; /* radv_check_active() requires proper P->cf */ p->active = radv_check_active(p); /* Allocate or free FIB */ @@ -658,11 +662,22 @@ radv_reconfigure(struct proto *P, struct proto_config *c) /* We started to accept routes so we need to refeed them */ if (!old->propagate_routes && new->propagate_routes) - proto_request_feeding(&p->p); + channel_request_feeding(p->p.main_channel); struct iface *iface; WALK_LIST(iface, iface_list) { + if (!(iface->flags & IF_UP)) + continue; + + /* Ignore non-multicast ifaces */ + if (!(iface->flags & IF_MULTICAST)) + continue; + + /* Ignore ifaces without link-local address */ + if (!iface->llv6) + continue; + struct radv_iface *ifa = radv_iface_find(p, iface); struct radv_iface_config *ic = (struct radv_iface_config *) iface_patt_find(&new->patt_list, iface, NULL); @@ -748,7 +763,10 @@ struct protocol proto_radv = { .name = "RAdv", .template = "radv%d", .attr_class = EAP_RADV, + .channel_mask = NB_IP6, + .proto_size = sizeof(struct radv_proto), .config_size = sizeof(struct radv_config), + .postconfig = radv_postconfig, .init = radv_init, .start = radv_start, .shutdown = radv_shutdown, |