diff options
author | David Ahern <dsa@cumulusnetworks.com> | 2015-09-29 23:07:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-09-29 23:40:32 -0400 |
commit | 1b69c6d0ae90b7f1a4f61d5c8209d5cb7a55f849 (patch) | |
tree | 5c32b6f77817a51e86d333e59ae48bdae7b593ad | |
parent | 007979eaf94d1c888d8c7cf8a5250c2c6c9bd98e (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-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | include/linux/netdevice.h | 3 | ||||
-rw-r--r-- | include/net/l3mdev.h | 125 | ||||
-rw-r--r-- | net/Kconfig | 1 | ||||
-rw-r--r-- | net/Makefile | 3 | ||||
-rw-r--r-- | net/l3mdev/Kconfig | 10 | ||||
-rw-r--r-- | net/l3mdev/Makefile | 5 | ||||
-rw-r--r-- | net/l3mdev/l3mdev.c | 92 |
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 | |||
6095 | F: drivers/auxdisplay/ks0108.c | 6095 | F: drivers/auxdisplay/ks0108.c |
6096 | F: include/linux/ks0108.h | 6096 | F: include/linux/ks0108.h |
6097 | 6097 | ||
6098 | L3MDEV | ||
6099 | M: David Ahern <dsa@cumulusnetworks.com> | ||
6100 | L: netdev@vger.kernel.org | ||
6101 | S: Maintained | ||
6102 | F: net/l3mdev | ||
6103 | F: include/net/l3mdev.h | ||
6104 | |||
6098 | LAPB module | 6105 | LAPB module |
6099 | L: linux-x25@vger.kernel.org | 6106 | L: linux-x25@vger.kernel.org |
6100 | S: Orphan | 6107 | S: 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 | |||
22 | struct 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 | |||
30 | int l3mdev_master_ifindex_rcu(struct net_device *dev); | ||
31 | static 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 | */ | ||
46 | static inline int l3mdev_fib_oif_rcu(struct net_device *dev) | ||
47 | { | ||
48 | return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex; | ||
49 | } | ||
50 | |||
51 | static 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 | |||
62 | u32 l3mdev_fib_table_rcu(const struct net_device *dev); | ||
63 | u32 l3mdev_fib_table_by_index(struct net *net, int ifindex); | ||
64 | static 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 | |||
75 | static 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 | |||
86 | static inline int l3mdev_master_ifindex_rcu(struct net_device *dev) | ||
87 | { | ||
88 | return 0; | ||
89 | } | ||
90 | static inline int l3mdev_master_ifindex(struct net_device *dev) | ||
91 | { | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static inline int l3mdev_fib_oif_rcu(struct net_device *dev) | ||
96 | { | ||
97 | return dev ? dev->ifindex : 0; | ||
98 | } | ||
99 | static inline int l3mdev_fib_oif(struct net_device *dev) | ||
100 | { | ||
101 | return dev ? dev->ifindex : 0; | ||
102 | } | ||
103 | |||
104 | static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev) | ||
105 | { | ||
106 | return 0; | ||
107 | } | ||
108 | static inline u32 l3mdev_fib_table(const struct net_device *dev) | ||
109 | { | ||
110 | return 0; | ||
111 | } | ||
112 | static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) | ||
113 | { | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static 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" | |||
232 | source "net/mpls/Kconfig" | 232 | source "net/mpls/Kconfig" |
233 | source "net/hsr/Kconfig" | 233 | source "net/hsr/Kconfig" |
234 | source "net/switchdev/Kconfig" | 234 | source "net/switchdev/Kconfig" |
235 | source "net/l3mdev/Kconfig" | ||
235 | 236 | ||
236 | config RPS | 237 | config 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/ | |||
74 | ifneq ($(CONFIG_NET_SWITCHDEV),) | 74 | ifneq ($(CONFIG_NET_SWITCHDEV),) |
75 | obj-y += switchdev/ | 75 | obj-y += switchdev/ |
76 | endif | 76 | endif |
77 | ifneq ($(CONFIG_NET_L3_MASTER_DEV),) | ||
78 | obj-y += l3mdev/ | ||
79 | endif | ||
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 | |||
5 | config 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 | |||
5 | obj-$(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 | |||
20 | int 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 | } | ||
39 | EXPORT_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 | |||
47 | u32 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 | } | ||
72 | EXPORT_SYMBOL_GPL(l3mdev_fib_table_rcu); | ||
73 | |||
74 | u32 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 | } | ||
92 | EXPORT_SYMBOL_GPL(l3mdev_fib_table_by_index); | ||