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 #include <net/dst.h> 15 #include <net/fib_rules.h> 16 17 /** 18 * struct l3mdev_ops - l3mdev operations 19 * 20 * @l3mdev_fib_table: Get FIB table id to use for lookups 21 * 22 * @l3mdev_l3_rcv: Hook in L3 receive path 23 * 24 * @l3mdev_l3_out: Hook in L3 output path 25 * 26 * @l3mdev_get_rtable: Get cached IPv4 rtable (dst_entry) for device 27 * 28 * @l3mdev_get_saddr: Get source address for a flow 29 * 30 * @l3mdev_link_scope_lookup: IPv6 lookup for linklocal and mcast destinations 31 */ 32 33 struct l3mdev_ops { 34 u32 (*l3mdev_fib_table)(const struct net_device *dev); 35 struct sk_buff * (*l3mdev_l3_rcv)(struct net_device *dev, 36 struct sk_buff *skb, u16 proto); 37 struct sk_buff * (*l3mdev_l3_out)(struct net_device *dev, 38 struct sock *sk, struct sk_buff *skb, 39 u16 proto); 40 41 /* IPv4 ops */ 42 struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev, 43 const struct flowi4 *fl4); 44 int (*l3mdev_get_saddr)(struct net_device *dev, 45 struct flowi4 *fl4); 46 47 /* IPv6 ops */ 48 struct dst_entry * (*l3mdev_link_scope_lookup)(const struct net_device *dev, 49 struct flowi6 *fl6); 50 int (*l3mdev_get_saddr6)(struct net_device *dev, 51 const struct sock *sk, 52 struct flowi6 *fl6); 53 }; 54 55 #ifdef CONFIG_NET_L3_MASTER_DEV 56 57 int l3mdev_fib_rule_match(struct net *net, struct flowi *fl, 58 struct fib_lookup_arg *arg); 59 60 void l3mdev_update_flow(struct net *net, struct flowi *fl); 61 62 int l3mdev_master_ifindex_rcu(const struct net_device *dev); 63 static inline int l3mdev_master_ifindex(struct net_device *dev) 64 { 65 int ifindex; 66 67 rcu_read_lock(); 68 ifindex = l3mdev_master_ifindex_rcu(dev); 69 rcu_read_unlock(); 70 71 return ifindex; 72 } 73 74 static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) 75 { 76 struct net_device *dev; 77 int rc = 0; 78 79 if (likely(ifindex)) { 80 rcu_read_lock(); 81 82 dev = dev_get_by_index_rcu(net, ifindex); 83 if (dev) 84 rc = l3mdev_master_ifindex_rcu(dev); 85 86 rcu_read_unlock(); 87 } 88 89 return rc; 90 } 91 92 static inline 93 struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev) 94 { 95 /* netdev_master_upper_dev_get_rcu calls 96 * list_first_or_null_rcu to walk the upper dev list. 97 * list_first_or_null_rcu does not handle a const arg. We aren't 98 * making changes, just want the master device from that list so 99 * typecast to remove the const 100 */ 101 struct net_device *dev = (struct net_device *)_dev; 102 struct net_device *master; 103 104 if (!dev) 105 return NULL; 106 107 if (netif_is_l3_master(dev)) 108 master = dev; 109 else if (netif_is_l3_slave(dev)) 110 master = netdev_master_upper_dev_get_rcu(dev); 111 else 112 master = NULL; 113 114 return master; 115 } 116 117 /* get index of an interface to use for FIB lookups. For devices 118 * enslaved to an L3 master device FIB lookups are based on the 119 * master index 120 */ 121 static inline int l3mdev_fib_oif_rcu(struct net_device *dev) 122 { 123 return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex; 124 } 125 126 static inline int l3mdev_fib_oif(struct net_device *dev) 127 { 128 int oif; 129 130 rcu_read_lock(); 131 oif = l3mdev_fib_oif_rcu(dev); 132 rcu_read_unlock(); 133 134 return oif; 135 } 136 137 u32 l3mdev_fib_table_rcu(const struct net_device *dev); 138 u32 l3mdev_fib_table_by_index(struct net *net, int ifindex); 139 static inline u32 l3mdev_fib_table(const struct net_device *dev) 140 { 141 u32 tb_id; 142 143 rcu_read_lock(); 144 tb_id = l3mdev_fib_table_rcu(dev); 145 rcu_read_unlock(); 146 147 return tb_id; 148 } 149 150 static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, 151 const struct flowi4 *fl4) 152 { 153 if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rtable) 154 return dev->l3mdev_ops->l3mdev_get_rtable(dev, fl4); 155 156 return NULL; 157 } 158 159 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 160 { 161 struct net_device *dev; 162 bool rc = false; 163 164 if (ifindex == 0) 165 return false; 166 167 rcu_read_lock(); 168 169 dev = dev_get_by_index_rcu(net, ifindex); 170 if (dev) 171 rc = netif_is_l3_master(dev); 172 173 rcu_read_unlock(); 174 175 return rc; 176 } 177 178 int l3mdev_get_saddr(struct net *net, int ifindex, struct flowi4 *fl4); 179 180 struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6); 181 int l3mdev_get_saddr6(struct net *net, const struct sock *sk, 182 struct flowi6 *fl6); 183 184 static inline 185 struct sk_buff *l3mdev_l3_rcv(struct sk_buff *skb, u16 proto) 186 { 187 struct net_device *master = NULL; 188 189 if (netif_is_l3_slave(skb->dev)) 190 master = netdev_master_upper_dev_get_rcu(skb->dev); 191 else if (netif_is_l3_master(skb->dev)) 192 master = skb->dev; 193 194 if (master && master->l3mdev_ops->l3mdev_l3_rcv) 195 skb = master->l3mdev_ops->l3mdev_l3_rcv(master, skb, proto); 196 197 return skb; 198 } 199 200 static inline 201 struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) 202 { 203 return l3mdev_l3_rcv(skb, AF_INET); 204 } 205 206 static inline 207 struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) 208 { 209 return l3mdev_l3_rcv(skb, AF_INET6); 210 } 211 212 static inline 213 struct sk_buff *l3mdev_l3_out(struct sock *sk, struct sk_buff *skb, u16 proto) 214 { 215 struct net_device *dev = skb_dst(skb)->dev; 216 217 if (netif_is_l3_slave(dev)) { 218 struct net_device *master; 219 220 master = netdev_master_upper_dev_get_rcu(dev); 221 if (master && master->l3mdev_ops->l3mdev_l3_out) 222 skb = master->l3mdev_ops->l3mdev_l3_out(master, sk, 223 skb, proto); 224 } 225 226 return skb; 227 } 228 229 static inline 230 struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) 231 { 232 return l3mdev_l3_out(sk, skb, AF_INET); 233 } 234 235 static inline 236 struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) 237 { 238 return l3mdev_l3_out(sk, skb, AF_INET6); 239 } 240 #else 241 242 static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev) 243 { 244 return 0; 245 } 246 static inline int l3mdev_master_ifindex(struct net_device *dev) 247 { 248 return 0; 249 } 250 251 static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) 252 { 253 return 0; 254 } 255 256 static inline 257 struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev) 258 { 259 return NULL; 260 } 261 262 static inline int l3mdev_fib_oif_rcu(struct net_device *dev) 263 { 264 return dev ? dev->ifindex : 0; 265 } 266 static inline int l3mdev_fib_oif(struct net_device *dev) 267 { 268 return dev ? dev->ifindex : 0; 269 } 270 271 static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev) 272 { 273 return 0; 274 } 275 static inline u32 l3mdev_fib_table(const struct net_device *dev) 276 { 277 return 0; 278 } 279 static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) 280 { 281 return 0; 282 } 283 284 static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, 285 const struct flowi4 *fl4) 286 { 287 return NULL; 288 } 289 290 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 291 { 292 return false; 293 } 294 295 static inline int l3mdev_get_saddr(struct net *net, int ifindex, 296 struct flowi4 *fl4) 297 { 298 return 0; 299 } 300 301 static inline 302 struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6) 303 { 304 return NULL; 305 } 306 307 static inline int l3mdev_get_saddr6(struct net *net, const struct sock *sk, 308 struct flowi6 *fl6) 309 { 310 return 0; 311 } 312 313 static inline 314 struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) 315 { 316 return skb; 317 } 318 319 static inline 320 struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) 321 { 322 return skb; 323 } 324 325 static inline 326 struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) 327 { 328 return skb; 329 } 330 331 static inline 332 struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) 333 { 334 return skb; 335 } 336 337 static inline 338 int l3mdev_fib_rule_match(struct net *net, struct flowi *fl, 339 struct fib_lookup_arg *arg) 340 { 341 return 1; 342 } 343 static inline 344 void l3mdev_update_flow(struct net *net, struct flowi *fl) 345 { 346 } 347 #endif 348 349 #endif /* _NET_L3MDEV_H_ */ 350