RE: IPV6 stateless address autoconfiguration

Previous thread: Re: Fix FRTO+NewReno problem (Was: Re: This has a work around) by Ilpo Järvinen on Monday, May 12, 2008 - 4:32 am. (17 messages)

Next thread: TCP receive splice performance by Octavian Purdila on Monday, May 12, 2008 - 5:45 am. (3 messages)
From: Bonitch, Joseph
Date: Monday, May 12, 2008 - 4:46 am

I sent a note last week regarding an issue I found with IPV6 stateless
address autoconfiguration.  I received no responses so I'm wondering if
there is another list I should be sending this problem too.

If anyone has the information for the usagi-users list, that would be
helpful - they changed the domain name of the mail list servers but
have not updated their website yet.  The necessary information is
xxxxx'd out in the archives.

Or should I just submit a bug in bugzilla.kernel.org?

Joe

--

From: David Miller
Date: Monday, May 12, 2008 - 5:14 am

From: "Bonitch, Joseph" <Joseph.Bonitch@xerox.com>

We've all received it and saw your posting, it's just that everyone is
simply busy with other things.

We'll get to your posting when we get a chance, but realize that most
of us have enormous backlogs of work to do currently.

--

From: YOSHIFUJI Hideaki /
Date: Monday, May 12, 2008 - 7:58 am

Just FYI, I'm now looking into it.

--yoshfuji
--

From: YOSHIFUJI Hideaki /
Date: Monday, May 12, 2008 - 8:46 am

Okay, this is my tentative patch.
Could you test this, please?

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

--- 
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e591e09..266a6bb 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1787,18 +1787,29 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 		rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL,
 				dev->ifindex, 1);
 
-		if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
-			if (rt->rt6i_flags&RTF_EXPIRES) {
-				if (valid_lft == 0) {
-					ip6_del_rt(rt);
-					rt = NULL;
-				} else {
-					rt->rt6i_expires = jiffies + rt_expires;
-				}
+		if (rt && (rt->rt6i_flags & (RTF_ADDRCONF | RTF_PREFIX_RT)) == (RTF_ADDRCONF | RTF_PREFIX_RT)) {
+			/* Autoconf prefix route */
+			if (valid_lft == 0) {
+				ip6_del_rt(rt);
+				rt = NULL;
+			} else if (~rt_expires) {
+				/* not infinity */
+				rt->rt6i_expires = jiffies + rt_expires;
+				rt->rt6i_flags |= RTF_EXPIRES;
+			} else {
+				rt->rt6i_flags &= ~RTF_EXPIRES;
+				rt->rt6i_expires = 0;
 			}
 		} else if (valid_lft) {
+			int flags = RTF_ADDRCONF | RTF_PREFIX_RT;
+			clock_t expires = 0;
+			if (~rt_expires) {
+				/* not infinity */
+				flags |= RTF_EXPIRES;
+				expires = jiffies_to_clock_t(rt_expires);
+			}
 			addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,
-					      dev, jiffies_to_clock_t(rt_expires), RTF_ADDRCONF|RTF_EXPIRES|RTF_PREFIX_RT);
+					      dev, expires, flags);
 		}
 		if (rt)
 			dst_release(&rt->u.dst);


--yoshfuji
--

From: David Stevens
Date: Monday, May 12, 2008 - 10:00 am

rt_expires is "unsigned long" -- won't the high-order
bits be set on 64-bit machines?
        Also, don't you need to check before the divide by
USER_HZ?

                                                        +-DLS


--

From: YOSHIFUJI Hideaki /
Date: Monday, May 12, 2008 - 10:17 am

Oops, I'm afraid I sent a wrong file, sorry.

This is the correct version.
(...and I plan to come up with more fixes
for real application on top of the net tree.)

Sighed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

-- 
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e591e09..0e2de23 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1769,7 +1769,9 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 	   but it would require division in fib gc, that it
 	   not good.
 	 */
-	if (valid_lft >= 0x7FFFFFFF/HZ)
+	if (valid_lft == 0xFFFFFFFF)
+		rt_expires = ~0UL;
+	else if (valid_lft >= 0x7FFFFFFF/HZ)
 		rt_expires = 0x7FFFFFFF - (0x7FFFFFFF % HZ);
 	else
 		rt_expires = valid_lft * HZ;
@@ -1779,7 +1781,8 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 	 * Avoid arithmetic overflow there as well.
 	 * Overflow can happen only if HZ < USER_HZ.
 	 */
-	if (HZ < USER_HZ && rt_expires > 0x7FFFFFFF / USER_HZ)
+	if (HZ < USER_HZ &&
+	    ~rt_expires && rt_expires > 0x7FFFFFFF / USER_HZ)
 		rt_expires = 0x7FFFFFFF / USER_HZ;
 
 	if (pinfo->onlink) {
@@ -1787,18 +1790,29 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 		rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL,
 				dev->ifindex, 1);
 
-		if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
-			if (rt->rt6i_flags&RTF_EXPIRES) {
-				if (valid_lft == 0) {
-					ip6_del_rt(rt);
-					rt = NULL;
-				} else {
-					rt->rt6i_expires = jiffies + rt_expires;
-				}
+		if (rt && (rt->rt6i_flags & (RTF_ADDRCONF | RTF_PREFIX_RT)) == (RTF_ADDRCONF | RTF_PREFIX_RT)) {
+			/* Autoconf prefix route */
+			if (valid_lft == 0) {
+				ip6_del_rt(rt);
+				rt = NULL;
+			} else if (~rt_expires) {
+				/* not infinity */
+				rt->rt6i_expires = jiffies + rt_expires;
+				rt->rt6i_flags |= RTF_EXPIRES;
+			} else {
+				rt->rt6i_flags &= ~RTF_EXPIRES;
+				rt->rt6i_expires = 0;
 			}
 		} else if (valid_lft) ...
From: Bonitch, Joseph
Date: Monday, May 12, 2008 - 12:36 pm

I did some testing with the second patch.  My router is still configured
to send RA's with prefix information valid_lft = preferred_lft = 0xffffffff.
It works except for one thing: the initial prefix route (after the first RA)
shows an expire time when using
   ip -6 route list
If I keep checking I can see the expires time counting down.  After some
minutes the expires field disappeares from the ip -6 route list output.
I tracked it down and it looks like when a subsequent RA is received
with the same prefix is when the expires time stops showing up.

Joe
--

From: YOSHIFUJI Hideaki /
Date: Monday, May 12, 2008 - 6:42 pm

Thanks.  I had missed sevral other users of addrconf_prefix_route().
Please try this.

----
[IPV6] ADDRCONF: Allow infinite prefix lifetime.

We need to handle infinite prefix lifetime specially.
Issue reported by "Bonitch, Joseph" <Joseph.Bonitch@xerox.com>

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
 net/ipv6/addrconf.c |   73 ++++++++++++++++++++++++++++++++++----------------
 1 files changed, 49 insertions(+), 24 deletions(-)

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e591e09..3a78021 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1764,14 +1764,16 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 	 *	2) Configure prefixes with the auto flag set
 	 */
 
-	/* Avoid arithmetic overflow. Really, we could
-	   save rt_expires in seconds, likely valid_lft,
-	   but it would require division in fib gc, that it
-	   not good.
-	 */
-	if (valid_lft >= 0x7FFFFFFF/HZ)
+	if (valid_lft == INFINITY_LIFE_TIME)
+		rt_expires = ~0UL;
+	else if (valid_lft >= 0x7FFFFFFF/HZ) {
+		/* Avoid arithmetic overflow. Really, we could
+		 * save rt_expires in seconds, likely valid_lft,
+		 * but it would require division in fib gc, that it
+		 * not good.
+		 */
 		rt_expires = 0x7FFFFFFF - (0x7FFFFFFF % HZ);
-	else
+	} else
 		rt_expires = valid_lft * HZ;
 
 	/*
@@ -1779,7 +1781,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 	 * Avoid arithmetic overflow there as well.
 	 * Overflow can happen only if HZ < USER_HZ.
 	 */
-	if (HZ < USER_HZ && rt_expires > 0x7FFFFFFF / USER_HZ)
+	if (HZ < USER_HZ && ~rt_expires && rt_expires > 0x7FFFFFFF / USER_HZ)
 		rt_expires = 0x7FFFFFFF / USER_HZ;
 
 	if (pinfo->onlink) {
@@ -1788,17 +1790,28 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 				dev->ifindex, 1);
 
 		if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
-			if (rt->rt6i_flags&RTF_EXPIRES) {
-				if (valid_lft == 0) ...
From: Bonitch, Joseph
Date: Wednesday, May 14, 2008 - 4:15 am

I will test this afternoon and let you know the results.

Regards,

Joe
--

From: Bonitch, Joseph
Date: Wednesday, May 14, 2008 - 1:05 pm

Yoshfuji,

I tested your latest patch to addrconf.c.  It worked but I still had the
problem that the prefix routes had an expiry time until the second
RA was received.

I tracked it down to ip6_route_add() inside route.c: lifetime passed
in was not checked for 0.  I made a minor change (see below) and
now it is working as expected.

Regards,

Joe

diff --git a/route.c.orig b/route.c
index 5f0043c..2c23d67 100644
--- a/route.c.orig
+++ b/route.c
@@ -1069,7 +1069,7 @@ int ip6_route_add(struct fib6_config *cfg)
        }

        rt->u.dst.obsolete = -1;
-       rt->rt6i_expires = jiffies + clock_t_to_jiffies(cfg->fc_expires);
+       rt->rt6i_expires = (cfg->fc_expires) ? jiffies + clock_t_to_jiffies(cfg->fc_expires) : 0;

        if (cfg->fc_protocol == RTPROT_UNSPEC)
                cfg->fc_protocol = RTPROT_BOOT;
--

From: YOSHIFUJI Hideaki /
Date: Thursday, May 15, 2008 - 1:10 am

Okay, thank you.  I'll send the final version soon.

--yoshfuji
--

Previous thread: Re: Fix FRTO+NewReno problem (Was: Re: This has a work around) by Ilpo Järvinen on Monday, May 12, 2008 - 4:32 am. (17 messages)

Next thread: TCP receive splice performance by Octavian Purdila on Monday, May 12, 2008 - 5:45 am. (3 messages)