aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ahern <dsa@cumulusnetworks.com>2015-09-29 23:07:11 -0400
committerDavid S. Miller <davem@davemloft.net>2015-09-29 23:40:32 -0400
commit1b69c6d0ae90b7f1a4f61d5c8209d5cb7a55f849 (patch)
tree5c32b6f77817a51e86d333e59ae48bdae7b593ad
parent007979eaf94d1c888d8c7cf8a5250c2c6c9bd98e (diff)
net: Introduce L3 Master device abstraction
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>
-rw-r--r--MAINTAINERS7
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--include/net/l3mdev.h125
-rw-r--r--net/Kconfig1
-rw-r--r--net/Makefile3
-rw-r--r--net/l3mdev/Kconfig10
-rw-r--r--net/l3mdev/Makefile5
-rw-r--r--net/l3mdev/l3mdev.c92
8 files changed, 246 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index bcd263de4827..3f2d7a9d0bbf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6095,6 +6095,13 @@ F: Documentation/auxdisplay/ks0108
6095F: drivers/auxdisplay/ks0108.c 6095F: drivers/auxdisplay/ks0108.c
6096F: include/linux/ks0108.h 6096F: include/linux/ks0108.h
6097 6097
6098L3MDEV
6099M: David Ahern <dsa@cumulusnetworks.com>
6100L: netdev@vger.kernel.org
6101S: Maintained
6102F: net/l3mdev
6103F: include/net/l3mdev.h
6104
6098LAPB module 6105LAPB module
6099L: linux-x25@vger.kernel.org 6106L: linux-x25@vger.kernel.org
6100S: Orphan 6107S: Orphan
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 99c33e83822f..c7f14794fe14 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1587,6 +1587,9 @@ struct net_device {
1587#ifdef CONFIG_NET_SWITCHDEV 1587#ifdef CONFIG_NET_SWITCHDEV
1588 const struct switchdev_ops *switchdev_ops; 1588 const struct switchdev_ops *switchdev_ops;
1589#endif 1589#endif
1590#ifdef CONFIG_NET_L3_MASTER_DEV
1591 const struct l3mdev_ops *l3mdev_ops;
1592#endif
1590 1593
1591 const struct header_ops *header_ops; 1594 const struct header_ops *header_ops;
1592 1595
diff --git a/include/net/l3mdev.h b/include/net/l3mdev.h
new file mode 100644
index 000000000000..e382c777bab8
--- /dev/null
+++ b/include/net/l3mdev.h
@@ -0,0 +1,125 @@
1/*
2 * include/net/l3mdev.h - L3 master device API
3 * Copyright (c) 2015 Cumulus Networks
4 * Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11#ifndef _NET_L3MDEV_H_
12#define _NET_L3MDEV_H_
13
14/**
15 * struct l3mdev_ops - l3mdev operations
16 *
17 * @l3mdev_fib_table: Get FIB table id to use for lookups
18 *
19 * @l3mdev_get_rtable: Get cached IPv4 rtable (dst_entry) for device
20 */
21
22struct l3mdev_ops {
23 u32 (*l3mdev_fib_table)(const struct net_device *dev);
24 struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev,
25 const struct flowi4 *fl4);
26};
27
28#ifdef CONFIG_NET_L3_MASTER_DEV
29
30int l3mdev_master_ifindex_rcu(struct net_device *dev);
31static inline int l3mdev_master_ifindex(struct net_device *dev)
32{
33 int ifindex;
34
35 rcu_read_lock();
36 ifindex = l3mdev_master_ifindex_rcu(dev);
37 rcu_read_unlock();
38
39 return ifindex;
40}
41
42/* get index of an interface to use for FIB lookups. For devices
43 * enslaved to an L3 master device FIB lookups are based on the
44 * master index
45 */
46static inline int l3mdev_fib_oif_rcu(struct net_device *dev)
47{
48 return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex;
49}
50
51static inline int l3mdev_fib_oif(struct net_device *dev)
52{
53 int oif;
54
55 rcu_read_lock();
56 oif = l3mdev_fib_oif_rcu(dev);
57 rcu_read_unlock();
58
59 return oif;
60}
61
62u32 l3mdev_fib_table_rcu(const struct net_device *dev);
63u32 l3mdev_fib_table_by_index(struct net *net, int ifindex);
64static inline u32 l3mdev_fib_table(const struct net_device *dev)
65{
66 u32 tb_id;
67
68 rcu_read_lock();
69 tb_id = l3mdev_fib_table_rcu(dev);
70 rcu_read_unlock();
71
72 return tb_id;
73}
74
75static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev,
76 const struct flowi4 *fl4)
77{
78 if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rtable)
79 return dev->l3mdev_ops->l3mdev_get_rtable(dev, fl4);
80
81 return NULL;
82}
83
84#else
85
86static inline int l3mdev_master_ifindex_rcu(struct net_device *dev)
87{
88 return 0;
89}
90static inline int l3mdev_master_ifindex(struct net_device *dev)
91{
92 return 0;
93}
94
95static inline int l3mdev_fib_oif_rcu(struct net_device *dev)
96{
97 return dev ? dev->ifindex : 0;
98}
99static inline int l3mdev_fib_oif(struct net_device *dev)
100{
101 return dev ? dev->ifindex : 0;
102}
103
104static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev)
105{
106 return 0;
107}
108static inline u32 l3mdev_fib_table(const struct net_device *dev)
109{
110 return 0;
111}
112static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex)
113{
114 return 0;
115}
116
117static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev,
118 const struct flowi4 *fl4)
119{
120 return NULL;
121}
122
123#endif
124
125#endif /* _NET_L3MDEV_H_ */
diff --git a/net/Kconfig b/net/Kconfig
index 7021c1bf44d6..127da94ae25e 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -232,6 +232,7 @@ source "net/netlink/Kconfig"
232source "net/mpls/Kconfig" 232source "net/mpls/Kconfig"
233source "net/hsr/Kconfig" 233source "net/hsr/Kconfig"
234source "net/switchdev/Kconfig" 234source "net/switchdev/Kconfig"
235source "net/l3mdev/Kconfig"
235 236
236config RPS 237config RPS
237 bool 238 bool
diff --git a/net/Makefile b/net/Makefile
index 3995613e5510..a5d04098dfce 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -74,3 +74,6 @@ obj-$(CONFIG_HSR) += hsr/
74ifneq ($(CONFIG_NET_SWITCHDEV),) 74ifneq ($(CONFIG_NET_SWITCHDEV),)
75obj-y += switchdev/ 75obj-y += switchdev/
76endif 76endif
77ifneq ($(CONFIG_NET_L3_MASTER_DEV),)
78obj-y += l3mdev/
79endif
diff --git a/net/l3mdev/Kconfig b/net/l3mdev/Kconfig
new file mode 100644
index 000000000000..5d47325037bc
--- /dev/null
+++ b/net/l3mdev/Kconfig
@@ -0,0 +1,10 @@
1#
2# Configuration for L3 master device support
3#
4
5config NET_L3_MASTER_DEV
6 bool "L3 Master device support"
7 depends on INET || IPV6
8 ---help---
9 This module provides glue between core networking code and device
10 drivers to support L3 master devices like VRF.
diff --git a/net/l3mdev/Makefile b/net/l3mdev/Makefile
new file mode 100644
index 000000000000..84a53a6f609a
--- /dev/null
+++ b/net/l3mdev/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for the L3 device API
3#
4
5obj-$(CONFIG_NET_L3_MASTER_DEV) += l3mdev.o
diff --git a/net/l3mdev/l3mdev.c b/net/l3mdev/l3mdev.c
new file mode 100644
index 000000000000..ddf75ad41713
--- /dev/null
+++ b/net/l3mdev/l3mdev.c
@@ -0,0 +1,92 @@
1/*
2 * net/l3mdev/l3mdev.c - L3 master device implementation
3 * Copyright (c) 2015 Cumulus Networks
4 * Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/netdevice.h>
13#include <net/l3mdev.h>
14
15/**
16 * l3mdev_master_ifindex - get index of L3 master device
17 * @dev: targeted interface
18 */
19
20int l3mdev_master_ifindex_rcu(struct net_device *dev)
21{
22 int ifindex = 0;
23
24 if (!dev)
25 return 0;
26
27 if (netif_is_l3_master(dev)) {
28 ifindex = dev->ifindex;
29 } else if (dev->flags & IFF_SLAVE) {
30 struct net_device *master;
31
32 master = netdev_master_upper_dev_get_rcu(dev);
33 if (master && netif_is_l3_master(master))
34 ifindex = master->ifindex;
35 }
36
37 return ifindex;
38}
39EXPORT_SYMBOL_GPL(l3mdev_master_ifindex_rcu);
40
41/**
42 * l3mdev_fib_table - get FIB table id associated with an L3
43 * master interface
44 * @dev: targeted interface
45 */
46
47u32 l3mdev_fib_table_rcu(const struct net_device *dev)
48{
49 u32 tb_id = 0;
50
51 if (!dev)
52 return 0;
53
54 if (netif_is_l3_master(dev)) {
55 if (dev->l3mdev_ops->l3mdev_fib_table)
56 tb_id = dev->l3mdev_ops->l3mdev_fib_table(dev);
57 } else if (dev->flags & IFF_SLAVE) {
58 /* Users of netdev_master_upper_dev_get_rcu need non-const,
59 * but current inet_*type functions take a const
60 */
61 struct net_device *_dev = (struct net_device *) dev;
62 const struct net_device *master;
63
64 master = netdev_master_upper_dev_get_rcu(_dev);
65 if (master && netif_is_l3_master(master) &&
66 master->l3mdev_ops->l3mdev_fib_table)
67 tb_id = master->l3mdev_ops->l3mdev_fib_table(master);
68 }
69
70 return tb_id;
71}
72EXPORT_SYMBOL_GPL(l3mdev_fib_table_rcu);
73
74u32 l3mdev_fib_table_by_index(struct net *net, int ifindex)
75{
76 struct net_device *dev;
77 u32 tb_id = 0;
78
79 if (!ifindex)
80 return 0;
81
82 rcu_read_lock();
83
84 dev = dev_get_by_index_rcu(net, ifindex);
85 if (dev)
86 tb_id = l3mdev_fib_table_rcu(dev);
87
88 rcu_read_unlock();
89
90 return tb_id;
91}
92EXPORT_SYMBOL_GPL(l3mdev_fib_table_by_index);