xref: /openbmc/linux/include/net/l3mdev.h (revision 8cbb512c)
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 
141b69c6d0SDavid Ahern /**
151b69c6d0SDavid Ahern  * struct l3mdev_ops - l3mdev operations
161b69c6d0SDavid Ahern  *
171b69c6d0SDavid Ahern  * @l3mdev_fib_table: Get FIB table id to use for lookups
181b69c6d0SDavid Ahern  *
191b69c6d0SDavid Ahern  * @l3mdev_get_rtable: Get cached IPv4 rtable (dst_entry) for device
208cbb512cSDavid Ahern  *
218cbb512cSDavid Ahern  * @l3mdev_get_saddr: Get source address for a flow
221b69c6d0SDavid Ahern  */
231b69c6d0SDavid Ahern 
241b69c6d0SDavid Ahern struct l3mdev_ops {
251b69c6d0SDavid Ahern 	u32		(*l3mdev_fib_table)(const struct net_device *dev);
261b69c6d0SDavid Ahern 	struct rtable *	(*l3mdev_get_rtable)(const struct net_device *dev,
271b69c6d0SDavid Ahern 					     const struct flowi4 *fl4);
288cbb512cSDavid Ahern 	void		(*l3mdev_get_saddr)(struct net_device *dev,
298cbb512cSDavid Ahern 					    struct flowi4 *fl4);
301b69c6d0SDavid Ahern };
311b69c6d0SDavid Ahern 
321b69c6d0SDavid Ahern #ifdef CONFIG_NET_L3_MASTER_DEV
331b69c6d0SDavid Ahern 
341b69c6d0SDavid Ahern int l3mdev_master_ifindex_rcu(struct net_device *dev);
351b69c6d0SDavid Ahern static inline int l3mdev_master_ifindex(struct net_device *dev)
361b69c6d0SDavid Ahern {
371b69c6d0SDavid Ahern 	int ifindex;
381b69c6d0SDavid Ahern 
391b69c6d0SDavid Ahern 	rcu_read_lock();
401b69c6d0SDavid Ahern 	ifindex = l3mdev_master_ifindex_rcu(dev);
411b69c6d0SDavid Ahern 	rcu_read_unlock();
421b69c6d0SDavid Ahern 
431b69c6d0SDavid Ahern 	return ifindex;
441b69c6d0SDavid Ahern }
451b69c6d0SDavid Ahern 
461b69c6d0SDavid Ahern /* get index of an interface to use for FIB lookups. For devices
471b69c6d0SDavid Ahern  * enslaved to an L3 master device FIB lookups are based on the
481b69c6d0SDavid Ahern  * master index
491b69c6d0SDavid Ahern  */
501b69c6d0SDavid Ahern static inline int l3mdev_fib_oif_rcu(struct net_device *dev)
511b69c6d0SDavid Ahern {
521b69c6d0SDavid Ahern 	return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex;
531b69c6d0SDavid Ahern }
541b69c6d0SDavid Ahern 
551b69c6d0SDavid Ahern static inline int l3mdev_fib_oif(struct net_device *dev)
561b69c6d0SDavid Ahern {
571b69c6d0SDavid Ahern 	int oif;
581b69c6d0SDavid Ahern 
591b69c6d0SDavid Ahern 	rcu_read_lock();
601b69c6d0SDavid Ahern 	oif = l3mdev_fib_oif_rcu(dev);
611b69c6d0SDavid Ahern 	rcu_read_unlock();
621b69c6d0SDavid Ahern 
631b69c6d0SDavid Ahern 	return oif;
641b69c6d0SDavid Ahern }
651b69c6d0SDavid Ahern 
661b69c6d0SDavid Ahern u32 l3mdev_fib_table_rcu(const struct net_device *dev);
671b69c6d0SDavid Ahern u32 l3mdev_fib_table_by_index(struct net *net, int ifindex);
681b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table(const struct net_device *dev)
691b69c6d0SDavid Ahern {
701b69c6d0SDavid Ahern 	u32 tb_id;
711b69c6d0SDavid Ahern 
721b69c6d0SDavid Ahern 	rcu_read_lock();
731b69c6d0SDavid Ahern 	tb_id = l3mdev_fib_table_rcu(dev);
741b69c6d0SDavid Ahern 	rcu_read_unlock();
751b69c6d0SDavid Ahern 
761b69c6d0SDavid Ahern 	return tb_id;
771b69c6d0SDavid Ahern }
781b69c6d0SDavid Ahern 
791b69c6d0SDavid Ahern static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev,
801b69c6d0SDavid Ahern 					       const struct flowi4 *fl4)
811b69c6d0SDavid Ahern {
821b69c6d0SDavid Ahern 	if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rtable)
831b69c6d0SDavid Ahern 		return dev->l3mdev_ops->l3mdev_get_rtable(dev, fl4);
841b69c6d0SDavid Ahern 
851b69c6d0SDavid Ahern 	return NULL;
861b69c6d0SDavid Ahern }
871b69c6d0SDavid Ahern 
889478d12dSDavid Ahern static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
899478d12dSDavid Ahern {
909478d12dSDavid Ahern 	struct net_device *dev;
919478d12dSDavid Ahern 	bool rc = false;
929478d12dSDavid Ahern 
939478d12dSDavid Ahern 	if (ifindex == 0)
949478d12dSDavid Ahern 		return false;
959478d12dSDavid Ahern 
969478d12dSDavid Ahern 	rcu_read_lock();
979478d12dSDavid Ahern 
989478d12dSDavid Ahern 	dev = dev_get_by_index_rcu(net, ifindex);
999478d12dSDavid Ahern 	if (dev)
1009478d12dSDavid Ahern 		rc = netif_is_l3_master(dev);
1019478d12dSDavid Ahern 
1029478d12dSDavid Ahern 	rcu_read_unlock();
1039478d12dSDavid Ahern 
1049478d12dSDavid Ahern 	return rc;
1059478d12dSDavid Ahern }
1069478d12dSDavid Ahern 
1078cbb512cSDavid Ahern static inline void l3mdev_get_saddr(struct net *net, int ifindex,
1088cbb512cSDavid Ahern 				    struct flowi4 *fl4)
1098cbb512cSDavid Ahern {
1108cbb512cSDavid Ahern 	struct net_device *dev;
1118cbb512cSDavid Ahern 
1128cbb512cSDavid Ahern 	if (ifindex) {
1138cbb512cSDavid Ahern 
1148cbb512cSDavid Ahern 		rcu_read_lock();
1158cbb512cSDavid Ahern 
1168cbb512cSDavid Ahern 		dev = dev_get_by_index_rcu(net, ifindex);
1178cbb512cSDavid Ahern 		if (dev && netif_is_l3_master(dev) &&
1188cbb512cSDavid Ahern 		    dev->l3mdev_ops->l3mdev_get_saddr) {
1198cbb512cSDavid Ahern 			dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4);
1208cbb512cSDavid Ahern 		}
1218cbb512cSDavid Ahern 
1228cbb512cSDavid Ahern 		rcu_read_unlock();
1238cbb512cSDavid Ahern 	}
1248cbb512cSDavid Ahern }
1258cbb512cSDavid Ahern 
1261b69c6d0SDavid Ahern #else
1271b69c6d0SDavid Ahern 
1281b69c6d0SDavid Ahern static inline int l3mdev_master_ifindex_rcu(struct net_device *dev)
1291b69c6d0SDavid Ahern {
1301b69c6d0SDavid Ahern 	return 0;
1311b69c6d0SDavid Ahern }
1321b69c6d0SDavid Ahern static inline int l3mdev_master_ifindex(struct net_device *dev)
1331b69c6d0SDavid Ahern {
1341b69c6d0SDavid Ahern 	return 0;
1351b69c6d0SDavid Ahern }
1361b69c6d0SDavid Ahern 
1371b69c6d0SDavid Ahern static inline int l3mdev_fib_oif_rcu(struct net_device *dev)
1381b69c6d0SDavid Ahern {
1391b69c6d0SDavid Ahern 	return dev ? dev->ifindex : 0;
1401b69c6d0SDavid Ahern }
1411b69c6d0SDavid Ahern static inline int l3mdev_fib_oif(struct net_device *dev)
1421b69c6d0SDavid Ahern {
1431b69c6d0SDavid Ahern 	return dev ? dev->ifindex : 0;
1441b69c6d0SDavid Ahern }
1451b69c6d0SDavid Ahern 
1461b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev)
1471b69c6d0SDavid Ahern {
1481b69c6d0SDavid Ahern 	return 0;
1491b69c6d0SDavid Ahern }
1501b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table(const struct net_device *dev)
1511b69c6d0SDavid Ahern {
1521b69c6d0SDavid Ahern 	return 0;
1531b69c6d0SDavid Ahern }
1541b69c6d0SDavid Ahern static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex)
1551b69c6d0SDavid Ahern {
1561b69c6d0SDavid Ahern 	return 0;
1571b69c6d0SDavid Ahern }
1581b69c6d0SDavid Ahern 
1591b69c6d0SDavid Ahern static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev,
1601b69c6d0SDavid Ahern 					       const struct flowi4 *fl4)
1611b69c6d0SDavid Ahern {
1621b69c6d0SDavid Ahern 	return NULL;
1631b69c6d0SDavid Ahern }
1641b69c6d0SDavid Ahern 
1659478d12dSDavid Ahern static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
1669478d12dSDavid Ahern {
1679478d12dSDavid Ahern 	return false;
1689478d12dSDavid Ahern }
1699478d12dSDavid Ahern 
1708cbb512cSDavid Ahern static inline void l3mdev_get_saddr(struct net *net, int ifindex,
1718cbb512cSDavid Ahern 				    struct flowi4 *fl4)
1728cbb512cSDavid Ahern {
1738cbb512cSDavid Ahern }
1741b69c6d0SDavid Ahern #endif
1751b69c6d0SDavid Ahern 
1761b69c6d0SDavid Ahern #endif /* _NET_L3MDEV_H_ */
177