xref: /openbmc/linux/include/net/l3mdev.h (revision 49042c22)
12874c5fdSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */
21b69c6d0SDavid Ahern /*
31b69c6d0SDavid Ahern  * include/net/l3mdev.h - L3 master device API
41b69c6d0SDavid Ahern  * Copyright (c) 2015 Cumulus Networks
51b69c6d0SDavid Ahern  * Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com>
61b69c6d0SDavid Ahern  */
71b69c6d0SDavid Ahern #ifndef _NET_L3MDEV_H_
81b69c6d0SDavid Ahern #define _NET_L3MDEV_H_
91b69c6d0SDavid Ahern 
10a8e3e1a9SDavid Ahern #include <net/dst.h>
1196c63fa7SDavid Ahern #include <net/fib_rules.h>
1296c63fa7SDavid Ahern 
1349042c22SAndrea Mayer enum l3mdev_type {
1449042c22SAndrea Mayer 	L3MDEV_TYPE_UNSPEC,
1549042c22SAndrea Mayer 	L3MDEV_TYPE_VRF,
1649042c22SAndrea Mayer 	__L3MDEV_TYPE_MAX
1749042c22SAndrea Mayer };
1849042c22SAndrea Mayer 
1949042c22SAndrea Mayer #define L3MDEV_TYPE_MAX (__L3MDEV_TYPE_MAX - 1)
2049042c22SAndrea Mayer 
2149042c22SAndrea Mayer typedef int (*lookup_by_table_id_t)(struct net *net, u32 table_d);
2249042c22SAndrea Mayer 
231b69c6d0SDavid Ahern /**
241b69c6d0SDavid Ahern  * struct l3mdev_ops - l3mdev operations
251b69c6d0SDavid Ahern  *
261b69c6d0SDavid Ahern  * @l3mdev_fib_table: Get FIB table id to use for lookups
271b69c6d0SDavid Ahern  *
28a8e3e1a9SDavid Ahern  * @l3mdev_l3_rcv:    Hook in L3 receive path
29a8e3e1a9SDavid Ahern  *
30a8e3e1a9SDavid Ahern  * @l3mdev_l3_out:    Hook in L3 output path
31a8e3e1a9SDavid Ahern  *
324c1feac5SDavid Ahern  * @l3mdev_link_scope_lookup: IPv6 lookup for linklocal and mcast destinations
331b69c6d0SDavid Ahern  */
341b69c6d0SDavid Ahern 
351b69c6d0SDavid Ahern struct l3mdev_ops {
361b69c6d0SDavid Ahern 	u32		(*l3mdev_fib_table)(const struct net_device *dev);
3774b20582SDavid Ahern 	struct sk_buff * (*l3mdev_l3_rcv)(struct net_device *dev,
3874b20582SDavid Ahern 					  struct sk_buff *skb, u16 proto);
39a8e3e1a9SDavid Ahern 	struct sk_buff * (*l3mdev_l3_out)(struct net_device *dev,
40a8e3e1a9SDavid Ahern 					  struct sock *sk, struct sk_buff *skb,
41a8e3e1a9SDavid Ahern 					  u16 proto);
42ccf3c8c3SDavid Ahern 
43ccf3c8c3SDavid Ahern 	/* IPv6 ops */
444c1feac5SDavid Ahern 	struct dst_entry * (*l3mdev_link_scope_lookup)(const struct net_device *dev,
45cd2a9e62SDavid Ahern 						 struct flowi6 *fl6);
461b69c6d0SDavid Ahern };
471b69c6d0SDavid Ahern 
481b69c6d0SDavid Ahern #ifdef CONFIG_NET_L3_MASTER_DEV
491b69c6d0SDavid Ahern 
5049042c22SAndrea Mayer int l3mdev_table_lookup_register(enum l3mdev_type l3type,
5149042c22SAndrea Mayer 				 lookup_by_table_id_t fn);
5249042c22SAndrea Mayer 
5349042c22SAndrea Mayer void l3mdev_table_lookup_unregister(enum l3mdev_type l3type,
5449042c22SAndrea Mayer 				    lookup_by_table_id_t fn);
5549042c22SAndrea Mayer 
5649042c22SAndrea Mayer int l3mdev_ifindex_lookup_by_table_id(enum l3mdev_type l3type, struct net *net,
5749042c22SAndrea Mayer 				      u32 table_id);
5849042c22SAndrea Mayer 
5996c63fa7SDavid Ahern int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
6096c63fa7SDavid Ahern 			  struct fib_lookup_arg *arg);
6196c63fa7SDavid Ahern 
629ee0034bSDavid Ahern void l3mdev_update_flow(struct net *net, struct flowi *fl);
639ee0034bSDavid Ahern 
643f2fb9a8SDavid Ahern int l3mdev_master_ifindex_rcu(const struct net_device *dev);
l3mdev_master_ifindex(struct net_device * dev)651b69c6d0SDavid Ahern static inline int l3mdev_master_ifindex(struct net_device *dev)
661b69c6d0SDavid Ahern {
671b69c6d0SDavid Ahern 	int ifindex;
681b69c6d0SDavid Ahern 
691b69c6d0SDavid Ahern 	rcu_read_lock();
701b69c6d0SDavid Ahern 	ifindex = l3mdev_master_ifindex_rcu(dev);
711b69c6d0SDavid Ahern 	rcu_read_unlock();
721b69c6d0SDavid Ahern 
731b69c6d0SDavid Ahern 	return ifindex;
741b69c6d0SDavid Ahern }
751b69c6d0SDavid Ahern 
l3mdev_master_ifindex_by_index(struct net * net,int ifindex)761a852479SDavid Ahern static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
771a852479SDavid Ahern {
781a852479SDavid Ahern 	struct net_device *dev;
791a852479SDavid Ahern 	int rc = 0;
801a852479SDavid Ahern 
811a852479SDavid Ahern 	if (likely(ifindex)) {
821a852479SDavid Ahern 		rcu_read_lock();
831a852479SDavid Ahern 
841a852479SDavid Ahern 		dev = dev_get_by_index_rcu(net, ifindex);
851a852479SDavid Ahern 		if (dev)
861a852479SDavid Ahern 			rc = l3mdev_master_ifindex_rcu(dev);
871a852479SDavid Ahern 
881a852479SDavid Ahern 		rcu_read_unlock();
891a852479SDavid Ahern 	}
901a852479SDavid Ahern 
911a852479SDavid Ahern 	return rc;
921a852479SDavid Ahern }
931a852479SDavid Ahern 
94afbac601SDavid Ahern static inline
l3mdev_master_dev_rcu(const struct net_device * _dev)955f02ce24SDavid Ahern struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev)
96afbac601SDavid Ahern {
97afbac601SDavid Ahern 	/* netdev_master_upper_dev_get_rcu calls
98afbac601SDavid Ahern 	 * list_first_or_null_rcu to walk the upper dev list.
99afbac601SDavid Ahern 	 * list_first_or_null_rcu does not handle a const arg. We aren't
100afbac601SDavid Ahern 	 * making changes, just want the master device from that list so
101afbac601SDavid Ahern 	 * typecast to remove the const
102afbac601SDavid Ahern 	 */
103afbac601SDavid Ahern 	struct net_device *dev = (struct net_device *)_dev;
1045f02ce24SDavid Ahern 	struct net_device *master;
105afbac601SDavid Ahern 
106afbac601SDavid Ahern 	if (!dev)
107afbac601SDavid Ahern 		return NULL;
108afbac601SDavid Ahern 
109afbac601SDavid Ahern 	if (netif_is_l3_master(dev))
110afbac601SDavid Ahern 		master = dev;
111afbac601SDavid Ahern 	else if (netif_is_l3_slave(dev))
112afbac601SDavid Ahern 		master = netdev_master_upper_dev_get_rcu(dev);
113afbac601SDavid Ahern 	else
114afbac601SDavid Ahern 		master = NULL;
115afbac601SDavid Ahern 
116afbac601SDavid Ahern 	return master;
117afbac601SDavid Ahern }
118afbac601SDavid Ahern 
1196a6d6681SAlexis Bauvin int l3mdev_master_upper_ifindex_by_index_rcu(struct net *net, int ifindex);
1206a6d6681SAlexis Bauvin static inline
l3mdev_master_upper_ifindex_by_index(struct net * net,int ifindex)1216a6d6681SAlexis Bauvin int l3mdev_master_upper_ifindex_by_index(struct net *net, int ifindex)
1226a6d6681SAlexis Bauvin {
1236a6d6681SAlexis Bauvin 	rcu_read_lock();
1246a6d6681SAlexis Bauvin 	ifindex = l3mdev_master_upper_ifindex_by_index_rcu(net, ifindex);
1256a6d6681SAlexis Bauvin 	rcu_read_unlock();
1266a6d6681SAlexis Bauvin 
1276a6d6681SAlexis Bauvin 	return ifindex;
1286a6d6681SAlexis Bauvin }
1296a6d6681SAlexis Bauvin 
1301b69c6d0SDavid Ahern u32 l3mdev_fib_table_rcu(const struct net_device *dev);
1311b69c6d0SDavid Ahern u32 l3mdev_fib_table_by_index(struct net *net, int ifindex);
l3mdev_fib_table(const struct net_device * dev)1321b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table(const struct net_device *dev)
1331b69c6d0SDavid Ahern {
1341b69c6d0SDavid Ahern 	u32 tb_id;
1351b69c6d0SDavid Ahern 
1361b69c6d0SDavid Ahern 	rcu_read_lock();
1371b69c6d0SDavid Ahern 	tb_id = l3mdev_fib_table_rcu(dev);
1381b69c6d0SDavid Ahern 	rcu_read_unlock();
1391b69c6d0SDavid Ahern 
1401b69c6d0SDavid Ahern 	return tb_id;
1411b69c6d0SDavid Ahern }
1421b69c6d0SDavid Ahern 
netif_index_is_l3_master(struct net * net,int ifindex)1436104e112SDavid Ahern static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
1446104e112SDavid Ahern {
1456104e112SDavid Ahern 	struct net_device *dev;
1466104e112SDavid Ahern 	bool rc = false;
1476104e112SDavid Ahern 
1486104e112SDavid Ahern 	if (ifindex == 0)
1496104e112SDavid Ahern 		return false;
1506104e112SDavid Ahern 
1516104e112SDavid Ahern 	rcu_read_lock();
1526104e112SDavid Ahern 
1536104e112SDavid Ahern 	dev = dev_get_by_index_rcu(net, ifindex);
1546104e112SDavid Ahern 	if (dev)
1556104e112SDavid Ahern 		rc = netif_is_l3_master(dev);
1566104e112SDavid Ahern 
1576104e112SDavid Ahern 	rcu_read_unlock();
1586104e112SDavid Ahern 
1596104e112SDavid Ahern 	return rc;
1606104e112SDavid Ahern }
1616104e112SDavid Ahern 
1624c1feac5SDavid Ahern struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6);
163ccf3c8c3SDavid Ahern 
16474b20582SDavid Ahern static inline
l3mdev_l3_rcv(struct sk_buff * skb,u16 proto)16574b20582SDavid Ahern struct sk_buff *l3mdev_l3_rcv(struct sk_buff *skb, u16 proto)
16674b20582SDavid Ahern {
16774b20582SDavid Ahern 	struct net_device *master = NULL;
16874b20582SDavid Ahern 
16974b20582SDavid Ahern 	if (netif_is_l3_slave(skb->dev))
17074b20582SDavid Ahern 		master = netdev_master_upper_dev_get_rcu(skb->dev);
171d5256083SDaniel Borkmann 	else if (netif_is_l3_master(skb->dev) ||
172d5256083SDaniel Borkmann 		 netif_has_l3_rx_handler(skb->dev))
17374b20582SDavid Ahern 		master = skb->dev;
17474b20582SDavid Ahern 
17574b20582SDavid Ahern 	if (master && master->l3mdev_ops->l3mdev_l3_rcv)
17674b20582SDavid Ahern 		skb = master->l3mdev_ops->l3mdev_l3_rcv(master, skb, proto);
17774b20582SDavid Ahern 
17874b20582SDavid Ahern 	return skb;
17974b20582SDavid Ahern }
18074b20582SDavid Ahern 
18174b20582SDavid Ahern static inline
l3mdev_ip_rcv(struct sk_buff * skb)18274b20582SDavid Ahern struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb)
18374b20582SDavid Ahern {
18474b20582SDavid Ahern 	return l3mdev_l3_rcv(skb, AF_INET);
18574b20582SDavid Ahern }
18674b20582SDavid Ahern 
18774b20582SDavid Ahern static inline
l3mdev_ip6_rcv(struct sk_buff * skb)18874b20582SDavid Ahern struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb)
18974b20582SDavid Ahern {
19074b20582SDavid Ahern 	return l3mdev_l3_rcv(skb, AF_INET6);
19174b20582SDavid Ahern }
19274b20582SDavid Ahern 
193a8e3e1a9SDavid Ahern static inline
l3mdev_l3_out(struct sock * sk,struct sk_buff * skb,u16 proto)194a8e3e1a9SDavid Ahern struct sk_buff *l3mdev_l3_out(struct sock *sk, struct sk_buff *skb, u16 proto)
195a8e3e1a9SDavid Ahern {
196a8e3e1a9SDavid Ahern 	struct net_device *dev = skb_dst(skb)->dev;
197a8e3e1a9SDavid Ahern 
198a8e3e1a9SDavid Ahern 	if (netif_is_l3_slave(dev)) {
199a8e3e1a9SDavid Ahern 		struct net_device *master;
200a8e3e1a9SDavid Ahern 
201a8e3e1a9SDavid Ahern 		master = netdev_master_upper_dev_get_rcu(dev);
202a8e3e1a9SDavid Ahern 		if (master && master->l3mdev_ops->l3mdev_l3_out)
203a8e3e1a9SDavid Ahern 			skb = master->l3mdev_ops->l3mdev_l3_out(master, sk,
204a8e3e1a9SDavid Ahern 								skb, proto);
205a8e3e1a9SDavid Ahern 	}
206a8e3e1a9SDavid Ahern 
207a8e3e1a9SDavid Ahern 	return skb;
208a8e3e1a9SDavid Ahern }
209a8e3e1a9SDavid Ahern 
210a8e3e1a9SDavid Ahern static inline
l3mdev_ip_out(struct sock * sk,struct sk_buff * skb)211a8e3e1a9SDavid Ahern struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb)
212a8e3e1a9SDavid Ahern {
213a8e3e1a9SDavid Ahern 	return l3mdev_l3_out(sk, skb, AF_INET);
214a8e3e1a9SDavid Ahern }
215a8e3e1a9SDavid Ahern 
216a8e3e1a9SDavid Ahern static inline
l3mdev_ip6_out(struct sock * sk,struct sk_buff * skb)217a8e3e1a9SDavid Ahern struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb)
218a8e3e1a9SDavid Ahern {
219a8e3e1a9SDavid Ahern 	return l3mdev_l3_out(sk, skb, AF_INET6);
220a8e3e1a9SDavid Ahern }
2211b69c6d0SDavid Ahern #else
2221b69c6d0SDavid Ahern 
l3mdev_master_ifindex_rcu(const struct net_device * dev)2233f2fb9a8SDavid Ahern static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev)
2241b69c6d0SDavid Ahern {
2251b69c6d0SDavid Ahern 	return 0;
2261b69c6d0SDavid Ahern }
l3mdev_master_ifindex(struct net_device * dev)2271b69c6d0SDavid Ahern static inline int l3mdev_master_ifindex(struct net_device *dev)
2281b69c6d0SDavid Ahern {
2291b69c6d0SDavid Ahern 	return 0;
2301b69c6d0SDavid Ahern }
2311b69c6d0SDavid Ahern 
l3mdev_master_ifindex_by_index(struct net * net,int ifindex)2321a852479SDavid Ahern static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
2331a852479SDavid Ahern {
2341a852479SDavid Ahern 	return 0;
2351a852479SDavid Ahern }
2361a852479SDavid Ahern 
237afbac601SDavid Ahern static inline
l3mdev_master_upper_ifindex_by_index_rcu(struct net * net,int ifindex)2386a6d6681SAlexis Bauvin int l3mdev_master_upper_ifindex_by_index_rcu(struct net *net, int ifindex)
2396a6d6681SAlexis Bauvin {
2406a6d6681SAlexis Bauvin 	return 0;
2416a6d6681SAlexis Bauvin }
2426a6d6681SAlexis Bauvin static inline
l3mdev_master_upper_ifindex_by_index(struct net * net,int ifindex)2436a6d6681SAlexis Bauvin int l3mdev_master_upper_ifindex_by_index(struct net *net, int ifindex)
2446a6d6681SAlexis Bauvin {
2456a6d6681SAlexis Bauvin 	return 0;
2466a6d6681SAlexis Bauvin }
2476a6d6681SAlexis Bauvin 
2486a6d6681SAlexis Bauvin static inline
l3mdev_master_dev_rcu(const struct net_device * dev)2495f02ce24SDavid Ahern struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev)
250afbac601SDavid Ahern {
251afbac601SDavid Ahern 	return NULL;
252afbac601SDavid Ahern }
253afbac601SDavid Ahern 
l3mdev_fib_table_rcu(const struct net_device * dev)2541b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev)
2551b69c6d0SDavid Ahern {
2561b69c6d0SDavid Ahern 	return 0;
2571b69c6d0SDavid Ahern }
l3mdev_fib_table(const struct net_device * dev)2581b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table(const struct net_device *dev)
2591b69c6d0SDavid Ahern {
2601b69c6d0SDavid Ahern 	return 0;
2611b69c6d0SDavid Ahern }
l3mdev_fib_table_by_index(struct net * net,int ifindex)2621b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex)
2631b69c6d0SDavid Ahern {
2641b69c6d0SDavid Ahern 	return 0;
2651b69c6d0SDavid Ahern }
2661b69c6d0SDavid Ahern 
netif_index_is_l3_master(struct net * net,int ifindex)2676104e112SDavid Ahern static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
2686104e112SDavid Ahern {
2696104e112SDavid Ahern 	return false;
2706104e112SDavid Ahern }
2716104e112SDavid Ahern 
272ccf3c8c3SDavid Ahern static inline
l3mdev_link_scope_lookup(struct net * net,struct flowi6 * fl6)2734c1feac5SDavid Ahern struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6)
274ccf3c8c3SDavid Ahern {
275ccf3c8c3SDavid Ahern 	return NULL;
276ccf3c8c3SDavid Ahern }
27774b20582SDavid Ahern 
27874b20582SDavid Ahern static inline
l3mdev_ip_rcv(struct sk_buff * skb)27974b20582SDavid Ahern struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb)
28074b20582SDavid Ahern {
28174b20582SDavid Ahern 	return skb;
28274b20582SDavid Ahern }
28374b20582SDavid Ahern 
28474b20582SDavid Ahern static inline
l3mdev_ip6_rcv(struct sk_buff * skb)28574b20582SDavid Ahern struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb)
28674b20582SDavid Ahern {
28774b20582SDavid Ahern 	return skb;
28874b20582SDavid Ahern }
28996c63fa7SDavid Ahern 
29096c63fa7SDavid Ahern static inline
l3mdev_ip_out(struct sock * sk,struct sk_buff * skb)291a8e3e1a9SDavid Ahern struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb)
292a8e3e1a9SDavid Ahern {
293a8e3e1a9SDavid Ahern 	return skb;
294a8e3e1a9SDavid Ahern }
295a8e3e1a9SDavid Ahern 
296a8e3e1a9SDavid Ahern static inline
l3mdev_ip6_out(struct sock * sk,struct sk_buff * skb)297a8e3e1a9SDavid Ahern struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb)
298a8e3e1a9SDavid Ahern {
299a8e3e1a9SDavid Ahern 	return skb;
300a8e3e1a9SDavid Ahern }
301a8e3e1a9SDavid Ahern 
302a8e3e1a9SDavid Ahern static inline
l3mdev_table_lookup_register(enum l3mdev_type l3type,lookup_by_table_id_t fn)30349042c22SAndrea Mayer int l3mdev_table_lookup_register(enum l3mdev_type l3type,
30449042c22SAndrea Mayer 				 lookup_by_table_id_t fn)
30549042c22SAndrea Mayer {
30649042c22SAndrea Mayer 	return -EOPNOTSUPP;
30749042c22SAndrea Mayer }
30849042c22SAndrea Mayer 
30949042c22SAndrea Mayer static inline
l3mdev_table_lookup_unregister(enum l3mdev_type l3type,lookup_by_table_id_t fn)31049042c22SAndrea Mayer void l3mdev_table_lookup_unregister(enum l3mdev_type l3type,
31149042c22SAndrea Mayer 				    lookup_by_table_id_t fn)
31249042c22SAndrea Mayer {
31349042c22SAndrea Mayer }
31449042c22SAndrea Mayer 
31549042c22SAndrea Mayer static inline
l3mdev_ifindex_lookup_by_table_id(enum l3mdev_type l3type,struct net * net,u32 table_id)31649042c22SAndrea Mayer int l3mdev_ifindex_lookup_by_table_id(enum l3mdev_type l3type, struct net *net,
31749042c22SAndrea Mayer 				      u32 table_id)
31849042c22SAndrea Mayer {
31949042c22SAndrea Mayer 	return -ENODEV;
32049042c22SAndrea Mayer }
32149042c22SAndrea Mayer 
32249042c22SAndrea Mayer static inline
l3mdev_fib_rule_match(struct net * net,struct flowi * fl,struct fib_lookup_arg * arg)32396c63fa7SDavid Ahern int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
32496c63fa7SDavid Ahern 			  struct fib_lookup_arg *arg)
32596c63fa7SDavid Ahern {
32696c63fa7SDavid Ahern 	return 1;
32796c63fa7SDavid Ahern }
3289ee0034bSDavid Ahern static inline
l3mdev_update_flow(struct net * net,struct flowi * fl)3299ee0034bSDavid Ahern void l3mdev_update_flow(struct net *net, struct flowi *fl)
3309ee0034bSDavid Ahern {
3319ee0034bSDavid Ahern }
3321b69c6d0SDavid Ahern #endif
3331b69c6d0SDavid Ahern 
3341b69c6d0SDavid Ahern #endif /* _NET_L3MDEV_H_ */
335