Dave,

This is a bug fix. So not sure if it is fitting for 2.6.15 or not.

Much thanks to Brian Pomerantz for thorough testing over the weekend and
today.

cheers,
jamal

This patch fixes the problem with promoting aliases when:
a) a single primary and > 1 secondary addresses
b) multiple primary addresses each with at least one secondary address

Based on earlier efforts from Brian Pomerantz <[EMAIL PROTECTED]>
and Patrick McHardy <[EMAIL PROTECTED]>

Signed-off-by: Jamal Hadi Salim <[EMAIL PROTECTED]>
---

 include/net/route.h     |    3 +++
 net/ipv4/devinet.c      |   38 +++++++++++++++++++++++++++++---------
 net/ipv4/fib_frontend.c |    3 ++-
 3 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/include/net/route.h b/include/net/route.h
index dbe79ca..e3e5436 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -126,6 +126,9 @@ extern int          ip_rt_ioctl(unsigned int cmd
 extern void            ip_rt_get_source(u8 *src, struct rtable *rt);
 extern int             ip_rt_dump(struct sk_buff *skb,  struct 
netlink_callback *cb);
 
+struct in_ifaddr;
+extern void fib_add_ifaddr(struct in_ifaddr *);
+
 static inline void ip_rt_put(struct rtable * rt)
 {
        if (rt)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 4ec4b2c..495bf22 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -234,7 +234,9 @@ static void inet_del_ifa(struct in_devic
                         int destroy)
 {
        struct in_ifaddr *promote = NULL;
-       struct in_ifaddr *ifa1 = *ifap;
+       struct in_ifaddr *ifa, *ifa1 = *ifap;
+       struct in_ifaddr *last_prim = in_dev->ifa_list;
+       struct in_ifaddr *prev_prom = NULL;
 
        ASSERT_RTNL();
 
@@ -243,14 +245,18 @@ static void inet_del_ifa(struct in_devic
         **/
 
        if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
-               struct in_ifaddr *ifa;
                struct in_ifaddr **ifap1 = &ifa1->ifa_next;
 
                while ((ifa = *ifap1) != NULL) {
+                       if (!(ifa->ifa_flags & IFA_F_SECONDARY) && 
+                           ifa1->ifa_scope <= ifa->ifa_scope)
+                               last_prim = ifa;
+
                        if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
                            ifa1->ifa_mask != ifa->ifa_mask ||
                            !inet_ifa_match(ifa1->ifa_address, ifa)) {
                                ifap1 = &ifa->ifa_next;
+                               prev_prom = ifa;
                                continue;
                        }
 
@@ -283,18 +289,32 @@ static void inet_del_ifa(struct in_devic
         */
        rtmsg_ifa(RTM_DELADDR, ifa1);
        notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
-       if (destroy) {
-               inet_free_ifa(ifa1);
-
-               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? */
+
+
+               if (prev_prom) {
+                       prev_prom->ifa_next = promote->ifa_next;
+                       promote->ifa_next = last_prim->ifa_next;
+                       last_prim->ifa_next = promote;
+               }
+
                promote->ifa_flags &= ~IFA_F_SECONDARY;
                rtmsg_ifa(RTM_NEWADDR, promote);
                notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote);
+               for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) {
+                       if (ifa1->ifa_mask != ifa->ifa_mask ||
+                           !inet_ifa_match(ifa1->ifa_address, ifa))
+                                       continue;
+                       fib_add_ifaddr(ifa);
+               }
+
+       }
+       if (destroy) {
+               inet_free_ifa(ifa1);
+
+               if (!in_dev->ifa_list)
+                       inetdev_destroy(in_dev);
        }
 }
 
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 2267c1f..92f6a53 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -407,7 +407,7 @@ static void fib_magic(int cmd, int type,
                tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
 }
 
-static void fib_add_ifaddr(struct in_ifaddr *ifa)
+void fib_add_ifaddr(struct in_ifaddr *ifa)
 {
        struct in_device *in_dev = ifa->ifa_dev;
        struct net_device *dev = in_dev->dev;
@@ -661,3 +661,4 @@ void __init ip_fib_init(void)
 
 EXPORT_SYMBOL(inet_addr_type);
 EXPORT_SYMBOL(ip_rt_ioctl);
+EXPORT_SYMBOL(fib_add_ifaddr);

Reply via email to