]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv4/fib_frontend.c
ipv4: Fix reverse path filtering with multipath routing.
[net-next-2.6.git] / net / ipv4 / fib_frontend.c
index 4f0ed458c883658c37265fe6537bde2ac8b88429..7d02a9f999fabcebeb61800816d722e6f6c054ff 100644 (file)
@@ -175,6 +175,7 @@ out:
        fib_res_put(&res);
        return dev;
 }
+EXPORT_SYMBOL(ip_dev_find);
 
 /*
  * Find address type as if only "dev" was present in the system. If
@@ -214,12 +215,14 @@ unsigned int inet_addr_type(struct net *net, __be32 addr)
 {
        return __inet_dev_addr_type(net, NULL, addr);
 }
+EXPORT_SYMBOL(inet_addr_type);
 
 unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
                                __be32 addr)
 {
        return __inet_dev_addr_type(net, dev, addr);
 }
+EXPORT_SYMBOL(inet_dev_addr_type);
 
 /* Given (packet source, input interface) and optional (dst, oif, tos):
    - (main) check, that source is valid i.e. not broadcast or our local
@@ -243,6 +246,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
 
        struct fib_result res;
        int no_addr, rpf, accept_local;
+       bool dev_match;
        int ret;
        struct net *net;
 
@@ -270,12 +274,22 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
        }
        *spec_dst = FIB_RES_PREFSRC(res);
        fib_combine_itag(itag, &res);
+       dev_match = false;
+
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
-       if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
+       for (ret = 0; ret < res.fi->fib_nhs; ret++) {
+               struct fib_nh *nh = &res.fi->fib_nh[ret];
+
+               if (nh->nh_dev == dev) {
+                       dev_match = true;
+                       break;
+               }
+       }
 #else
        if (FIB_RES_DEV(res) == dev)
+               dev_match = true;
 #endif
-       {
+       if (dev_match) {
                ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
                fib_res_put(&res);
                return ret;
@@ -284,7 +298,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
        if (no_addr)
                goto last_resort;
        if (rpf == 1)
-               goto e_inval;
+               goto e_rpf;
        fl.oif = dev->ifindex;
 
        ret = 0;
@@ -299,7 +313,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
 
 last_resort:
        if (rpf)
-               goto e_inval;
+               goto e_rpf;
        *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
        *itag = 0;
        return 0;
@@ -308,6 +322,8 @@ e_inval_res:
        fib_res_put(&res);
 e_inval:
        return -EINVAL;
+e_rpf:
+       return -EXDEV;
 }
 
 static inline __be32 sk_extract_addr(struct sockaddr *addr)
@@ -1075,7 +1091,3 @@ void __init ip_fib_init(void)
 
        fib_hash_init();
 }
-
-EXPORT_SYMBOL(inet_addr_type);
-EXPORT_SYMBOL(inet_dev_addr_type);
-EXPORT_SYMBOL(ip_dev_find);