xref: /openbmc/linux/include/net/l3mdev.h (revision cd2a9e62)
11b69c6d0SDavid Ahern /*
21b69c6d0SDavid Ahern  * include/net/l3mdev.h - L3 master device API
31b69c6d0SDavid Ahern  * Copyright (c) 2015 Cumulus Networks
41b69c6d0SDavid Ahern  * Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com>
51b69c6d0SDavid Ahern  *
61b69c6d0SDavid Ahern  * This program is free software; you can redistribute it and/or modify
71b69c6d0SDavid Ahern  * it under the terms of the GNU General Public License as published by
81b69c6d0SDavid Ahern  * the Free Software Foundation; either version 2 of the License, or
91b69c6d0SDavid Ahern  * (at your option) any later version.
101b69c6d0SDavid Ahern  */
111b69c6d0SDavid Ahern #ifndef _NET_L3MDEV_H_
121b69c6d0SDavid Ahern #define _NET_L3MDEV_H_
131b69c6d0SDavid Ahern 
1496c63fa7SDavid Ahern #include <net/fib_rules.h>
1596c63fa7SDavid Ahern 
161b69c6d0SDavid Ahern /**
171b69c6d0SDavid Ahern  * struct l3mdev_ops - l3mdev operations
181b69c6d0SDavid Ahern  *
191b69c6d0SDavid Ahern  * @l3mdev_fib_table: Get FIB table id to use for lookups
201b69c6d0SDavid Ahern  *
211b69c6d0SDavid Ahern  * @l3mdev_get_rtable: Get cached IPv4 rtable (dst_entry) for device
228cbb512cSDavid Ahern  *
238cbb512cSDavid Ahern  * @l3mdev_get_saddr: Get source address for a flow
24ccf3c8c3SDavid Ahern  *
25ccf3c8c3SDavid Ahern  * @l3mdev_get_rt6_dst: Get cached IPv6 rt6_info (dst_entry) for device
261b69c6d0SDavid Ahern  */
271b69c6d0SDavid Ahern 
281b69c6d0SDavid Ahern struct l3mdev_ops {
291b69c6d0SDavid Ahern 	u32		(*l3mdev_fib_table)(const struct net_device *dev);
3074b20582SDavid Ahern 	struct sk_buff * (*l3mdev_l3_rcv)(struct net_device *dev,
3174b20582SDavid Ahern 					  struct sk_buff *skb, u16 proto);
32ccf3c8c3SDavid Ahern 
33ccf3c8c3SDavid Ahern 	/* IPv4 ops */
341b69c6d0SDavid Ahern 	struct rtable *	(*l3mdev_get_rtable)(const struct net_device *dev,
351b69c6d0SDavid Ahern 					     const struct flowi4 *fl4);
36b5bdacf3SDavid Ahern 	int		(*l3mdev_get_saddr)(struct net_device *dev,
378cbb512cSDavid Ahern 					    struct flowi4 *fl4);
38ccf3c8c3SDavid Ahern 
39ccf3c8c3SDavid Ahern 	/* IPv6 ops */
40ccf3c8c3SDavid Ahern 	struct dst_entry * (*l3mdev_get_rt6_dst)(const struct net_device *dev,
41cd2a9e62SDavid Ahern 						 struct flowi6 *fl6);
421b69c6d0SDavid Ahern };
431b69c6d0SDavid Ahern 
441b69c6d0SDavid Ahern #ifdef CONFIG_NET_L3_MASTER_DEV
451b69c6d0SDavid Ahern 
4696c63fa7SDavid Ahern int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
4796c63fa7SDavid Ahern 			  struct fib_lookup_arg *arg);
4896c63fa7SDavid Ahern 
493f2fb9a8SDavid Ahern int l3mdev_master_ifindex_rcu(const struct net_device *dev);
501b69c6d0SDavid Ahern static inline int l3mdev_master_ifindex(struct net_device *dev)
511b69c6d0SDavid Ahern {
521b69c6d0SDavid Ahern 	int ifindex;
531b69c6d0SDavid Ahern 
541b69c6d0SDavid Ahern 	rcu_read_lock();
551b69c6d0SDavid Ahern 	ifindex = l3mdev_master_ifindex_rcu(dev);
561b69c6d0SDavid Ahern 	rcu_read_unlock();
571b69c6d0SDavid Ahern 
581b69c6d0SDavid Ahern 	return ifindex;
591b69c6d0SDavid Ahern }
601b69c6d0SDavid Ahern 
611a852479SDavid Ahern static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
621a852479SDavid Ahern {
631a852479SDavid Ahern 	struct net_device *dev;
641a852479SDavid Ahern 	int rc = 0;
651a852479SDavid Ahern 
661a852479SDavid Ahern 	if (likely(ifindex)) {
671a852479SDavid Ahern 		rcu_read_lock();
681a852479SDavid Ahern 
691a852479SDavid Ahern 		dev = dev_get_by_index_rcu(net, ifindex);
701a852479SDavid Ahern 		if (dev)
711a852479SDavid Ahern 			rc = l3mdev_master_ifindex_rcu(dev);
721a852479SDavid Ahern 
731a852479SDavid Ahern 		rcu_read_unlock();
741a852479SDavid Ahern 	}
751a852479SDavid Ahern 
761a852479SDavid Ahern 	return rc;
771a852479SDavid Ahern }
781a852479SDavid Ahern 
791b69c6d0SDavid Ahern /* get index of an interface to use for FIB lookups. For devices
801b69c6d0SDavid Ahern  * enslaved to an L3 master device FIB lookups are based on the
811b69c6d0SDavid Ahern  * master index
821b69c6d0SDavid Ahern  */
831b69c6d0SDavid Ahern static inline int l3mdev_fib_oif_rcu(struct net_device *dev)
841b69c6d0SDavid Ahern {
851b69c6d0SDavid Ahern 	return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex;
861b69c6d0SDavid Ahern }
871b69c6d0SDavid Ahern 
881b69c6d0SDavid Ahern static inline int l3mdev_fib_oif(struct net_device *dev)
891b69c6d0SDavid Ahern {
901b69c6d0SDavid Ahern 	int oif;
911b69c6d0SDavid Ahern 
921b69c6d0SDavid Ahern 	rcu_read_lock();
931b69c6d0SDavid Ahern 	oif = l3mdev_fib_oif_rcu(dev);
941b69c6d0SDavid Ahern 	rcu_read_unlock();
951b69c6d0SDavid Ahern 
961b69c6d0SDavid Ahern 	return oif;
971b69c6d0SDavid Ahern }
981b69c6d0SDavid Ahern 
991b69c6d0SDavid Ahern u32 l3mdev_fib_table_rcu(const struct net_device *dev);
1001b69c6d0SDavid Ahern u32 l3mdev_fib_table_by_index(struct net *net, int ifindex);
1011b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table(const struct net_device *dev)
1021b69c6d0SDavid Ahern {
1031b69c6d0SDavid Ahern 	u32 tb_id;
1041b69c6d0SDavid Ahern 
1051b69c6d0SDavid Ahern 	rcu_read_lock();
1061b69c6d0SDavid Ahern 	tb_id = l3mdev_fib_table_rcu(dev);
1071b69c6d0SDavid Ahern 	rcu_read_unlock();
1081b69c6d0SDavid Ahern 
1091b69c6d0SDavid Ahern 	return tb_id;
1101b69c6d0SDavid Ahern }
1111b69c6d0SDavid Ahern 
1121b69c6d0SDavid Ahern static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev,
1131b69c6d0SDavid Ahern 					       const struct flowi4 *fl4)
1141b69c6d0SDavid Ahern {
1151b69c6d0SDavid Ahern 	if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rtable)
1161b69c6d0SDavid Ahern 		return dev->l3mdev_ops->l3mdev_get_rtable(dev, fl4);
1171b69c6d0SDavid Ahern 
1181b69c6d0SDavid Ahern 	return NULL;
1191b69c6d0SDavid Ahern }
1201b69c6d0SDavid Ahern 
1219478d12dSDavid Ahern static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
1229478d12dSDavid Ahern {
1239478d12dSDavid Ahern 	struct net_device *dev;
1249478d12dSDavid Ahern 	bool rc = false;
1259478d12dSDavid Ahern 
1269478d12dSDavid Ahern 	if (ifindex == 0)
1279478d12dSDavid Ahern 		return false;
1289478d12dSDavid Ahern 
1299478d12dSDavid Ahern 	rcu_read_lock();
1309478d12dSDavid Ahern 
1319478d12dSDavid Ahern 	dev = dev_get_by_index_rcu(net, ifindex);
1329478d12dSDavid Ahern 	if (dev)
1339478d12dSDavid Ahern 		rc = netif_is_l3_master(dev);
1349478d12dSDavid Ahern 
1359478d12dSDavid Ahern 	rcu_read_unlock();
1369478d12dSDavid Ahern 
1379478d12dSDavid Ahern 	return rc;
1389478d12dSDavid Ahern }
1399478d12dSDavid Ahern 
1404a65896fSDavid Ahern int l3mdev_get_saddr(struct net *net, int ifindex, struct flowi4 *fl4);
1418cbb512cSDavid Ahern 
142cd2a9e62SDavid Ahern struct dst_entry *l3mdev_get_rt6_dst(struct net *net, struct flowi6 *fl6);
143ccf3c8c3SDavid Ahern 
14474b20582SDavid Ahern static inline
14574b20582SDavid Ahern struct sk_buff *l3mdev_l3_rcv(struct sk_buff *skb, u16 proto)
14674b20582SDavid Ahern {
14774b20582SDavid Ahern 	struct net_device *master = NULL;
14874b20582SDavid Ahern 
14974b20582SDavid Ahern 	if (netif_is_l3_slave(skb->dev))
15074b20582SDavid Ahern 		master = netdev_master_upper_dev_get_rcu(skb->dev);
15174b20582SDavid Ahern 	else if (netif_is_l3_master(skb->dev))
15274b20582SDavid Ahern 		master = skb->dev;
15374b20582SDavid Ahern 
15474b20582SDavid Ahern 	if (master && master->l3mdev_ops->l3mdev_l3_rcv)
15574b20582SDavid Ahern 		skb = master->l3mdev_ops->l3mdev_l3_rcv(master, skb, proto);
15674b20582SDavid Ahern 
15774b20582SDavid Ahern 	return skb;
15874b20582SDavid Ahern }
15974b20582SDavid Ahern 
16074b20582SDavid Ahern static inline
16174b20582SDavid Ahern struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb)
16274b20582SDavid Ahern {
16374b20582SDavid Ahern 	return l3mdev_l3_rcv(skb, AF_INET);
16474b20582SDavid Ahern }
16574b20582SDavid Ahern 
16674b20582SDavid Ahern static inline
16774b20582SDavid Ahern struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb)
16874b20582SDavid Ahern {
16974b20582SDavid Ahern 	return l3mdev_l3_rcv(skb, AF_INET6);
17074b20582SDavid Ahern }
17174b20582SDavid Ahern 
1721b69c6d0SDavid Ahern #else
1731b69c6d0SDavid Ahern 
1743f2fb9a8SDavid Ahern static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev)
1751b69c6d0SDavid Ahern {
1761b69c6d0SDavid Ahern 	return 0;
1771b69c6d0SDavid Ahern }
1781b69c6d0SDavid Ahern static inline int l3mdev_master_ifindex(struct net_device *dev)
1791b69c6d0SDavid Ahern {
1801b69c6d0SDavid Ahern 	return 0;
1811b69c6d0SDavid Ahern }
1821b69c6d0SDavid Ahern 
1831a852479SDavid Ahern static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
1841a852479SDavid Ahern {
1851a852479SDavid Ahern 	return 0;
1861a852479SDavid Ahern }
1871a852479SDavid Ahern 
1881b69c6d0SDavid Ahern static inline int l3mdev_fib_oif_rcu(struct net_device *dev)
1891b69c6d0SDavid Ahern {
1901b69c6d0SDavid Ahern 	return dev ? dev->ifindex : 0;
1911b69c6d0SDavid Ahern }
1921b69c6d0SDavid Ahern static inline int l3mdev_fib_oif(struct net_device *dev)
1931b69c6d0SDavid Ahern {
1941b69c6d0SDavid Ahern 	return dev ? dev->ifindex : 0;
1951b69c6d0SDavid Ahern }
1961b69c6d0SDavid Ahern 
1971b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev)
1981b69c6d0SDavid Ahern {
1991b69c6d0SDavid Ahern 	return 0;
2001b69c6d0SDavid Ahern }
2011b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table(const struct net_device *dev)
2021b69c6d0SDavid Ahern {
2031b69c6d0SDavid Ahern 	return 0;
2041b69c6d0SDavid Ahern }
2051b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex)
2061b69c6d0SDavid Ahern {
2071b69c6d0SDavid Ahern 	return 0;
2081b69c6d0SDavid Ahern }
2091b69c6d0SDavid Ahern 
2101b69c6d0SDavid Ahern static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev,
2111b69c6d0SDavid Ahern 					       const struct flowi4 *fl4)
2121b69c6d0SDavid Ahern {
2131b69c6d0SDavid Ahern 	return NULL;
2141b69c6d0SDavid Ahern }
2151b69c6d0SDavid Ahern 
2169478d12dSDavid Ahern static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
2179478d12dSDavid Ahern {
2189478d12dSDavid Ahern 	return false;
2199478d12dSDavid Ahern }
2209478d12dSDavid Ahern 
221b5bdacf3SDavid Ahern static inline int l3mdev_get_saddr(struct net *net, int ifindex,
2228cbb512cSDavid Ahern 				   struct flowi4 *fl4)
2238cbb512cSDavid Ahern {
224b5bdacf3SDavid Ahern 	return 0;
2258cbb512cSDavid Ahern }
226ccf3c8c3SDavid Ahern 
227ccf3c8c3SDavid Ahern static inline
228cd2a9e62SDavid Ahern struct dst_entry *l3mdev_get_rt6_dst(struct net *net, struct flowi6 *fl6)
229ccf3c8c3SDavid Ahern {
230ccf3c8c3SDavid Ahern 	return NULL;
231ccf3c8c3SDavid Ahern }
23274b20582SDavid Ahern 
23374b20582SDavid Ahern static inline
23474b20582SDavid Ahern struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb)
23574b20582SDavid Ahern {
23674b20582SDavid Ahern 	return skb;
23774b20582SDavid Ahern }
23874b20582SDavid Ahern 
23974b20582SDavid Ahern static inline
24074b20582SDavid Ahern struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb)
24174b20582SDavid Ahern {
24274b20582SDavid Ahern 	return skb;
24374b20582SDavid Ahern }
24496c63fa7SDavid Ahern 
24596c63fa7SDavid Ahern static inline
24696c63fa7SDavid Ahern int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
24796c63fa7SDavid Ahern 			  struct fib_lookup_arg *arg)
24896c63fa7SDavid Ahern {
24996c63fa7SDavid Ahern 	return 1;
25096c63fa7SDavid Ahern }
2511b69c6d0SDavid Ahern #endif
2521b69c6d0SDavid Ahern 
2531b69c6d0SDavid Ahern #endif /* _NET_L3MDEV_H_ */
254