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