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