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