Skip to content

Commit

Permalink
net: l3mdev: Allow the l3mdev to be a loopback
Browse files Browse the repository at this point in the history
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: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David Ahern authored and David S. Miller committed Sep 11, 2016
1 parent a8e3e1a commit 5f02ce2
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 7 deletions.
6 changes: 3 additions & 3 deletions include/net/l3mdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
}

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
* list_first_or_null_rcu to walk the upper dev list.
Expand All @@ -99,7 +99,7 @@ const struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev)
* typecast to remove the const
*/
struct net_device *dev = (struct net_device *)_dev;
const struct net_device *master;
struct net_device *master;

if (!dev)
return NULL;
Expand Down Expand Up @@ -254,7 +254,7 @@ static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
}

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;
}
Expand Down
8 changes: 6 additions & 2 deletions net/ipv4/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -2018,7 +2018,9 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
return ERR_PTR(-EINVAL);

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);

if (ipv4_is_lbcast(fl4->daddr))
Expand Down Expand Up @@ -2302,7 +2304,9 @@ struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4,
else
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;
flags |= RTCF_LOCAL;
goto make_route;
Expand Down
12 changes: 10 additions & 2 deletions net/ipv6/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -2558,8 +2558,16 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
{
u32 tb_id;
struct net *net = dev_net(idev->dev);
struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
DST_NOCOUNT);
struct net_device *dev = net->loopback_dev;
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)
return ERR_PTR(-ENOMEM);

Expand Down

0 comments on commit 5f02ce2

Please sign in to comment.