[IPV4]: Primary and secondary addresses
authorHarald Welte <laforge@gnumonks.org>
Mon, 30 May 2005 03:23:46 +0000 (20:23 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 30 May 2005 03:23:46 +0000 (20:23 -0700)
Add an option to make secondary IP addresses get promoted
when primary IP addresses are removed from the device.
It defaults to off to preserve existing behavior.

Signed-off-by: Harald Welte <laforge@gnumonks.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/inetdevice.h
include/linux/sysctl.h
net/ipv4/devinet.c

index 6fafb27..7e1e15f 100644 (file)
@@ -29,6 +29,7 @@ struct ipv4_devconf
        int     no_xfrm;
        int     no_policy;
        int     force_igmp_version;
+       int     promote_secondaries;
        void    *sysctl;
 };
 
@@ -71,6 +72,7 @@ struct in_device
 #define IN_DEV_SEC_REDIRECTS(in_dev)   (ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects)
 #define IN_DEV_IDTAG(in_dev)           ((in_dev)->cnf.tag)
 #define IN_DEV_MEDIUM_ID(in_dev)       ((in_dev)->cnf.medium_id)
+#define IN_DEV_PROMOTE_SECONDARIES(in_dev)     (ipv4_devconf.promote_secondaries || (in_dev)->cnf.promote_secondaries)
 
 #define IN_DEV_RX_REDIRECTS(in_dev) \
        ((IN_DEV_FORWARD(in_dev) && \
index 7729981..23032d9 100644 (file)
@@ -399,6 +399,7 @@ enum
        NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
        NET_IPV4_CONF_ARP_ANNOUNCE=18,
        NET_IPV4_CONF_ARP_IGNORE=19,
+       NET_IPV4_CONF_PROMOTE_SECONDARIES=20,
        __NET_IPV4_CONF_MAX
 };
 
index 3cc9673..478a301 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 = {
                {