diff options
Diffstat (limited to 'proto/radv')
-rw-r--r-- | proto/radv/Makefile | 9 | ||||
-rw-r--r-- | proto/radv/config.Y | 45 | ||||
-rw-r--r-- | proto/radv/packets.c | 42 | ||||
-rw-r--r-- | proto/radv/radv.c | 200 | ||||
-rw-r--r-- | proto/radv/radv.h | 30 |
5 files changed, 169 insertions, 157 deletions
diff --git a/proto/radv/Makefile b/proto/radv/Makefile index efc4d4af..05317eff 100644 --- a/proto/radv/Makefile +++ b/proto/radv/Makefile @@ -1,5 +1,6 @@ -source=radv.c packets.c -root-rel=../../ -dir-name=proto/radv +src := packets.c radv.c +obj := $(src-o-files) +$(all-daemon) +$(cf-local) -include ../../Rules +tests_objs := $(tests_objs) $(src-o-files)
\ No newline at end of file diff --git a/proto/radv/config.Y b/proto/radv/config.Y index 84a2de0e..37815f0d 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -44,6 +44,7 @@ CF_ADDTO(proto, radv_proto) radv_proto_start: proto_start RADV { this_proto = proto_config_new(&proto_radv, $1); + init_list(&RADV_CFG->patt_list); init_list(&RADV_CFG->pref_list); init_list(&RADV_CFG->rdnss_list); @@ -52,15 +53,12 @@ radv_proto_start: proto_start RADV radv_proto_item: proto_item + | proto_channel | INTERFACE radv_iface | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); } | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); } | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); } - | TRIGGER prefix { - RADV_CFG->trigger_prefix = $2.addr; - RADV_CFG->trigger_pxlen = $2.len; - RADV_CFG->trigger_valid = 1; - } + | TRIGGER net_ip6 { RADV_CFG->trigger = $2; } | PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; } ; @@ -82,16 +80,16 @@ radv_iface_start: init_list(&RADV_IFACE->rdnss_list); init_list(&RADV_IFACE->dnssl_list); - RADV_IFACE->min_ra_int = -1; /* undefined */ + RADV_IFACE->min_ra_int = (u32) -1; /* undefined */ RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT; RADV_IFACE->min_delay = DEFAULT_MIN_DELAY; - RADV_IFACE->prefix_linger_time = -1; - RADV_IFACE->route_linger_time = -1; + RADV_IFACE->prefix_linger_time = (u32) -1; + RADV_IFACE->route_linger_time = (u32) -1; RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT; - RADV_IFACE->default_lifetime = -1; + RADV_IFACE->default_lifetime = (u32) -1; RADV_IFACE->default_lifetime_sensitive = 1; RADV_IFACE->default_preference = RA_PREF_MEDIUM; - RADV_IFACE->route_lifetime = -1; + RADV_IFACE->route_lifetime = (u32) -1; RADV_IFACE->route_lifetime_sensitive = 0; RADV_IFACE->route_preference = RA_PREF_MEDIUM; }; @@ -102,18 +100,18 @@ radv_iface_item: | MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error("Min delay must be positive"); } | MANAGED bool { RADV_IFACE->managed = $2; } | OTHER CONFIG bool { RADV_IFACE->other_config = $3; } - | LINK MTU expr { RADV_IFACE->link_mtu = $3; if ($3 < 0) cf_error("Link MTU must be 0 or positive"); } - | REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if (($3 < 0) || ($3 > 3600000)) cf_error("Reachable time must be in range 0-3600000"); } - | RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; if ($3 < 0) cf_error("Retrans timer must be 0 or positive"); } - | CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if (($4 < 0) || ($4 > 255)) cf_error("Current hop limit must be in range 0-255"); } + | LINK MTU expr { RADV_IFACE->link_mtu = $3; } + | REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if ($3 > 3600000) cf_error("Reachable time must be in range 0-3600000"); } + | RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; } + | CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if ($4 > 255) cf_error("Current hop limit must be in range 0-255"); } | DEFAULT LIFETIME expr radv_sensitive { RADV_IFACE->default_lifetime = $3; - if (($3 < 0) || ($3 > 9000)) cf_error("Default lifetime must be in range 0-9000"); - if ($4 != -1) RADV_IFACE->default_lifetime_sensitive = $4; + if ($3 > 9000) cf_error("Default lifetime must be in range 0-9000"); + if ($4 != (uint) -1) RADV_IFACE->default_lifetime_sensitive = $4; } | ROUTE LIFETIME expr radv_sensitive { RADV_IFACE->route_lifetime = $3; - if ($4 != -1) RADV_IFACE->route_lifetime_sensitive = $4; + if ($4 != (uint) -1) RADV_IFACE->route_lifetime_sensitive = $4; } | DEFAULT PREFERENCE radv_preference { RADV_IFACE->default_preference = $3; } | ROUTE PREFERENCE radv_preference { RADV_IFACE->route_preference = $3; } @@ -152,7 +150,7 @@ radv_iface_finish: if ((ic->min_ra_int > 3) && (ic->min_ra_int > (ic->max_ra_int * 3 / 4))) - cf_error("Min RA interval must be at most 3/4 * Max RA interval %d %d", ic->min_ra_int, ic->max_ra_int); + cf_error("Min RA interval must be at most 3/4 * Max RA interval"); if ((ic->default_lifetime > 0) && (ic->default_lifetime < ic->max_ra_int)) cf_error("Default lifetime must be either 0 or at least Max RA interval"); @@ -184,11 +182,10 @@ radv_iface: radv_iface_start iface_patt_list_nopx radv_iface_opt_list radv_iface_finish; -radv_prefix_start: prefix +radv_prefix_start: net_ip6 { this_radv_prefix = cfg_allocz(sizeof(struct radv_prefix_config)); - RADV_PREFIX->prefix = $1.addr; - RADV_PREFIX->pxlen = $1.len; + RADV_PREFIX->prefix = *(net_addr_ip6 *) &($1); RADV_PREFIX->onlink = 1; RADV_PREFIX->autonomous = 1; @@ -202,11 +199,11 @@ radv_prefix_item: | AUTONOMOUS bool { RADV_PREFIX->autonomous = $2; } | VALID LIFETIME expr radv_sensitive { RADV_PREFIX->valid_lifetime = $3; - if ($4 != -1) RADV_PREFIX->valid_lifetime_sensitive = $4; + if ($4 != (uint) -1) RADV_PREFIX->valid_lifetime_sensitive = $4; } | PREFERRED LIFETIME expr radv_sensitive { RADV_PREFIX->preferred_lifetime = $3; - if ($4 != -1) RADV_PREFIX->preferred_lifetime_sensitive = $4; + if ($4 != (uint) -1) RADV_PREFIX->preferred_lifetime_sensitive = $4; } ; @@ -331,7 +328,7 @@ radv_mult: ; radv_sensitive: - /* empty */ { $$ = -1; } + /* empty */ { $$ = (uint) -1; } | SENSITIVE bool { $$ = $2; } ; diff --git a/proto/radv/packets.c b/proto/radv/packets.c index 7d54a827..b12d3a12 100644 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@ -39,7 +39,7 @@ struct radv_opt_prefix u32 valid_lifetime; u32 preferred_lifetime; u32 reserved; - ip_addr prefix; + ip6_addr prefix; }; #define OPT_PX_ONLINK 0x80 @@ -68,7 +68,7 @@ struct radv_opt_rdnss u8 length; u16 reserved; u32 lifetime; - ip_addr servers[]; + ip6_addr servers[]; }; struct radv_opt_dnssl @@ -85,7 +85,7 @@ radv_prepare_route(struct radv_iface *ifa, struct radv_route *rt, char **buf, char *bufend) { struct radv_proto *p = ifa->ra; - u8 px_blocks = (rt->n.pxlen + 63) / 64; + u8 px_blocks = (net6_pxlen(rt->n.addr) + 63) / 64; u8 opt_len = 8 * (1 + px_blocks); if (*buf + opt_len > bufend) @@ -103,17 +103,17 @@ radv_prepare_route(struct radv_iface *ifa, struct radv_route *rt, *buf += opt_len; opt->type = OPT_ROUTE; opt->length = 1 + px_blocks; - opt->pxlen = rt->n.pxlen; + opt->pxlen = net6_pxlen(rt->n.addr); opt->flags = preference; opt->lifetime = valid ? htonl(lifetime) : 0; /* Copy the relevant part of the prefix */ - ip6_addr px_addr = ip6_hton(rt->n.prefix); + ip6_addr px_addr = ip6_hton(net6_prefix(rt->n.addr)); memcpy(opt->prefix, &px_addr, 8 * px_blocks); /* Keeping track of first linger timeout */ if (!rt->valid) - ifa->valid_time = MIN(ifa->valid_time, rt->changed + ifa->cf->route_linger_time); + ifa->valid_time = MIN(ifa->valid_time, rt->changed + ifa->cf->route_linger_time S); return 0; } @@ -127,7 +127,7 @@ radv_prepare_rdnss(struct radv_iface *ifa, list *rdnss_list, char **buf, char *b { struct radv_rdnss_config *rcf_base = rcf; struct radv_opt_rdnss *op = (void *) *buf; - int max_i = (bufend - *buf - sizeof(struct radv_opt_rdnss)) / sizeof(ip_addr); + int max_i = (bufend - *buf - sizeof(struct radv_opt_rdnss)) / sizeof(ip6_addr); int i = 0; if (max_i < 1) @@ -148,8 +148,7 @@ radv_prepare_rdnss(struct radv_iface *ifa, list *rdnss_list, char **buf, char *b if (i >= max_i) goto too_much; - op->servers[i] = rcf->server; - ipa_hton(op->servers[i]); + op->servers[i] = ip6_hton(rcf->server); i++; rcf = NODE_NEXT(rcf); @@ -254,10 +253,10 @@ radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *b } static int -radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *prefix, +radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *px, char **buf, char *bufend) { - struct radv_prefix_config *pc = prefix->cf; + struct radv_prefix_config *pc = px->cf; if (*buf + sizeof(struct radv_opt_prefix) > bufend) { @@ -269,7 +268,7 @@ radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *prefix, struct radv_opt_prefix *op = (void *) *buf; op->type = OPT_PREFIX; op->length = 4; - op->pxlen = prefix->len; + op->pxlen = px->prefix.pxlen; op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) | (pc->autonomous ? OPT_PX_AUTONOMOUS : 0); op->valid_lifetime = (ifa->ra->active || !pc->valid_lifetime_sensitive) ? @@ -277,13 +276,12 @@ radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *prefix, op->preferred_lifetime = (ifa->ra->active || !pc->preferred_lifetime_sensitive) ? htonl(pc->preferred_lifetime) : 0; op->reserved = 0; - op->prefix = prefix->prefix; - ipa_hton(op->prefix); + op->prefix = ip6_hton(px->prefix.prefix); *buf += sizeof(*op); /* Keeping track of first linger timeout */ - if (!prefix->valid) - ifa->valid_time = MIN(ifa->valid_time, prefix->changed + ifa->cf->prefix_linger_time); + if (!px->valid) + ifa->valid_time = MIN(ifa->valid_time, px->changed + ifa->cf->prefix_linger_time S); return 0; } @@ -294,6 +292,7 @@ radv_prepare_ra(struct radv_iface *ifa) struct radv_proto *p = ifa->ra; struct radv_config *cf = (struct radv_config *) (p->p.cf); struct radv_iface_config *ic = ifa->cf; + btime now = current_time(); char *buf = ifa->sk->tbuf; char *bufstart = buf; @@ -330,7 +329,7 @@ radv_prepare_ra(struct radv_iface *ifa) WALK_LIST(px, ifa->prefixes) { /* Skip invalid prefixes that are past linger timeout but still not pruned */ - if (!px->valid && (px->changed + ic->prefix_linger_time <= now)) + if (!px->valid && ((px->changed + ic->prefix_linger_time S) <= now)) continue; if (radv_prepare_prefix(ifa, px, &buf, bufend) < 0) @@ -353,12 +352,10 @@ radv_prepare_ra(struct radv_iface *ifa) if (p->fib_up) { - FIB_WALK(&p->routes, n) + FIB_WALK(&p->routes, struct radv_route, rt) { - struct radv_route *rt = (void *) n; - /* Skip invalid routes that are past linger timeout but still not pruned */ - if (!rt->valid && (rt->changed + ic->route_linger_time <= now)) + if (!rt->valid && ((rt->changed + ic->route_linger_time S) <= now)) continue; if (radv_prepare_route(ifa, rt, &buf, bufend) < 0) @@ -396,7 +393,7 @@ radv_rx_hook(sock *sk, uint size) if (sk->lifindex != sk->iface->index) return 1; - if (ipa_equal(sk->faddr, ifa->addr->ip)) + if (ipa_equal(sk->faddr, sk->saddr)) return 1; if (size < 8) @@ -448,6 +445,7 @@ radv_sk_open(struct radv_iface *ifa) { sock *sk = sk_new(ifa->pool); sk->type = SK_IP; + sk->subtype = SK_IPV6; sk->dport = ICMPV6_PROTO; sk->saddr = ifa->addr->ip; sk->vrf = ifa->ra->p.vrf; 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, diff --git a/proto/radv/radv.h b/proto/radv/radv.h index ab081397..66f785a7 100644 --- a/proto/radv/radv.h +++ b/proto/radv/radv.h @@ -30,7 +30,7 @@ #define ICMPV6_RA 134 #define MAX_INITIAL_RTR_ADVERTISEMENTS 3 -#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16 +#define MAX_INITIAL_RTR_ADVERT_INTERVAL (16 S_) #define DEFAULT_MAX_RA_INT 600 #define DEFAULT_MIN_DELAY 3 @@ -50,9 +50,7 @@ struct radv_config list rdnss_list; /* Global list of RDNSS configs (struct radv_rdnss_config) */ list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */ - ip_addr trigger_prefix; /* Prefix of a trigger route, if defined */ - u8 trigger_pxlen; /* Pxlen of a trigger route, if defined */ - u8 trigger_valid; /* Whether a trigger route is defined */ + net_addr trigger; /* Prefix of a trigger route, if defined */ u8 propagate_routes; /* Do we propagate more specific routes (RFC 4191)? */ u32 max_linger_time; /* Maximum of interface route_linger_time */ }; @@ -91,8 +89,7 @@ struct radv_iface_config struct radv_prefix_config { node n; - ip_addr prefix; - uint pxlen; + net_addr_ip6 prefix; u8 skip; /* Do not include this prefix to RA */ u8 onlink; /* Standard options from RFC 4861 */ @@ -108,7 +105,7 @@ struct radv_rdnss_config node n; u32 lifetime; /* Valid if lifetime_mult is 0 */ u16 lifetime_mult; /* Lifetime specified as multiple of max_ra_int */ - ip_addr server; /* IP address of recursive DNS server */ + ip6_addr server; /* IP address of recursive DNS server */ }; struct radv_dnssl_config @@ -130,13 +127,14 @@ struct radv_dnssl_config */ struct radv_route { - struct fib_node n; u32 lifetime; /* Lifetime from an attribute */ u8 lifetime_set; /* Whether lifetime is defined */ u8 preference; /* Preference of the route, RA_PREF_* */ u8 preference_set; /* Whether preference is defined */ u8 valid; /* Whethe route is valid or withdrawn */ - bird_clock_t changed; /* Last time when the route changed */ + btime changed; /* Last time when the route changed */ + + struct fib_node n; }; struct radv_proto @@ -147,18 +145,18 @@ struct radv_proto u8 active; /* Whether radv is active w.r.t. triggers */ u8 fib_up; /* FIB table (routes) is initialized */ struct fib routes; /* FIB table of specific routes (struct radv_route) */ - bird_clock_t prune_time; /* Next time of route table pruning */ + btime prune_time; /* Next time of route table pruning */ }; struct radv_prefix /* One prefix we advertise */ { node n; - ip_addr prefix; - u8 len; + net_addr_ip6 prefix; + u8 valid; /* Is the prefix valid? If not, we advertise it with 0 lifetime, so clients stop using it */ u8 mark; /* A temporary mark for processing */ - bird_clock_t changed; /* Last time when the prefix changed */ + btime changed; /* Last time when the prefix changed */ struct radv_prefix_config *cf; /* The config tied to this prefix */ }; @@ -171,14 +169,14 @@ struct radv_iface struct ifa *addr; /* Link-local address of iface */ struct pool *pool; /* A pool for interface-specific things */ list prefixes; /* The prefixes we advertise (struct radv_prefix) */ - bird_clock_t prune_time; /* Next time of prefix list pruning */ - bird_clock_t valid_time; /* Cached packet is valid until first linger timeout */ + btime prune_time; /* Next time of prefix list pruning */ + btime valid_time; /* Cached packet is valid until first linger timeout */ timer *timer; struct object_lock *lock; sock *sk; - bird_clock_t last; /* Time of last sending of RA */ + btime last; /* Time of last sending of RA */ u16 plen; /* Length of prepared RA in tbuf, or 0 if not valid */ byte initial; /* How many RAs are still to be sent as initial */ }; |