Skip to content

Commit

Permalink
net: Introduce L3 Master device abstraction
Browse files Browse the repository at this point in the history
L3 master devices allow users of the abstraction to influence FIB lookups
for enslaved devices. Current API provides a means for the master device
to return a specific FIB table for an enslaved device, to return an
rtable/custom dst and influence the OIF used for fib lookups.

Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David Ahern authored and davem330 committed Sep 30, 2015
1 parent 007979e commit 1b69c6d
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 0 deletions.
7 changes: 7 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -6095,6 +6095,13 @@ F: Documentation/auxdisplay/ks0108
F: drivers/auxdisplay/ks0108.c
F: include/linux/ks0108.h

L3MDEV
M: David Ahern <dsa@cumulusnetworks.com>
L: netdev@vger.kernel.org
S: Maintained
F: net/l3mdev
F: include/net/l3mdev.h

LAPB module
L: linux-x25@vger.kernel.org
S: Orphan
Expand Down
3 changes: 3 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -1587,6 +1587,9 @@ struct net_device {
#ifdef CONFIG_NET_SWITCHDEV
const struct switchdev_ops *switchdev_ops;
#endif
#ifdef CONFIG_NET_L3_MASTER_DEV
const struct l3mdev_ops *l3mdev_ops;
#endif

const struct header_ops *header_ops;

Expand Down
125 changes: 125 additions & 0 deletions include/net/l3mdev.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* include/net/l3mdev.h - L3 master device API
* Copyright (c) 2015 Cumulus Networks
* Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef _NET_L3MDEV_H_
#define _NET_L3MDEV_H_

/**
* struct l3mdev_ops - l3mdev operations
*
* @l3mdev_fib_table: Get FIB table id to use for lookups
*
* @l3mdev_get_rtable: Get cached IPv4 rtable (dst_entry) for device
*/

struct l3mdev_ops {
u32 (*l3mdev_fib_table)(const struct net_device *dev);
struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev,
const struct flowi4 *fl4);
};

#ifdef CONFIG_NET_L3_MASTER_DEV

int l3mdev_master_ifindex_rcu(struct net_device *dev);
static inline int l3mdev_master_ifindex(struct net_device *dev)
{
int ifindex;

rcu_read_lock();
ifindex = l3mdev_master_ifindex_rcu(dev);
rcu_read_unlock();

return ifindex;
}

/* get index of an interface to use for FIB lookups. For devices
* enslaved to an L3 master device FIB lookups are based on the
* master index
*/
static inline int l3mdev_fib_oif_rcu(struct net_device *dev)
{
return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex;
}

static inline int l3mdev_fib_oif(struct net_device *dev)
{
int oif;

rcu_read_lock();
oif = l3mdev_fib_oif_rcu(dev);
rcu_read_unlock();

return oif;
}

u32 l3mdev_fib_table_rcu(const struct net_device *dev);
u32 l3mdev_fib_table_by_index(struct net *net, int ifindex);
static inline u32 l3mdev_fib_table(const struct net_device *dev)
{
u32 tb_id;

rcu_read_lock();
tb_id = l3mdev_fib_table_rcu(dev);
rcu_read_unlock();

return tb_id;
}

static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev,
const struct flowi4 *fl4)
{
if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rtable)
return dev->l3mdev_ops->l3mdev_get_rtable(dev, fl4);

return NULL;
}

#else

static inline int l3mdev_master_ifindex_rcu(struct net_device *dev)
{
return 0;
}
static inline int l3mdev_master_ifindex(struct net_device *dev)
{
return 0;
}

static inline int l3mdev_fib_oif_rcu(struct net_device *dev)
{
return dev ? dev->ifindex : 0;
}
static inline int l3mdev_fib_oif(struct net_device *dev)
{
return dev ? dev->ifindex : 0;
}

static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev)
{
return 0;
}
static inline u32 l3mdev_fib_table(const struct net_device *dev)
{
return 0;
}
static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex)
{
return 0;
}

static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev,
const struct flowi4 *fl4)
{
return NULL;
}

#endif

#endif /* _NET_L3MDEV_H_ */
1 change: 1 addition & 0 deletions net/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ source "net/netlink/Kconfig"
source "net/mpls/Kconfig"
source "net/hsr/Kconfig"
source "net/switchdev/Kconfig"
source "net/l3mdev/Kconfig"

config RPS
bool
Expand Down
3 changes: 3 additions & 0 deletions net/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ obj-$(CONFIG_HSR) += hsr/
ifneq ($(CONFIG_NET_SWITCHDEV),)
obj-y += switchdev/
endif
ifneq ($(CONFIG_NET_L3_MASTER_DEV),)
obj-y += l3mdev/
endif
10 changes: 10 additions & 0 deletions net/l3mdev/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#
# Configuration for L3 master device support
#

config NET_L3_MASTER_DEV
bool "L3 Master device support"
depends on INET || IPV6
---help---
This module provides glue between core networking code and device
drivers to support L3 master devices like VRF.
5 changes: 5 additions & 0 deletions net/l3mdev/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# Makefile for the L3 device API
#

obj-$(CONFIG_NET_L3_MASTER_DEV) += l3mdev.o
92 changes: 92 additions & 0 deletions net/l3mdev/l3mdev.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* net/l3mdev/l3mdev.c - L3 master device implementation
* Copyright (c) 2015 Cumulus Networks
* Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

#include <linux/netdevice.h>
#include <net/l3mdev.h>

/**
* l3mdev_master_ifindex - get index of L3 master device
* @dev: targeted interface
*/

int l3mdev_master_ifindex_rcu(struct net_device *dev)
{
int ifindex = 0;

if (!dev)
return 0;

if (netif_is_l3_master(dev)) {
ifindex = dev->ifindex;
} else if (dev->flags & IFF_SLAVE) {
struct net_device *master;

master = netdev_master_upper_dev_get_rcu(dev);
if (master && netif_is_l3_master(master))
ifindex = master->ifindex;
}

return ifindex;
}
EXPORT_SYMBOL_GPL(l3mdev_master_ifindex_rcu);

/**
* l3mdev_fib_table - get FIB table id associated with an L3
* master interface
* @dev: targeted interface
*/

u32 l3mdev_fib_table_rcu(const struct net_device *dev)
{
u32 tb_id = 0;

if (!dev)
return 0;

if (netif_is_l3_master(dev)) {
if (dev->l3mdev_ops->l3mdev_fib_table)
tb_id = dev->l3mdev_ops->l3mdev_fib_table(dev);
} else if (dev->flags & IFF_SLAVE) {
/* Users of netdev_master_upper_dev_get_rcu need non-const,
* but current inet_*type functions take a const
*/
struct net_device *_dev = (struct net_device *) dev;
const struct net_device *master;

master = netdev_master_upper_dev_get_rcu(_dev);
if (master && netif_is_l3_master(master) &&
master->l3mdev_ops->l3mdev_fib_table)
tb_id = master->l3mdev_ops->l3mdev_fib_table(master);
}

return tb_id;
}
EXPORT_SYMBOL_GPL(l3mdev_fib_table_rcu);

u32 l3mdev_fib_table_by_index(struct net *net, int ifindex)
{
struct net_device *dev;
u32 tb_id = 0;

if (!ifindex)
return 0;

rcu_read_lock();

dev = dev_get_by_index_rcu(net, ifindex);
if (dev)
tb_id = l3mdev_fib_table_rcu(dev);

rcu_read_unlock();

return tb_id;
}
EXPORT_SYMBOL_GPL(l3mdev_fib_table_by_index);

0 comments on commit 1b69c6d

Please sign in to comment.