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: "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. --
Just FYI, I'm now looking into it. --yoshfuji --
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
--
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
--
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) ...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 --
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) ...I will test this afternoon and let you know the results. Regards, Joe --
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;
--
Okay, thank you. I'll send the final version soon. --yoshfuji --
