Commit 5f02ce24 authored by David Ahern's avatar David Ahern Committed by David S. Miller

net: l3mdev: Allow the l3mdev to be a loopback

Allow an L3 master device to act as the loopback for that L3 domain.
For IPv4 the device can also have the address 127.0.0.1.
Signed-off-by: default avatarDavid Ahern <dsa@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a8e3e1a9
...@@ -90,7 +90,7 @@ static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) ...@@ -90,7 +90,7 @@ static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
} }
static inline static inline
const struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev) struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev)
{ {
/* netdev_master_upper_dev_get_rcu calls /* netdev_master_upper_dev_get_rcu calls
* list_first_or_null_rcu to walk the upper dev list. * list_first_or_null_rcu to walk the upper dev list.
...@@ -99,7 +99,7 @@ const struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev) ...@@ -99,7 +99,7 @@ const struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev)
* typecast to remove the const * typecast to remove the const
*/ */
struct net_device *dev = (struct net_device *)_dev; struct net_device *dev = (struct net_device *)_dev;
const struct net_device *master; struct net_device *master;
if (!dev) if (!dev)
return NULL; return NULL;
...@@ -254,7 +254,7 @@ static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) ...@@ -254,7 +254,7 @@ static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
} }
static inline static inline
const struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev) struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev)
{ {
return NULL; return NULL;
} }
......
...@@ -2018,7 +2018,9 @@ static struct rtable *__mkroute_output(const struct fib_result *res, ...@@ -2018,7 +2018,9 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (likely(!IN_DEV_ROUTE_LOCALNET(in_dev))) if (likely(!IN_DEV_ROUTE_LOCALNET(in_dev)))
if (ipv4_is_loopback(fl4->saddr) && !(dev_out->flags & IFF_LOOPBACK)) if (ipv4_is_loopback(fl4->saddr) &&
!(dev_out->flags & IFF_LOOPBACK) &&
!netif_is_l3_master(dev_out))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (ipv4_is_lbcast(fl4->daddr)) if (ipv4_is_lbcast(fl4->daddr))
...@@ -2302,7 +2304,9 @@ struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4, ...@@ -2302,7 +2304,9 @@ struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4,
else else
fl4->saddr = fl4->daddr; fl4->saddr = fl4->daddr;
} }
dev_out = net->loopback_dev;
/* L3 master device is the loopback for that domain */
dev_out = l3mdev_master_dev_rcu(dev_out) ? : net->loopback_dev;
fl4->flowi4_oif = dev_out->ifindex; fl4->flowi4_oif = dev_out->ifindex;
flags |= RTCF_LOCAL; flags |= RTCF_LOCAL;
goto make_route; goto make_route;
......
...@@ -2558,8 +2558,16 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, ...@@ -2558,8 +2558,16 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
{ {
u32 tb_id; u32 tb_id;
struct net *net = dev_net(idev->dev); struct net *net = dev_net(idev->dev);
struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, struct net_device *dev = net->loopback_dev;
DST_NOCOUNT); struct rt6_info *rt;
/* use L3 Master device as loopback for host routes if device
* is enslaved and address is not link local or multicast
*/
if (!rt6_need_strict(addr))
dev = l3mdev_master_dev_rcu(idev->dev) ? : dev;
rt = ip6_dst_alloc(net, dev, DST_NOCOUNT);
if (!rt) if (!rt)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
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