diff options
author | David Ahern <dsa@cumulusnetworks.com> | 2016-05-07 19:49:00 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-05-09 22:33:52 -0400 |
commit | 1ff23beebdd315fe4d16070c08c065e89d7debb3 (patch) | |
tree | f82066e771ed276e9b9eb5f93b5b0f28ca1061a2 | |
parent | 4a65896f94fa82370041823837cd75aac1186b54 (diff) |
net: l3mdev: Allow send on enslaved interface
Allow udp and raw sockets to send by oif that is an enslaved interface
versus the l3mdev/VRF device. For example, this allows BFD to use ifindex
from IP_PKTINFO on a receive to send a response without the need to
convert to the VRF index. It also allows ping and ping6 to work when
specifying an enslaved interface (e.g., ping -I swp1 <ip>) which is
a natural use case.
Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/vrf.c | 2 | ||||
-rw-r--r-- | net/ipv4/route.c | 4 | ||||
-rw-r--r-- | net/l3mdev/l3mdev.c | 17 |
3 files changed, 19 insertions, 4 deletions
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 4b2461ae5d3b..c8db55aa8280 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c | |||
@@ -648,6 +648,8 @@ static int vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4) | |||
648 | 648 | ||
649 | fl4->flowi4_flags |= FLOWI_FLAG_SKIP_NH_OIF; | 649 | fl4->flowi4_flags |= FLOWI_FLAG_SKIP_NH_OIF; |
650 | fl4->flowi4_iif = LOOPBACK_IFINDEX; | 650 | fl4->flowi4_iif = LOOPBACK_IFINDEX; |
651 | /* make sure oif is set to VRF device for lookup */ | ||
652 | fl4->flowi4_oif = dev->ifindex; | ||
651 | fl4->flowi4_tos = tos & IPTOS_RT_MASK; | 653 | fl4->flowi4_tos = tos & IPTOS_RT_MASK; |
652 | fl4->flowi4_scope = ((tos & RTO_ONLINK) ? | 654 | fl4->flowi4_scope = ((tos & RTO_ONLINK) ? |
653 | RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); | 655 | RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 8c8c655bb2c4..a1f2830d8110 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2146,6 +2146,7 @@ struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4, | |||
2146 | unsigned int flags = 0; | 2146 | unsigned int flags = 0; |
2147 | struct fib_result res; | 2147 | struct fib_result res; |
2148 | struct rtable *rth; | 2148 | struct rtable *rth; |
2149 | int master_idx; | ||
2149 | int orig_oif; | 2150 | int orig_oif; |
2150 | int err = -ENETUNREACH; | 2151 | int err = -ENETUNREACH; |
2151 | 2152 | ||
@@ -2155,6 +2156,9 @@ struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4, | |||
2155 | 2156 | ||
2156 | orig_oif = fl4->flowi4_oif; | 2157 | orig_oif = fl4->flowi4_oif; |
2157 | 2158 | ||
2159 | master_idx = l3mdev_master_ifindex_by_index(net, fl4->flowi4_oif); | ||
2160 | if (master_idx) | ||
2161 | fl4->flowi4_oif = master_idx; | ||
2158 | fl4->flowi4_iif = LOOPBACK_IFINDEX; | 2162 | fl4->flowi4_iif = LOOPBACK_IFINDEX; |
2159 | fl4->flowi4_tos = tos & IPTOS_RT_MASK; | 2163 | fl4->flowi4_tos = tos & IPTOS_RT_MASK; |
2160 | fl4->flowi4_scope = ((tos & RTO_ONLINK) ? | 2164 | fl4->flowi4_scope = ((tos & RTO_ONLINK) ? |
diff --git a/net/l3mdev/l3mdev.c b/net/l3mdev/l3mdev.c index 898d01e0f87b..6651a78e100c 100644 --- a/net/l3mdev/l3mdev.c +++ b/net/l3mdev/l3mdev.c | |||
@@ -112,12 +112,18 @@ struct dst_entry *l3mdev_get_rt6_dst(struct net *net, | |||
112 | struct dst_entry *dst = NULL; | 112 | struct dst_entry *dst = NULL; |
113 | struct net_device *dev; | 113 | struct net_device *dev; |
114 | 114 | ||
115 | dev = dev_get_by_index(net, fl6->flowi6_oif); | 115 | if (fl6->flowi6_oif) { |
116 | if (dev) { | 116 | rcu_read_lock(); |
117 | if (netif_is_l3_master(dev) && | 117 | |
118 | dev = dev_get_by_index_rcu(net, fl6->flowi6_oif); | ||
119 | if (dev && netif_is_l3_slave(dev)) | ||
120 | dev = netdev_master_upper_dev_get_rcu(dev); | ||
121 | |||
122 | if (dev && netif_is_l3_master(dev) && | ||
118 | dev->l3mdev_ops->l3mdev_get_rt6_dst) | 123 | dev->l3mdev_ops->l3mdev_get_rt6_dst) |
119 | dst = dev->l3mdev_ops->l3mdev_get_rt6_dst(dev, fl6); | 124 | dst = dev->l3mdev_ops->l3mdev_get_rt6_dst(dev, fl6); |
120 | dev_put(dev); | 125 | |
126 | rcu_read_unlock(); | ||
121 | } | 127 | } |
122 | 128 | ||
123 | return dst; | 129 | return dst; |
@@ -141,6 +147,9 @@ int l3mdev_get_saddr(struct net *net, int ifindex, struct flowi4 *fl4) | |||
141 | rcu_read_lock(); | 147 | rcu_read_lock(); |
142 | 148 | ||
143 | dev = dev_get_by_index_rcu(net, ifindex); | 149 | dev = dev_get_by_index_rcu(net, ifindex); |
150 | if (dev && netif_is_l3_slave(dev)) | ||
151 | dev = netdev_master_upper_dev_get_rcu(dev); | ||
152 | |||
144 | if (dev && netif_is_l3_master(dev) && | 153 | if (dev && netif_is_l3_master(dev) && |
145 | dev->l3mdev_ops->l3mdev_get_saddr) | 154 | dev->l3mdev_ops->l3mdev_get_saddr) |
146 | rc = dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4); | 155 | rc = dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4); |