[IPV4]: Primary and secondary addresses
[deliverable/linux.git] / net / ipv4 / devinet.c
index 3cc96730c4ed285d4a1f65e69ca659290b26abe0..478a30179a527149a837bf1092e1cda0b704456f 100644 (file)
@@ -233,11 +233,14 @@ int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
 static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
                         int destroy)
 {
+       struct in_ifaddr *promote = NULL;
        struct in_ifaddr *ifa1 = *ifap;
 
        ASSERT_RTNL();
 
-       /* 1. Deleting primary ifaddr forces deletion all secondaries */
+       /* 1. Deleting primary ifaddr forces deletion all secondaries 
+        * unless alias promotion is set
+        **/
 
        if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
                struct in_ifaddr *ifa;
@@ -251,11 +254,16 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
                                continue;
                        }
 
-                       *ifap1 = ifa->ifa_next;
+                       if (!IN_DEV_PROMOTE_SECONDARIES(in_dev)) {
+                               *ifap1 = ifa->ifa_next;
 
-                       rtmsg_ifa(RTM_DELADDR, ifa);
-                       notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
-                       inet_free_ifa(ifa);
+                               rtmsg_ifa(RTM_DELADDR, ifa);
+                               notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
+                               inet_free_ifa(ifa);
+                       } else {
+                               promote = ifa;
+                               break;
+                       }
                }
        }
 
@@ -281,6 +289,13 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
                if (!in_dev->ifa_list)
                        inetdev_destroy(in_dev);
        }
+
+       if (promote && IN_DEV_PROMOTE_SECONDARIES(in_dev)) {
+               /* not sure if we should send a delete notify first? */
+               promote->ifa_flags &= ~IFA_F_SECONDARY;
+               rtmsg_ifa(RTM_NEWADDR, promote);
+               notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote);
+       }
 }
 
 static int inet_insert_ifa(struct in_ifaddr *ifa)
@@ -1384,6 +1399,15 @@ static struct devinet_sysctl_table {
                        .proc_handler   = &ipv4_doint_and_flush,
                        .strategy       = &ipv4_doint_and_flush_strategy,
                },
+               {
+                       .ctl_name       = NET_IPV4_CONF_PROMOTE_SECONDARIES,
+                       .procname       = "promote_secondaries",
+                       .data           = &ipv4_devconf.promote_secondaries,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = &ipv4_doint_and_flush,
+                       .strategy       = &ipv4_doint_and_flush_strategy,
+               },
        },
        .devinet_dev = {
                {
This page took 0.02633 seconds and 5 git commands to generate.