From: Daniel Lezcano <[EMAIL PROTECTED]>

When no source address is specified, search from the dev list the
ifaddr allowed to be used as source address.

Signed-off-by: Daniel Lezcano <[EMAIL PROTECTED]>

---
 include/linux/net_namespace.h |   14 ++++++++
 net/core/net_namespace.c      |   68 ++++++++++++++++++++++++++++++++++++++++++
 net/ipv4/route.c              |   28 +++++++++++------
 3 files changed, 100 insertions(+), 10 deletions(-)

Index: 2.6.20-rc4-mm1/net/ipv4/route.c
===================================================================
--- 2.6.20-rc4-mm1.orig/net/ipv4/route.c
+++ 2.6.20-rc4-mm1/net/ipv4/route.c
@@ -2475,17 +2475,17 @@
 
                if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst == 
htonl(0xFFFFFFFF)) {
                        if (!fl.fl4_src)
-                               fl.fl4_src = inet_select_addr(dev_out, 0,
-                                                             RT_SCOPE_LINK);
+                               fl.fl4_src = SELECT_SRC_ADDR(dev_out, 0,
+                                                            RT_SCOPE_LINK);
                        goto make_route;
                }
                if (!fl.fl4_src) {
                        if (MULTICAST(oldflp->fl4_dst))
-                               fl.fl4_src = inet_select_addr(dev_out, 0,
-                                                             fl.fl4_scope);
+                               fl.fl4_src = SELECT_SRC_ADDR(dev_out, 0,
+                                                            fl.fl4_scope);
                        else if (!oldflp->fl4_dst)
-                               fl.fl4_src = inet_select_addr(dev_out, 0,
-                                                             RT_SCOPE_HOST);
+                               fl.fl4_src = SELECT_SRC_ADDR(dev_out, 0,
+                                                            RT_SCOPE_HOST);
                }
        }
 
@@ -2525,8 +2525,8 @@
                         */
 
                        if (fl.fl4_src == 0)
-                               fl.fl4_src = inet_select_addr(dev_out, 0,
-                                                             RT_SCOPE_LINK);
+                               fl.fl4_src = SELECT_SRC_ADDR(dev_out, 0,
+                                                            RT_SCOPE_LINK);
                        res.type = RTN_UNICAST;
                        goto make_route;
                }
@@ -2539,7 +2539,13 @@
 
        if (res.type == RTN_LOCAL) {
                if (!fl.fl4_src)
+#ifdef CONFIG_NET_NS
+                       fl.fl4_src = net_ns_select_source_address(dev_out,
+                                                                 fl.fl4_dst,
+                                                                 
RT_SCOPE_LINK);
+#else
                        fl.fl4_src = fl.fl4_dst;
+#endif
                if (dev_out)
                        dev_put(dev_out);
                dev_out = &loopback_dev;
@@ -2561,8 +2567,10 @@
                fib_select_default(&fl, &res);
 
        if (!fl.fl4_src)
-               fl.fl4_src = FIB_RES_PREFSRC(res);
-
+               fl.fl4_src = res.fi->fib_prefsrc ? :
+                       SELECT_SRC_ADDR(FIB_RES_DEV(res),
+                                       FIB_RES_GW(res),
+                                       res.scope);
        if (dev_out)
                dev_put(dev_out);
        dev_out = FIB_RES_DEV(res);
Index: 2.6.20-rc4-mm1/include/linux/net_namespace.h
===================================================================
--- 2.6.20-rc4-mm1.orig/include/linux/net_namespace.h
+++ 2.6.20-rc4-mm1/include/linux/net_namespace.h
@@ -5,6 +5,7 @@
 #include <linux/kref.h>
 #include <linux/nsproxy.h>
 #include <linux/errno.h>
+#include <linux/types.h>
 
 struct net_namespace {
        struct kref             kref;
@@ -95,6 +96,11 @@
 
 extern int net_ns_check_bind(int addr_type, u32 addr);
 
+extern __be32 net_ns_select_source_address(const struct net_device *dev,
+                                          u32 dst, int scope);
+
+#define SELECT_SRC_ADDR net_ns_select_source_address
+
 #else /* CONFIG_NET_NS */
 
 #define INIT_NET_NS(net_ns)
@@ -155,6 +161,14 @@
        return 0;
 }
 
+static inline __be32 net_ns_select_source_address(struct net_device *dev,
+                                                 u32 dst, int scope)
+{
+       return 0;
+}
+
+#define SELECT_SRC_ADDR inet_select_addr
+
 #endif /* !CONFIG_NET_NS */
 
 #endif /* _LINUX_NET_NAMESPACE_H */
Index: 2.6.20-rc4-mm1/net/core/net_namespace.c
===================================================================
--- 2.6.20-rc4-mm1.orig/net/core/net_namespace.c
+++ 2.6.20-rc4-mm1/net/core/net_namespace.c
@@ -317,4 +317,72 @@
        return ret;
 }
 
+/*
+ * This function choose the source address from the network device,
+ * destination and the scope. The function will browse the ifaddr
+ * owned by network namespace and choose the most adapted for the
+ * dst address and dev.
+ * @dev : the network device where the traffic will go
+ * @dst : the destination address
+ * @scope : the scope of the dst address
+ * Returns: a source address
+ */
+__be32 net_ns_select_source_address(const struct net_device *dev,
+                                   u32 dst, int scope)
+{
+       __be32 addr = 0;
+       struct in_device *in_dev;
+       struct net_namespace *net_ns = current_net_ns;
+
+       if (LOOPBACK(dst))
+           return htonl(INADDR_LOOPBACK);
+
+       if (!dev)
+               goto no_dev;
+
+       rcu_read_lock();
+       in_dev = __in_dev_get_rcu(dev);
+       if (!in_dev)
+               goto no_in_dev;
+
+       for_ifa(in_dev) {
+               if (ifa->ifa_scope > scope)
+                       continue;
+               if (ifa->ifa_net_ns != net_ns)
+                       continue;
+               if (!dst || inet_ifa_match(dst, ifa)) {
+                       addr = ifa->ifa_local;
+                       break;
+               }
+               if (!addr)
+                       addr = ifa->ifa_local;
+       } endfor_ifa(in_dev);
+no_in_dev:
+       rcu_read_unlock();
+
+       if (addr)
+               goto out;
+
+no_dev:
+       read_lock(&dev_base_lock);
+       rcu_read_lock();
+       for (dev = dev_base; dev; dev = dev->next) {
+               if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
+                       continue;
+
+               for_ifa(in_dev) {
+                       if (ifa->ifa_scope != RT_SCOPE_LINK &&
+                           ifa->ifa_scope <= scope &&
+                           ifa->ifa_net_ns == net_ns) {
+                               addr = ifa->ifa_local;
+                               goto out_unlock_both;
+                       }
+               } endfor_ifa(in_dev);
+       }
+out_unlock_both:
+       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
+out:
+       return addr;
+}
 #endif /* CONFIG_NET_NS */

-- 
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to