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 int (*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 static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) 55 { 56 struct net_device *dev; 57 int rc = 0; 58 59 if (likely(ifindex)) { 60 rcu_read_lock(); 61 62 dev = dev_get_by_index_rcu(net, ifindex); 63 if (dev) 64 rc = l3mdev_master_ifindex_rcu(dev); 65 66 rcu_read_unlock(); 67 } 68 69 return rc; 70 } 71 72 /* get index of an interface to use for FIB lookups. For devices 73 * enslaved to an L3 master device FIB lookups are based on the 74 * master index 75 */ 76 static inline int l3mdev_fib_oif_rcu(struct net_device *dev) 77 { 78 return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex; 79 } 80 81 static inline int l3mdev_fib_oif(struct net_device *dev) 82 { 83 int oif; 84 85 rcu_read_lock(); 86 oif = l3mdev_fib_oif_rcu(dev); 87 rcu_read_unlock(); 88 89 return oif; 90 } 91 92 u32 l3mdev_fib_table_rcu(const struct net_device *dev); 93 u32 l3mdev_fib_table_by_index(struct net *net, int ifindex); 94 static inline u32 l3mdev_fib_table(const struct net_device *dev) 95 { 96 u32 tb_id; 97 98 rcu_read_lock(); 99 tb_id = l3mdev_fib_table_rcu(dev); 100 rcu_read_unlock(); 101 102 return tb_id; 103 } 104 105 static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, 106 const struct flowi4 *fl4) 107 { 108 if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rtable) 109 return dev->l3mdev_ops->l3mdev_get_rtable(dev, fl4); 110 111 return NULL; 112 } 113 114 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 115 { 116 struct net_device *dev; 117 bool rc = false; 118 119 if (ifindex == 0) 120 return false; 121 122 rcu_read_lock(); 123 124 dev = dev_get_by_index_rcu(net, ifindex); 125 if (dev) 126 rc = netif_is_l3_master(dev); 127 128 rcu_read_unlock(); 129 130 return rc; 131 } 132 133 static inline int l3mdev_get_saddr(struct net *net, int ifindex, 134 struct flowi4 *fl4) 135 { 136 struct net_device *dev; 137 int rc = 0; 138 139 if (ifindex) { 140 141 rcu_read_lock(); 142 143 dev = dev_get_by_index_rcu(net, ifindex); 144 if (dev && netif_is_l3_master(dev) && 145 dev->l3mdev_ops->l3mdev_get_saddr) { 146 rc = dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4); 147 } 148 149 rcu_read_unlock(); 150 } 151 152 return rc; 153 } 154 155 static inline struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev, 156 const struct flowi6 *fl6) 157 { 158 if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rt6_dst) 159 return dev->l3mdev_ops->l3mdev_get_rt6_dst(dev, fl6); 160 161 return NULL; 162 } 163 164 static inline 165 struct dst_entry *l3mdev_rt6_dst_by_oif(struct net *net, 166 const struct flowi6 *fl6) 167 { 168 struct dst_entry *dst = NULL; 169 struct net_device *dev; 170 171 dev = dev_get_by_index(net, fl6->flowi6_oif); 172 if (dev) { 173 dst = l3mdev_get_rt6_dst(dev, fl6); 174 dev_put(dev); 175 } 176 177 return dst; 178 } 179 180 #else 181 182 static inline int l3mdev_master_ifindex_rcu(struct net_device *dev) 183 { 184 return 0; 185 } 186 static inline int l3mdev_master_ifindex(struct net_device *dev) 187 { 188 return 0; 189 } 190 191 static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) 192 { 193 return 0; 194 } 195 196 static inline int l3mdev_fib_oif_rcu(struct net_device *dev) 197 { 198 return dev ? dev->ifindex : 0; 199 } 200 static inline int l3mdev_fib_oif(struct net_device *dev) 201 { 202 return dev ? dev->ifindex : 0; 203 } 204 205 static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev) 206 { 207 return 0; 208 } 209 static inline u32 l3mdev_fib_table(const struct net_device *dev) 210 { 211 return 0; 212 } 213 static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) 214 { 215 return 0; 216 } 217 218 static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, 219 const struct flowi4 *fl4) 220 { 221 return NULL; 222 } 223 224 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 225 { 226 return false; 227 } 228 229 static inline int l3mdev_get_saddr(struct net *net, int ifindex, 230 struct flowi4 *fl4) 231 { 232 return 0; 233 } 234 235 static inline 236 struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev, 237 const struct flowi6 *fl6) 238 { 239 return NULL; 240 } 241 static inline 242 struct dst_entry *l3mdev_rt6_dst_by_oif(struct net *net, 243 const struct flowi6 *fl6) 244 { 245 return NULL; 246 } 247 #endif 248 249 #endif /* _NET_L3MDEV_H_ */ 250