1 /* 2 * include/net/l3mdev.h - L3 master device API 3 * Copyright (c) 2015 Cumulus Networks 4 * Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 #ifndef _NET_L3MDEV_H_ 12 #define _NET_L3MDEV_H_ 13 14 /** 15 * struct l3mdev_ops - l3mdev operations 16 * 17 * @l3mdev_fib_table: Get FIB table id to use for lookups 18 * 19 * @l3mdev_get_rtable: Get cached IPv4 rtable (dst_entry) for device 20 * 21 * @l3mdev_get_saddr: Get source address for a flow 22 * 23 * @l3mdev_get_rt6_dst: Get cached IPv6 rt6_info (dst_entry) for device 24 */ 25 26 struct l3mdev_ops { 27 u32 (*l3mdev_fib_table)(const struct net_device *dev); 28 29 /* IPv4 ops */ 30 struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev, 31 const struct flowi4 *fl4); 32 void (*l3mdev_get_saddr)(struct net_device *dev, 33 struct flowi4 *fl4); 34 35 /* IPv6 ops */ 36 struct dst_entry * (*l3mdev_get_rt6_dst)(const struct net_device *dev, 37 const struct flowi6 *fl6); 38 }; 39 40 #ifdef CONFIG_NET_L3_MASTER_DEV 41 42 int l3mdev_master_ifindex_rcu(struct net_device *dev); 43 static inline int l3mdev_master_ifindex(struct net_device *dev) 44 { 45 int ifindex; 46 47 rcu_read_lock(); 48 ifindex = l3mdev_master_ifindex_rcu(dev); 49 rcu_read_unlock(); 50 51 return ifindex; 52 } 53 54 /* get index of an interface to use for FIB lookups. For devices 55 * enslaved to an L3 master device FIB lookups are based on the 56 * master index 57 */ 58 static inline int l3mdev_fib_oif_rcu(struct net_device *dev) 59 { 60 return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex; 61 } 62 63 static inline int l3mdev_fib_oif(struct net_device *dev) 64 { 65 int oif; 66 67 rcu_read_lock(); 68 oif = l3mdev_fib_oif_rcu(dev); 69 rcu_read_unlock(); 70 71 return oif; 72 } 73 74 u32 l3mdev_fib_table_rcu(const struct net_device *dev); 75 u32 l3mdev_fib_table_by_index(struct net *net, int ifindex); 76 static inline u32 l3mdev_fib_table(const struct net_device *dev) 77 { 78 u32 tb_id; 79 80 rcu_read_lock(); 81 tb_id = l3mdev_fib_table_rcu(dev); 82 rcu_read_unlock(); 83 84 return tb_id; 85 } 86 87 static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, 88 const struct flowi4 *fl4) 89 { 90 if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rtable) 91 return dev->l3mdev_ops->l3mdev_get_rtable(dev, fl4); 92 93 return NULL; 94 } 95 96 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 97 { 98 struct net_device *dev; 99 bool rc = false; 100 101 if (ifindex == 0) 102 return false; 103 104 rcu_read_lock(); 105 106 dev = dev_get_by_index_rcu(net, ifindex); 107 if (dev) 108 rc = netif_is_l3_master(dev); 109 110 rcu_read_unlock(); 111 112 return rc; 113 } 114 115 static inline void l3mdev_get_saddr(struct net *net, int ifindex, 116 struct flowi4 *fl4) 117 { 118 struct net_device *dev; 119 120 if (ifindex) { 121 122 rcu_read_lock(); 123 124 dev = dev_get_by_index_rcu(net, ifindex); 125 if (dev && netif_is_l3_master(dev) && 126 dev->l3mdev_ops->l3mdev_get_saddr) { 127 dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4); 128 } 129 130 rcu_read_unlock(); 131 } 132 } 133 134 static inline struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev, 135 const struct flowi6 *fl6) 136 { 137 if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rt6_dst) 138 return dev->l3mdev_ops->l3mdev_get_rt6_dst(dev, fl6); 139 140 return NULL; 141 } 142 143 static inline 144 struct dst_entry *l3mdev_rt6_dst_by_oif(struct net *net, 145 const struct flowi6 *fl6) 146 { 147 struct dst_entry *dst = NULL; 148 struct net_device *dev; 149 150 dev = dev_get_by_index(net, fl6->flowi6_oif); 151 if (dev) { 152 dst = l3mdev_get_rt6_dst(dev, fl6); 153 dev_put(dev); 154 } 155 156 return dst; 157 } 158 159 #else 160 161 static inline int l3mdev_master_ifindex_rcu(struct net_device *dev) 162 { 163 return 0; 164 } 165 static inline int l3mdev_master_ifindex(struct net_device *dev) 166 { 167 return 0; 168 } 169 170 static inline int l3mdev_fib_oif_rcu(struct net_device *dev) 171 { 172 return dev ? dev->ifindex : 0; 173 } 174 static inline int l3mdev_fib_oif(struct net_device *dev) 175 { 176 return dev ? dev->ifindex : 0; 177 } 178 179 static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev) 180 { 181 return 0; 182 } 183 static inline u32 l3mdev_fib_table(const struct net_device *dev) 184 { 185 return 0; 186 } 187 static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) 188 { 189 return 0; 190 } 191 192 static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, 193 const struct flowi4 *fl4) 194 { 195 return NULL; 196 } 197 198 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 199 { 200 return false; 201 } 202 203 static inline void l3mdev_get_saddr(struct net *net, int ifindex, 204 struct flowi4 *fl4) 205 { 206 } 207 208 static inline 209 struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev, 210 const struct flowi6 *fl6) 211 { 212 return NULL; 213 } 214 static inline 215 struct dst_entry *l3mdev_rt6_dst_by_oif(struct net *net, 216 const struct flowi6 *fl6) 217 { 218 return NULL; 219 } 220 #endif 221 222 #endif /* _NET_L3MDEV_H_ */ 223