Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / net / l3mdev / l3mdev.c
index 6651a78..c4a1c3e 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/netdevice.h>
+#include <net/fib_rules.h>
 #include <net/l3mdev.h>
 
 /**
@@ -107,7 +108,7 @@ EXPORT_SYMBOL_GPL(l3mdev_fib_table_by_index);
  */
 
 struct dst_entry *l3mdev_get_rt6_dst(struct net *net,
-                                    const struct flowi6 *fl6)
+                                    struct flowi6 *fl6)
 {
        struct dst_entry *dst = NULL;
        struct net_device *dev;
@@ -160,3 +161,64 @@ int l3mdev_get_saddr(struct net *net, int ifindex, struct flowi4 *fl4)
        return rc;
 }
 EXPORT_SYMBOL_GPL(l3mdev_get_saddr);
+
+int l3mdev_get_saddr6(struct net *net, const struct sock *sk,
+                     struct flowi6 *fl6)
+{
+       struct net_device *dev;
+       int rc = 0;
+
+       if (fl6->flowi6_oif) {
+               rcu_read_lock();
+
+               dev = dev_get_by_index_rcu(net, fl6->flowi6_oif);
+               if (dev && netif_is_l3_slave(dev))
+                       dev = netdev_master_upper_dev_get_rcu(dev);
+
+               if (dev && netif_is_l3_master(dev) &&
+                   dev->l3mdev_ops->l3mdev_get_saddr6)
+                       rc = dev->l3mdev_ops->l3mdev_get_saddr6(dev, sk, fl6);
+
+               rcu_read_unlock();
+       }
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(l3mdev_get_saddr6);
+
+/**
+ *     l3mdev_fib_rule_match - Determine if flowi references an
+ *                             L3 master device
+ *     @net: network namespace for device index lookup
+ *     @fl:  flow struct
+ */
+
+int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
+                         struct fib_lookup_arg *arg)
+{
+       struct net_device *dev;
+       int rc = 0;
+
+       rcu_read_lock();
+
+       dev = dev_get_by_index_rcu(net, fl->flowi_oif);
+       if (dev && netif_is_l3_master(dev) &&
+           dev->l3mdev_ops->l3mdev_fib_table) {
+               arg->table = dev->l3mdev_ops->l3mdev_fib_table(dev);
+               rc = 1;
+               goto out;
+       }
+
+       dev = dev_get_by_index_rcu(net, fl->flowi_iif);
+       if (dev && netif_is_l3_master(dev) &&
+           dev->l3mdev_ops->l3mdev_fib_table) {
+               arg->table = dev->l3mdev_ops->l3mdev_fib_table(dev);
+               rc = 1;
+               goto out;
+       }
+
+out:
+       rcu_read_unlock();
+
+       return rc;
+}