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