Commit 20e61335 authored by David S. Miller's avatar David S. Miller

Merge branch 'l3mdev-send-enslaved'

David Ahern says:

====================
net: l3mdev: Allow send on enslaved interface

First patch preps for the second. The second is required for several use
cases such as ping on an interface and BFD that need to send packets on
a specific interface, including ones enslaved to a VRF device.

v2
- fixed brackets on both patches per comment from DaveM
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 27c0f739 1ff23bee
......@@ -648,6 +648,8 @@ static int vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
fl4->flowi4_flags |= FLOWI_FLAG_SKIP_NH_OIF;
fl4->flowi4_iif = LOOPBACK_IFINDEX;
/* make sure oif is set to VRF device for lookup */
fl4->flowi4_oif = dev->ifindex;
fl4->flowi4_tos = tos & IPTOS_RT_MASK;
fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
......
......@@ -130,52 +130,9 @@ static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
return rc;
}
static inline int l3mdev_get_saddr(struct net *net, int ifindex,
struct flowi4 *fl4)
{
struct net_device *dev;
int rc = 0;
if (ifindex) {
rcu_read_lock();
dev = dev_get_by_index_rcu(net, ifindex);
if (dev && netif_is_l3_master(dev) &&
dev->l3mdev_ops->l3mdev_get_saddr) {
rc = dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4);
}
rcu_read_unlock();
}
return rc;
}
int l3mdev_get_saddr(struct net *net, int ifindex, struct flowi4 *fl4);
static inline struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev,
const struct flowi6 *fl6)
{
if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rt6_dst)
return dev->l3mdev_ops->l3mdev_get_rt6_dst(dev, fl6);
return NULL;
}
static inline
struct dst_entry *l3mdev_rt6_dst_by_oif(struct net *net,
const struct flowi6 *fl6)
{
struct dst_entry *dst = NULL;
struct net_device *dev;
dev = dev_get_by_index(net, fl6->flowi6_oif);
if (dev) {
dst = l3mdev_get_rt6_dst(dev, fl6);
dev_put(dev);
}
return dst;
}
struct dst_entry *l3mdev_get_rt6_dst(struct net *net, const struct flowi6 *fl6);
#else
......@@ -233,14 +190,7 @@ static inline int l3mdev_get_saddr(struct net *net, int ifindex,
}
static inline
struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev,
const struct flowi6 *fl6)
{
return NULL;
}
static inline
struct dst_entry *l3mdev_rt6_dst_by_oif(struct net *net,
const struct flowi6 *fl6)
struct dst_entry *l3mdev_get_rt6_dst(struct net *net, const struct flowi6 *fl6)
{
return NULL;
}
......
......@@ -2146,6 +2146,7 @@ struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4,
unsigned int flags = 0;
struct fib_result res;
struct rtable *rth;
int master_idx;
int orig_oif;
int err = -ENETUNREACH;
......@@ -2155,6 +2156,9 @@ struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4,
orig_oif = fl4->flowi4_oif;
master_idx = l3mdev_master_ifindex_by_index(net, fl4->flowi4_oif);
if (master_idx)
fl4->flowi4_oif = master_idx;
fl4->flowi4_iif = LOOPBACK_IFINDEX;
fl4->flowi4_tos = tos & IPTOS_RT_MASK;
fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
......
......@@ -1190,7 +1190,7 @@ struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
struct dst_entry *dst;
bool any_src;
dst = l3mdev_rt6_dst_by_oif(net, fl6);
dst = l3mdev_get_rt6_dst(net, fl6);
if (dst)
return dst;
......
......@@ -97,3 +97,66 @@ u32 l3mdev_fib_table_by_index(struct net *net, int ifindex)
return tb_id;
}
EXPORT_SYMBOL_GPL(l3mdev_fib_table_by_index);
/**
* l3mdev_get_rt6_dst - IPv6 route lookup based on flow. Returns
* cached route for L3 master device if relevant
* to flow
* @net: network namespace for device index lookup
* @fl6: IPv6 flow struct for lookup
*/
struct dst_entry *l3mdev_get_rt6_dst(struct net *net,
const struct flowi6 *fl6)
{
struct dst_entry *dst = NULL;
struct net_device *dev;
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_rt6_dst)
dst = dev->l3mdev_ops->l3mdev_get_rt6_dst(dev, fl6);
rcu_read_unlock();
}
return dst;
}
EXPORT_SYMBOL_GPL(l3mdev_get_rt6_dst);
/**
* l3mdev_get_saddr - get source address for a flow based on an interface
* enslaved to an L3 master device
* @net: network namespace for device index lookup
* @ifindex: Interface index
* @fl4: IPv4 flow struct
*/
int l3mdev_get_saddr(struct net *net, int ifindex, struct flowi4 *fl4)
{
struct net_device *dev;
int rc = 0;
if (ifindex) {
rcu_read_lock();
dev = dev_get_by_index_rcu(net, ifindex);
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_saddr)
rc = dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4);
rcu_read_unlock();
}
return rc;
}
EXPORT_SYMBOL_GPL(l3mdev_get_saddr);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment