Add --ra-param and remove --force-fast-ra

This commit is contained in:
Simon Kelley
2013-10-10 20:58:11 +01:00
parent 043c271f8a
commit c4cd95df68
5 changed files with 147 additions and 37 deletions

View File

@@ -32,11 +32,12 @@ struct ra_param {
char *if_name;
struct dhcp_netid *tags;
struct in6_addr link_local, link_global;
unsigned int pref_time;
unsigned int pref_time, adv_interval;
};
struct search_param {
time_t now; int iface;
char name[IF_NAMESIZE+1];
};
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
@@ -47,7 +48,11 @@ static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
int prefered, int valid, void *vparam);
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
static void new_timeout(struct dhcp_context *context, time_t now);
static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
static unsigned int calc_lifetime(struct ra_interface *ra);
static unsigned int calc_interval(struct ra_interface *ra);
static unsigned int calc_prio(struct ra_interface *ra);
static struct ra_interface *find_iface_param(char *iface);
static int hop_limit;
@@ -198,19 +203,20 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
struct dhcp_context *context, *tmp, **up;
struct dhcp_netid iface_id;
struct dhcp_opt *opt_cfg;
struct ra_interface *ra_param = find_iface_param(iface_name);
int done_dns = 0;
#ifdef HAVE_LINUX_NETWORK
FILE *f;
#endif
save_counter(0);
ra = expand(sizeof(struct ra_packet));
ra->type = ND_ROUTER_ADVERT;
ra->code = 0;
ra->hop_limit = hop_limit;
ra->flags = 0x00;
ra->lifetime = htons(RA_INTERVAL * 3); /* AdvDefaultLifetime * 3 */
ra->flags = calc_prio(ra_param);
ra->lifetime = htons(calc_lifetime(ra_param));
ra->reachable_time = 0;
ra->retrans_time = 0;
@@ -222,6 +228,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
parm.first = 1;
parm.now = now;
parm.pref_time = 0;
parm.adv_interval = calc_interval(ra_param);
/* set tag with name == interface */
iface_id.net = iface_name;
@@ -335,7 +342,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char((opt_cfg->len/8) + 1);
put_opt6_short(0);
put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
put_opt6_long(parm.adv_interval * 2); /* lifetime - twice RA retransmit */
/* zero means "self" */
for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
if (IN6_IS_ADDR_UNSPECIFIED(a))
@@ -351,7 +358,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
put_opt6_char(ICMP6_OPT_DNSSL);
put_opt6_char(len + 1);
put_opt6_short(0);
put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
put_opt6_long(parm.adv_interval * 2); /* lifetime - twice RA retransmit */
put_opt6(opt_cfg->val, opt_cfg->len);
/* pad */
@@ -366,7 +373,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char(3);
put_opt6_short(0);
put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
put_opt6_long(parm.adv_interval * 2); /* lifetime - twice RA retransmit */
put_opt6(&parm.link_global, IN6ADDRSZ);
}
@@ -455,8 +462,8 @@ static int add_prefixes(struct in6_addr *local, int prefix,
if (time > context->lease_time)
{
time = context->lease_time;
if (time < ((unsigned int)(3 * RA_INTERVAL)))
time = 3 * RA_INTERVAL;
if (time < ((unsigned int)(3 * param->adv_interval)))
time = 3 * param->adv_interval;
}
if (context->flags & CONTEXT_DEPRECATE)
@@ -564,8 +571,7 @@ time_t periodic_ra(time_t now)
struct search_param param;
struct dhcp_context *context;
time_t next_event;
char interface[IF_NAMESIZE+1];
param.now = now;
param.iface = 0;
@@ -586,13 +592,15 @@ time_t periodic_ra(time_t now)
if (!context)
break;
if ((context->flags & CONTEXT_OLD) && context->if_index != 0)
if ((context->flags & CONTEXT_OLD) &&
context->if_index != 0 &&
indextoname(daemon->icmp6fd, param.iface, param.name))
{
/* A context for an old address. We'll not find the interface by
looking for addresses, but we know it anyway, as long as we
sent at least one RA whilst the address was current. */
looking for addresses, but we know it anyway, since the context is
constructed */
param.iface = context->if_index;
new_timeout(context, now);
new_timeout(context, param.name, now);
}
else if (iface_enumerate(AF_INET6, &param, iface_search))
/* There's a context overdue, but we can't find an interface
@@ -603,15 +611,14 @@ time_t periodic_ra(time_t now)
context->ra_time = 0;
if (param.iface != 0 &&
indextoname(daemon->icmp6fd, param.iface, interface) &&
iface_check(AF_LOCAL, NULL, interface, NULL))
iface_check(AF_LOCAL, NULL, param.name, NULL))
{
struct iname *tmp;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, interface))
if (tmp->name && wildcard_match(tmp->name, param.name))
break;
if (!tmp)
send_ra(now, param.iface, interface, NULL);
send_ra(now, param.iface, param.name, NULL);
}
}
return next_event;
@@ -643,7 +650,14 @@ static int iface_search(struct in6_addr *local, int prefix,
if (!(flags & IFACE_TENTATIVE))
param->iface = if_index;
new_timeout(context, param->now);
/* should never fail */
if (!indextoname(daemon->icmp6fd, if_index, param->name))
{
param->iface = 0;
return 0;
}
new_timeout(context, param->name, param->now);
/* zero timers for other contexts on the same subnet, so they don't timeout
independently */
@@ -659,14 +673,70 @@ static int iface_search(struct in6_addr *local, int prefix,
return 1; /* keep searching */
}
static void new_timeout(struct dhcp_context *context, time_t now)
static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now)
{
if (difftime(now, context->ra_short_period_start) < 60.0 || option_bool(OPT_FAST_RA))
if (difftime(now, context->ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = now + 5 + (rand16()/4400);
else
/* range 3/4 - 1 times RA_INTERVAL */
context->ra_time = now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
{
/* range 3/4 - 1 times MaxRtrAdvInterval */
unsigned int adv_interval = calc_interval(find_iface_param(iface_name));
context->ra_time = now + (3 * adv_interval)/4 + ((adv_interval * (unsigned int)rand16()) >> 18);
}
}
static struct ra_interface *find_iface_param(char *iface)
{
struct ra_interface *ra;
for (ra = daemon->ra_interfaces; ra; ra = ra->next)
if (wildcard_match(ra->name, iface))
return ra;
return NULL;
}
static unsigned int calc_interval(struct ra_interface *ra)
{
int interval = 600;
if (ra && ra->interval != 0)
{
interval = ra->interval;
if (interval > 1800)
interval = 1800;
else if (interval < 4)
interval = 4;
}
return (unsigned int)interval;
}
static unsigned int calc_lifetime(struct ra_interface *ra)
{
int lifetime, interval = (int)calc_interval(ra);
if (!ra || ra->lifetime == -1) /* not specified */
lifetime = 3 * interval;
else
{
lifetime = ra->lifetime;
if (lifetime < interval && lifetime != 0)
lifetime = interval;
else if (lifetime > 9000)
lifetime = 9000;
}
return (unsigned int)lifetime;
}
static unsigned int calc_prio(struct ra_interface *ra)
{
if (ra)
return ra->prio;
return 0;
}
#endif