net: l3mdev: prefer VRF master for source address selection
[deliverable/linux.git] / net / ipv4 / devinet.c
index cebd9d31e65a4a7539cab0bef71887736bc188f7..8c3df2ccba4581583130b7e90be25592c2449100 100644 (file)
@@ -1194,6 +1194,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
        __be32 addr = 0;
        struct in_device *in_dev;
        struct net *net = dev_net(dev);
+       int master_idx;
 
        rcu_read_lock();
        in_dev = __in_dev_get_rcu(dev);
@@ -1214,12 +1215,33 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
        if (addr)
                goto out_unlock;
 no_in_dev:
+       master_idx = l3mdev_master_ifindex_rcu(dev);
+
+       /* For VRFs, the VRF device takes the place of the loopback device,
+        * with addresses on it being preferred.  Note in such cases the
+        * loopback device will be among the devices that fail the master_idx
+        * equality check in the loop below.
+        */
+       if (master_idx &&
+           (dev = dev_get_by_index_rcu(net, master_idx)) &&
+           (in_dev = __in_dev_get_rcu(dev))) {
+               for_primary_ifa(in_dev) {
+                       if (ifa->ifa_scope != RT_SCOPE_LINK &&
+                           ifa->ifa_scope <= scope) {
+                               addr = ifa->ifa_local;
+                               goto out_unlock;
+                       }
+               } endfor_ifa(in_dev);
+       }
 
        /* Not loopback addresses on loopback should be preferred
           in this case. It is important that lo is the first interface
           in dev_base list.
         */
        for_each_netdev_rcu(net, dev) {
+               if (l3mdev_master_ifindex_rcu(dev) != master_idx)
+                       continue;
+
                in_dev = __in_dev_get_rcu(dev);
                if (!in_dev)
                        continue;
@@ -1847,7 +1869,7 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb,
        if (err < 0)
                goto errout;
 
-       err = EINVAL;
+       err = -EINVAL;
        if (!tb[NETCONFA_IFINDEX])
                goto errout;
 
@@ -2185,6 +2207,8 @@ static struct devinet_sysctl_table {
                                        "igmpv3_unsolicited_report_interval"),
                DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
                                        "ignore_routes_with_linkdown"),
+               DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
+                                       "drop_gratuitous_arp"),
 
                DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
                DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
@@ -2192,6 +2216,8 @@ static struct devinet_sysctl_table {
                                              "promote_secondaries"),
                DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
                                              "route_localnet"),
+               DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
+                                             "drop_unicast_in_l2_multicast"),
        },
 };
 
This page took 0.024955 seconds and 5 git commands to generate.