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