summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-09-29 20:41:10 -0700
committerDavid S. Miller <davem@davemloft.net>2015-09-29 20:41:10 -0700
commitf82ff596c7a8917b21100117646c719017ce8fe4 (patch)
treec5106779c21e734397a7bedf8ddf7f9002d478cd /drivers
parente6934f3ec00b04234acb24a1a2c28af59763d3b5 (diff)
parent9478d12d33ad12d29c5343ae7346b51bc1f4c5a9 (diff)
Merge branch 'L3_master_device'
David Ahern says: ==================== net: L3 master device The VRF device is essentially a Layer 3 master device used to associate netdevices with a specific routing table and to influence FIB lookups via 'ip rules' and controlling the oif/iif used for the lookup. This series generalizes the VRF into L3 master device, l3mdev. Similar to switchdev it has a Kconfig option and separate set of operations in net_device allowing it to be completely compiled out if not wanted. The l3mdev methods rely on the 'master' aspect and use of netdev_master_upper_dev_get_rcu to retrieve the master device from a given netdevice if it is enslaved to an L3_MASTER. The VRF device is converted to use the l3mdev operations. At the end the vrf_ptr is no longer and removed, as are all direct references to VRF. The end result is a much simpler implementation for VRF. Thanks to Nikolay for suggestions (eg., use of the master linkage which is the key to making this work) and to Roopa, Andy and Shrijeet for early reviews. v3 - added license header to l3mdev.c - export symbols in l3mdev.c for use with GPL modules - removed netdevice header from l3mdev.h (not needed) and fixed typo in comment v2 - rebased to top of net-next - addressed Niks comments (checking master, removing extra lines, and flipping the order of patches 1 and 2) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/Kconfig1
-rw-r--r--drivers/net/vrf.c81
2 files changed, 49 insertions, 33 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d18eb607bee6..b9ebd0d18a52 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -299,6 +299,7 @@ config NLMON
config NET_VRF
tristate "Virtual Routing and Forwarding (Lite)"
depends on IP_MULTIPLE_TABLES && IPV6_MULTIPLE_TABLES
+ depends on NET_L3_MASTER_DEV
---help---
This option enables the support for mapping interfaces into VRF's. The
support enables VRF devices.
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 4ecb3a3e516a..64f2ab663ffe 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -34,7 +34,7 @@
#include <net/rtnetlink.h>
#include <net/route.h>
#include <net/addrconf.h>
-#include <net/vrf.h>
+#include <net/l3mdev.h>
#define DRV_NAME "vrf"
#define DRV_VERSION "1.0"
@@ -44,6 +44,21 @@
#define vrf_master_get_rcu(dev) \
((struct net_device *)rcu_dereference(dev->rx_handler_data))
+struct slave {
+ struct list_head list;
+ struct net_device *dev;
+};
+
+struct slave_queue {
+ struct list_head all_slaves;
+};
+
+struct net_vrf {
+ struct slave_queue queue;
+ struct rtable *rth;
+ u32 tb_id;
+};
+
struct pcpu_dstats {
u64 tx_pkts;
u64 tx_bytes;
@@ -395,18 +410,15 @@ static void __vrf_insert_slave(struct slave_queue *queue, struct slave *slave)
static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev)
{
- struct net_vrf_dev *vrf_ptr = kmalloc(sizeof(*vrf_ptr), GFP_KERNEL);
struct slave *slave = kzalloc(sizeof(*slave), GFP_KERNEL);
struct net_vrf *vrf = netdev_priv(dev);
struct slave_queue *queue = &vrf->queue;
int ret = -ENOMEM;
- if (!slave || !vrf_ptr)
+ if (!slave)
goto out_fail;
slave->dev = port_dev;
- vrf_ptr->ifindex = dev->ifindex;
- vrf_ptr->tb_id = vrf->tb_id;
/* register the packet handler for slave ports */
ret = netdev_rx_handler_register(port_dev, vrf_handle_frame, dev);
@@ -423,7 +435,6 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev)
port_dev->flags |= IFF_SLAVE;
__vrf_insert_slave(queue, slave);
- rcu_assign_pointer(port_dev->vrf_ptr, vrf_ptr);
cycle_netdev(port_dev);
return 0;
@@ -431,14 +442,13 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev)
out_unregister:
netdev_rx_handler_unregister(port_dev);
out_fail:
- kfree(vrf_ptr);
kfree(slave);
return ret;
}
static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev)
{
- if (netif_is_vrf(port_dev) || vrf_is_slave(port_dev))
+ if (netif_is_l3_master(port_dev) || vrf_is_slave(port_dev))
return -EINVAL;
return do_vrf_add_slave(dev, port_dev);
@@ -447,21 +457,15 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev)
/* inverse of do_vrf_add_slave */
static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev)
{
- struct net_vrf_dev *vrf_ptr = rtnl_dereference(port_dev->vrf_ptr);
struct net_vrf *vrf = netdev_priv(dev);
struct slave_queue *queue = &vrf->queue;
struct slave *slave;
- RCU_INIT_POINTER(port_dev->vrf_ptr, NULL);
-
netdev_upper_dev_unlink(port_dev, dev);
port_dev->flags &= ~IFF_SLAVE;
netdev_rx_handler_unregister(port_dev);
- /* after netdev_rx_handler_unregister for synchronize_rcu */
- kfree(vrf_ptr);
-
cycle_netdev(port_dev);
slave = __vrf_find_slave_dev(queue, port_dev);
@@ -529,6 +533,33 @@ static const struct net_device_ops vrf_netdev_ops = {
.ndo_del_slave = vrf_del_slave,
};
+static u32 vrf_fib_table(const struct net_device *dev)
+{
+ struct net_vrf *vrf = netdev_priv(dev);
+
+ return vrf->tb_id;
+}
+
+static struct rtable *vrf_get_rtable(const struct net_device *dev,
+ const struct flowi4 *fl4)
+{
+ struct rtable *rth = NULL;
+
+ if (!(fl4->flowi4_flags & FLOWI_FLAG_VRFSRC)) {
+ struct net_vrf *vrf = netdev_priv(dev);
+
+ rth = vrf->rth;
+ atomic_inc(&rth->dst.__refcnt);
+ }
+
+ return rth;
+}
+
+static const struct l3mdev_ops vrf_l3mdev_ops = {
+ .l3mdev_fib_table = vrf_fib_table,
+ .l3mdev_get_rtable = vrf_get_rtable,
+};
+
static void vrf_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
@@ -546,6 +577,7 @@ static void vrf_setup(struct net_device *dev)
/* Initialize the device structure. */
dev->netdev_ops = &vrf_netdev_ops;
+ dev->l3mdev_ops = &vrf_l3mdev_ops;
dev->ethtool_ops = &vrf_ethtool_ops;
dev->destructor = free_netdev;
@@ -572,10 +604,6 @@ static int vrf_validate(struct nlattr *tb[], struct nlattr *data[])
static void vrf_dellink(struct net_device *dev, struct list_head *head)
{
- struct net_vrf_dev *vrf_ptr = rtnl_dereference(dev->vrf_ptr);
-
- RCU_INIT_POINTER(dev->vrf_ptr, NULL);
- kfree_rcu(vrf_ptr, rcu);
unregister_netdevice_queue(dev, head);
}
@@ -583,7 +611,6 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct net_vrf *vrf = netdev_priv(dev);
- struct net_vrf_dev *vrf_ptr;
int err;
if (!data || !data[IFLA_VRF_TABLE])
@@ -591,26 +618,15 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev,
vrf->tb_id = nla_get_u32(data[IFLA_VRF_TABLE]);
- dev->priv_flags |= IFF_VRF_MASTER;
-
- err = -ENOMEM;
- vrf_ptr = kmalloc(sizeof(*dev->vrf_ptr), GFP_KERNEL);
- if (!vrf_ptr)
- goto out_fail;
-
- vrf_ptr->ifindex = dev->ifindex;
- vrf_ptr->tb_id = vrf->tb_id;
+ dev->priv_flags |= IFF_L3MDEV_MASTER;
err = register_netdevice(dev);
if (err < 0)
goto out_fail;
- rcu_assign_pointer(dev->vrf_ptr, vrf_ptr);
-
return 0;
out_fail:
- kfree(vrf_ptr);
free_netdev(dev);
return err;
}
@@ -654,10 +670,9 @@ static int vrf_device_event(struct notifier_block *unused,
/* only care about unregister events to drop slave references */
if (event == NETDEV_UNREGISTER) {
- struct net_vrf_dev *vrf_ptr = rtnl_dereference(dev->vrf_ptr);
struct net_device *vrf_dev;
- if (!vrf_ptr || netif_is_vrf(dev))
+ if (netif_is_l3_master(dev))
goto out;
vrf_dev = netdev_master_upper_dev_get(dev);