[radvd-devel-l] request for comments - DecreaseLifetimes option
Pekka Savola
pekkas at netcore.fi
Mon Mar 28 01:30:40 EDT 2011
I will observe that I'm aware of only one RFC 4861 S 6.2
implementation that supports "lifetimes decreasing in real time" --
rtadvd. I have vague recollection of hearing about this in the
context of Solaris, but I can't check that.
So, this is not a very widely used feature and not mandated by
specifications.
On Sun, 27 Mar 2011, Reuben Hawkins wrote:
> On Thu, Mar 24, 2011 at 9:36 PM, Mark Smith <radvd at 02a76c927861ca7413a122f2a73a0d37.nosense.org> wrote:
> Hi,
>
> This option is a bit more complicated than the last ones. It provides
> an option to have radvd decrease the preferred and valid lifetime
> values of specified prefixes over time. This would be used in
> conjunction with prefixes supplied by DHCPv6 based Prefix Delegation
> (DHCPv6-PD). The sequence of events would be as follows -
>
> 1. Initial DHCPv6-PD transaction takes place over a e.g. WAN interface
> of the router, and a delegated prefix e.g. a /56 is acquired, with e.g.
> a preferred lifetime of 14400 seconds and a valid lifetime of 86400
> seconds.
>
> 2. A /64 is taken from within the delegated prefix, for use on the LAN
> interface of the router.
>
> 3. A radvd configuration is built with to announce this prefix, with
> preferred and valid lifetimes of 14400 and 86400 seconds respectively,
> and a prefix DecreaseLifetimes option.
>
> 4. For each RA, either solicited or unsolicited, the preferred and
> valid lifetimes are decreased by the number of seconds since the last
> RA.
>
> 5. At time "T1" the DHCPv6-PD client will attempt to renew the
> delegated prefix. If the delegated prefix is renewed successfully, with
> the same preferred and valid lifetimes, the DHCPv6-PD client sends a
> USR1 signal to radvd. This causes radvd to reset the announced preferred
> and valid lifetimes back to the lifetime values specified in it's
> configuration file, and then continue to decrease them for each
> RA. If the delegated prefix either doesn't renew successfully, or has
> different preferred and valid lifetimes, then the DHCPv6-PD client will
> have to stop radvd, generate a new configuration for it and start it
> again.
>
> 6. If radvd never receives the USR1 signal, it will continue to
> decrease the lifetimes until the preferred lifetime reaches 0.
> After an announcement of the prefix with a 0 preferred lifetime, radvd
> then stops announcing that prefix. If it subsequently receives a USR1
> signal, it will then start announcing the prefix again, with the
> lifetimes starting back at the specified initial values.
>
> I'm interested in comments on the following patch. If people are happy
> with the approach, I'll finish it off by e.g. adding manual page
> entries.
>
> Attached and shown below, it should apply to cvs revision 1.115.
>
>
> Thanks,
> Mark.
>
>
> diff --git a/defaults.h b/defaults.h
> index e09a659..d17cb6f 100644
> --- a/defaults.h
> +++ b/defaults.h
> @@ -57,6 +57,7 @@
> #define DFLT_AdvPreferredLifetime 14400 /* seconds */
> #define DFLT_AdvAutonomousFlag 1
> #define DFLT_DeprecatePrefixFlag 0
> +#define DFLT_DecrementLifetimesFlag 0
>
> /* Each route has an associated: */
> #define DFLT_AdvRouteLifetime(iface) (3 * (iface)->MaxRtrAdvInterval)
> diff --git a/gram.y b/gram.y
> index 4c74cc8..eb7fb0d 100644
> --- a/gram.y
> +++ b/gram.y
> @@ -96,6 +96,7 @@ static struct in6_addr get_prefix6(struct in6_addr const *addr, struct in6_addr
> %token T_AdvValidLifetime
> %token T_AdvPreferredLifetime
> %token T_DeprecatePrefix
> +%token T_DecrementLifetimes
>
> %token T_AdvRouterAddr
> %token T_AdvHomeAgentFlag
> @@ -604,11 +605,13 @@ prefixparms : T_AdvOnLink SWITCH ';'
> struct AdvPrefix *p = prefix;
> do {
> p->AdvValidLifetime = $2;
> + p->curr_validlft = $2;
> p = p->next;
> } while (p && p->AutoSelected);
> }
> else
> prefix->AdvValidLifetime = $2;
> + prefix->curr_validlft = $2;
> }
> }
> | T_AdvPreferredLifetime number_or_infinity ';'
> @@ -618,17 +621,23 @@ prefixparms : T_AdvOnLink SWITCH ';'
> struct AdvPrefix *p = prefix;
> do {
> p->AdvPreferredLifetime = $2;
> + p->curr_preferredlft = $2;
> p = p->next;
> } while (p && p->AutoSelected);
> }
> else
> prefix->AdvPreferredLifetime = $2;
> + prefix->curr_preferredlft = $2;
> }
> }
> | T_DeprecatePrefix SWITCH ';'
> {
> prefix->DeprecatePrefixFlag = $2;
> }
> + | T_DecrementLifetimes SWITCH ';'
> + {
> + prefix->DecrementLifetimesFlag = $2;
> + }
> | T_Base6Interface name ';'
> {
> if (prefix) {
> diff --git a/interface.c b/interface.c
> index 0e6f672..4ffdbf1 100644
> --- a/interface.c
> +++ b/interface.c
> @@ -58,8 +58,12 @@ prefix_init_defaults(struct AdvPrefix *prefix)
> prefix->AdvValidLifetime = DFLT_AdvValidLifetime;
> prefix->AdvPreferredLifetime = DFLT_AdvPreferredLifetime;
> prefix->DeprecatePrefixFlag = DFLT_DeprecatePrefixFlag;
> + prefix->DecrementLifetimesFlag = DFLT_DecrementLifetimesFlag;
> prefix->if6to4[0] = 0;
> prefix->enabled = 1;
> +
> + prefix->curr_validlft = prefix->AdvValidLifetime;
> + prefix->curr_preferredlft = prefix->AdvPreferredLifetime;
> }
>
> void
> diff --git a/process.c b/process.c
> index 570911f..3cbebce 100644
> --- a/process.c
> +++ b/process.c
> @@ -333,7 +333,7 @@ process_ra(struct Interface *iface, unsigned char *msg, int len,
> {
> print_addr(&prefix->Prefix, prefix_str);
>
> - if (valid != prefix->AdvValidLifetime)
> + if (!prefix->DecrementLifetimesFlag && valid != prefix->AdvValidLifetime)
> {
> flog(LOG_WARNING, "our AdvValidLifetime on"
> " %s for %s doesn't agree with %s",
> @@ -342,7 +342,7 @@ process_ra(struct Interface *iface, unsigned char *msg, int len,
> addr_str
> );
> }
> - if (preferred != prefix->AdvPreferredLifetime)
> + if (!prefix->DecrementLifetimesFlag && preferred !=
> prefix->AdvPreferredLifetime)
> {
> flog(LOG_WARNING, "our AdvPreferredLifetime on"
> " %s for %s doesn't agree with %s",
> diff --git a/radvd.c b/radvd.c
> index 09a6fbe..fe88d79 100644
> --- a/radvd.c
> +++ b/radvd.c
> @@ -78,10 +78,12 @@ int sock = -1;
> volatile int sighup_received = 0;
> volatile int sigterm_received = 0;
> volatile int sigint_received = 0;
> +volatile int sigusr1_received = 0;
>
> void sighup_handler(int sig);
> void sigterm_handler(int sig);
> void sigint_handler(int sig);
> +void sigusr1_handler(int sig);
> void timer_handler(void *data);
> void config_interface(void);
> void kickoff_adverts(void);
> @@ -339,6 +341,7 @@ main(int argc, char *argv[])
> signal(SIGHUP, sighup_handler);
> signal(SIGTERM, sigterm_handler);
> signal(SIGINT, sigint_handler);
> + signal(SIGUSR1, sigusr1_handler);
>
> snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid());
>
> @@ -446,6 +449,13 @@ void main_loop(void)
> reload_config();
> sighup_received = 0;
> }
> +
> + if (sigusr1_received)
> + {
> + reset_prefix_lifetimes();
> + sigusr1_received = 0;
> + }
> +
> }
> }
>
> @@ -502,6 +512,9 @@ kickoff_adverts(void)
> {
> double next;
>
> +
> + gettimeofday(&iface->last_ra_time, NULL);
> +
> if( iface->UnicastOnly )
> continue;
>
> @@ -667,6 +680,45 @@ sigint_handler(int sig)
> }
> }
>
> +
> +void reset_prefix_lifetimes(void)
> +{
> + struct Interface *iface;
> + struct AdvPrefix *prefix;
> +
> +
> + flog(LOG_INFO, "Resetting prefix lifetimes\n");
> +
> + for (iface = IfaceList; iface; iface = iface->next)
> + {
> + for (prefix = iface->AdvPrefixList; prefix;
> + prefix = prefix->next)
> + {
> + if (prefix->DecrementLifetimesFlag)
> + {
> + prefix->curr_validlft =
> + prefix->AdvValidLifetime;
> + prefix->curr_preferredlft =
> + prefix->AdvPreferredLifetime;
> + }
> + }
> +
> + }
> +
> +}
> +
> +void sigusr1_handler(int sig)
> +{
> +
> + /* Linux has "one-shot" signals, reinstall the signal handler */
> + signal(SIGUSR1, sigusr1_handler);
> +
> + dlog(LOG_DEBUG, 4, "sigusr1_handler called");
> +
> + sigusr1_received = 1;
> +
> +}
> +
> int
> drop_root_privileges(const char *username)
> {
> diff --git a/radvd.h b/radvd.h
> index 16638fa..78e92b1 100644
> --- a/radvd.h
> +++ b/radvd.h
> @@ -49,6 +49,8 @@ struct Interface {
>
> int cease_adv;
>
> + struct timeval last_ra_time;
> +
> int IgnoreIfMissing;
> int AdvSendAdvert;
> double MaxRtrAdvInterval;
> @@ -103,6 +105,10 @@ struct AdvPrefix {
> uint32_t AdvValidLifetime;
> uint32_t AdvPreferredLifetime;
> int DeprecatePrefixFlag;
> + int DecrementLifetimesFlag;
> +
> + uint32_t curr_validlft;
> + uint32_t curr_preferredlft;
>
> /* Mobile IPv6 extensions */
> int AdvRouterAddr;
> @@ -179,6 +185,7 @@ int yylex(void);
> /* radvd.c */
> int check_ip6_forwarding(void);
> void reload_config(void);
> +void reset_prefix_lifetimes(void);
>
> /* timer.c */
> struct timeval next_timeval(double next);
> diff --git a/scanner.l b/scanner.l
> index 77106cf..a413b30 100644
> --- a/scanner.l
> +++ b/scanner.l
> @@ -70,6 +70,7 @@ AdvAutonomous { return T_AdvAutonomous; }
> AdvValidLifetime { return T_AdvValidLifetime; }
> AdvPreferredLifetime { return T_AdvPreferredLifetime; }
> DeprecatePrefix { return T_DeprecatePrefix; }
> +DecrementLifetimes { return T_DecrementLifetimes; }
>
> AdvRouterAddr { return T_AdvRouterAddr; }
> AdvHomeAgentFlag { return T_AdvHomeAgentFlag; }
> diff --git a/send.c b/send.c
> index 5ff5b5b..6dd9a25 100644
> --- a/send.c
> +++ b/send.c
> @@ -77,6 +77,16 @@ send_ra_inc_len(size_t *len, int add)
> }
> }
>
> +static void decrement_lifetime(const long int secs, uint32_t *lifetime)
> +{
> +
> + if (*lifetime > secs) {
> + *lifetime -= secs;
> + } else {
> + *lifetime = 0;
> + }
> +}
> +
> int
> send_ra(struct Interface *iface, struct in6_addr *dest)
> {
> @@ -92,6 +102,8 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
> struct AdvRoute *route;
> struct AdvRDNSS *rdnss;
> struct AdvDNSSL *dnssl;
> + struct timeval time_now;
> + long int secs_since_last_ra;
>
> unsigned char buff[MSG_SIZE_SEND];
> size_t len = 0;
> @@ -134,6 +146,14 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
> gettimeofday(&iface->last_multicast, NULL);
> }
>
> + gettimeofday(&time_now, NULL);
> + secs_since_last_ra = time_now.tv_sec - iface->last_ra_time.tv_sec;
> + if (secs_since_last_ra < 0) {
> + secs_since_last_ra = 0;
> + flog(LOG_WARNING, "gettimeofday() went backwards!");
> + }
> + iface->last_ra_time = time_now;
> +
> memset((void *)&addr, 0, sizeof(addr));
> addr.sin6_family = AF_INET6;
> addr.sin6_port = htons(IPPROTO_ICMPV6);
> @@ -177,7 +197,7 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
>
> while(prefix)
> {
> - if( prefix->enabled )
> + if( prefix->enabled && prefix->curr_preferredlft > 0 )
> {
> struct nd_opt_prefix_info *pinfo;
>
> @@ -200,9 +220,16 @@ send_ra(struct Interface *iface, struct in6_addr *dest)
> pinfo->nd_opt_pi_valid_time = htonl(MIN_AdvValidLifetime);
> pinfo->nd_opt_pi_preferred_time = 0;
> } else {
> + if (prefix->DecrementLifetimesFlag) {
> + decrement_lifetime(secs_since_last_ra,
> + &prefix->curr_validlft);
> +
> + decrement_lifetime(secs_since_last_ra,
> + &prefix->curr_preferredlft);
> + }
> + pinfo->nd_opt_pi_valid_time = htonl(prefix->curr_validlft);
> + pinfo->nd_opt_pi_preferred_time = htonl(prefix->curr_preferredlft);
>
> - pinfo->nd_opt_pi_valid_time = htonl(prefix->AdvValidLifetime);
> - pinfo->nd_opt_pi_preferred_time = htonl(prefix->AdvPreferredLifetime);
> }
> pinfo->nd_opt_pi_reserved2 = 0;
>
>
>
>
>
>
>
> --
> radvd-devel-l mailing list : radvd-devel-l at litech.org
> http://lists.litech.org/listinfo/radvd-devel-l
>
>
>
> Hi Mark,
>
> I'm not too enthusiastic about this patch for a few reasons. I don't like the idea of an advert being dependent on time.
> Although it's subtle, it makes debugging and/or reproducing a bug more difficult. However, this is called for in section 6.2.1
> of RFC 2461 under AdvPreferredLifetime and AdvValidLifetime.
>
> As such, please continue to test this for a while. Make sure it's working. If there's no objections to committing this, I'll
> commit it in a few weeks.
>
> Thanks,
> Reuben
>
>
--
Pekka Savola "You each name yourselves king, yet the
Netcore Oy kingdom bleeds."
Systems. Networks. Security. -- George R.R. Martin: A Clash of Kings
More information about the radvd-devel-l
mailing list