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