[PATCH] addrconf: Force logical down for bad MTU or no ipv6 addresses as well.

From: Eric W . Biederman
Date: Wed Dec 08 2010 - 14:59:36 EST


Don't loose our ipv6 state (like disable_ipv6) when we delete the last
address from an ipv6 interface or when we set an mtu on the interface
that is smaller than we support.

As well as making things more comprehensible to userspace this
makes the code simpler.

Signed-off-by: Eric W. Biederman <ebiederm@xxxxxxxxxxxx>
---
net/ipv6/addrconf.c | 79 ++++++++++++++++++++------------------------------
1 files changed, 32 insertions(+), 47 deletions(-)

Index: linux-2.6.37-rc5.x86_64/net/ipv6/addrconf.c
===================================================================
--- linux-2.6.37-rc5.x86_64.orig/net/ipv6/addrconf.c
+++ linux-2.6.37-rc5.x86_64/net/ipv6/addrconf.c
@@ -147,6 +147,7 @@ static void addrconf_leave_anycast(struc
static void addrconf_type_change(struct net_device *dev,
unsigned long event);
static int addrconf_ifdown(struct net_device *dev, int how);
+static void dev_disable_change(struct inet6_dev *idev);

static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags);
static void addrconf_dad_timer(unsigned long data);
@@ -2221,7 +2222,7 @@ static int inet6_addr_del(struct net *ne
disable IPv6 on this interface.
*/
if (list_empty(&idev->addr_list))
- addrconf_ifdown(idev->dev, 1);
+ dev_disable_change(idev);
return 0;
}
}
@@ -2499,7 +2500,7 @@ static int addrconf_notify(struct notifi

switch (event) {
case NETDEV_REGISTER:
- if (!idev && dev->mtu >= IPV6_MIN_MTU) {
+ if (!idev) {
idev = ipv6_add_dev(dev);
if (!idev)
return notifier_from_errno(-ENOMEM);
@@ -2520,26 +2521,18 @@ static int addrconf_notify(struct notifi
dev->name);
break;
}
-
- if (!idev && dev->mtu >= IPV6_MIN_MTU)
- idev = ipv6_add_dev(dev);
-
- if (idev) {
- idev->if_flags |= IF_READY;
- run_pending = 1;
- }
+ idev->if_flags |= IF_READY;
+ run_pending = 1;
} else {
if (!addrconf_qdisc_ok(dev)) {
/* device is still not ready. */
break;
}

- if (idev) {
- if (idev->if_flags & IF_READY)
- /* device is already configured. */
- break;
- idev->if_flags |= IF_READY;
- }
+ if (idev->if_flags & IF_READY)
+ /* device is already configured. */
+ break;
+ idev->if_flags |= IF_READY;

printk(KERN_INFO
"ADDRCONF(NETDEV_CHANGE): %s: "
@@ -2567,45 +2560,37 @@ static int addrconf_notify(struct notifi
break;
}

- if (idev) {
- if (run_pending)
- addrconf_dad_run(idev);
-
- /*
- * If the MTU changed during the interface down,
- * when the interface up, the changed MTU must be
- * reflected in the idev as well as routers.
- */
- if (idev->cnf.mtu6 != dev->mtu &&
- dev->mtu >= IPV6_MIN_MTU) {
- rt6_mtu_change(dev, dev->mtu);
- idev->cnf.mtu6 = dev->mtu;
- }
- idev->tstamp = jiffies;
- inet6_ifinfo_notify(RTM_NEWLINK, idev);
+ if (run_pending)
+ addrconf_dad_run(idev);

- /*
- * If the changed mtu during down is lower than
- * IPV6_MIN_MTU stop IPv6 on this interface.
- */
- if (dev->mtu < IPV6_MIN_MTU)
- addrconf_ifdown(dev, 1);
+ /*
+ * If the MTU changed during the interface down,
+ * when the interface up, the changed MTU must be
+ * reflected in the idev as well as routers.
+ */
+ if (idev->cnf.mtu6 != dev->mtu &&
+ dev->mtu >= IPV6_MIN_MTU) {
+ rt6_mtu_change(dev, dev->mtu);
+ idev->cnf.mtu6 = dev->mtu;
}
+ idev->tstamp = jiffies;
+ inet6_ifinfo_notify(RTM_NEWLINK, idev);
+
+ /*
+ * If the changed mtu during down is lower than
+ * IPV6_MIN_MTU stop IPv6 on this interface.
+ */
+ if (dev->mtu < IPV6_MIN_MTU)
+ dev_disable_change(idev);
break;

case NETDEV_CHANGEMTU:
- if (idev && dev->mtu >= IPV6_MIN_MTU) {
+ if (dev->mtu >= IPV6_MIN_MTU) {
rt6_mtu_change(dev, dev->mtu);
idev->cnf.mtu6 = dev->mtu;
break;
}

- if (!idev && dev->mtu >= IPV6_MIN_MTU) {
- idev = ipv6_add_dev(dev);
- if (idev)
- break;
- }
-
/*
* MTU falled under IPV6_MIN_MTU.
* Stop IPv6 on this interface.
@@ -2616,7 +2601,7 @@ static int addrconf_notify(struct notifi
/*
* Remove all addresses from this interface.
*/
- addrconf_ifdown(dev, event != NETDEV_DOWN);
+ addrconf_ifdown(dev, event == NETDEV_UNREGISTER);
break;

case NETDEV_CHANGENAME:
@@ -4137,6 +4122,18 @@ static void ipv6_ifa_notify(int event, s
rcu_read_unlock_bh();
}

+static void dev_disable_change(struct inet6_dev *idev)
+{
+ if (!idev || !idev->dev)
+ return;
+
+ if (idev->cnf.disable_ipv6 || (list_empty(&idev->addr_list)) ||
+ (idev->dev->mtu < IPV6_MIN_MTU))
+ addrconf_notify(NULL, NETDEV_DOWN, idev->dev);
+ else
+ addrconf_notify(NULL, NETDEV_UP, idev->dev);
+}
+
#ifdef CONFIG_SYSCTL

static
@@ -4157,17 +4154,6 @@ int addrconf_sysctl_forward(ctl_table *c
return ret;
}

-static void dev_disable_change(struct inet6_dev *idev)
-{
- if (!idev || !idev->dev)
- return;
-
- if (idev->cnf.disable_ipv6)
- addrconf_notify(NULL, NETDEV_DOWN, idev->dev);
- else
- addrconf_notify(NULL, NETDEV_UP, idev->dev);
-}
-
static void addrconf_disable_change(struct net *net, __s32 newf)
{
struct net_device *dev;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/