1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * include/net/l3mdev.h - L3 master device API 4 * Copyright (c) 2015 Cumulus Networks 5 * Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com> 6 */ 7 #ifndef _NET_L3MDEV_H_ 8 #define _NET_L3MDEV_H_ 9 10 #include <net/dst.h> 11 #include <net/fib_rules.h> 12 13 enum l3mdev_type { 14 L3MDEV_TYPE_UNSPEC, 15 L3MDEV_TYPE_VRF, 16 __L3MDEV_TYPE_MAX 17 }; 18 19 #define L3MDEV_TYPE_MAX (__L3MDEV_TYPE_MAX - 1) 20 21 typedef int (*lookup_by_table_id_t)(struct net *net, u32 table_d); 22 23 /** 24 * struct l3mdev_ops - l3mdev operations 25 * 26 * @l3mdev_fib_table: Get FIB table id to use for lookups 27 * 28 * @l3mdev_l3_rcv: Hook in L3 receive path 29 * 30 * @l3mdev_l3_out: Hook in L3 output path 31 * 32 * @l3mdev_link_scope_lookup: IPv6 lookup for linklocal and mcast destinations 33 */ 34 35 struct l3mdev_ops { 36 u32 (*l3mdev_fib_table)(const struct net_device *dev); 37 struct sk_buff * (*l3mdev_l3_rcv)(struct net_device *dev, 38 struct sk_buff *skb, u16 proto); 39 struct sk_buff * (*l3mdev_l3_out)(struct net_device *dev, 40 struct sock *sk, struct sk_buff *skb, 41 u16 proto); 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_table_lookup_register(enum l3mdev_type l3type, 51 lookup_by_table_id_t fn); 52 53 void l3mdev_table_lookup_unregister(enum l3mdev_type l3type, 54 lookup_by_table_id_t fn); 55 56 int l3mdev_ifindex_lookup_by_table_id(enum l3mdev_type l3type, struct net *net, 57 u32 table_id); 58 59 int l3mdev_fib_rule_match(struct net *net, struct flowi *fl, 60 struct fib_lookup_arg *arg); 61 62 static inline 63 bool l3mdev_fib_rule_iif_match(const struct flowi *fl, int iifindex) 64 { 65 return !(fl->flowi_flags & FLOWI_FLAG_L3MDEV_OIF) && 66 fl->flowi_l3mdev == iifindex; 67 } 68 69 static inline 70 bool l3mdev_fib_rule_oif_match(const struct flowi *fl, int oifindex) 71 { 72 return fl->flowi_flags & FLOWI_FLAG_L3MDEV_OIF && 73 fl->flowi_l3mdev == oifindex; 74 } 75 76 void l3mdev_update_flow(struct net *net, struct flowi *fl); 77 78 int l3mdev_master_ifindex_rcu(const struct net_device *dev); 79 static inline int l3mdev_master_ifindex(struct net_device *dev) 80 { 81 int ifindex; 82 83 rcu_read_lock(); 84 ifindex = l3mdev_master_ifindex_rcu(dev); 85 rcu_read_unlock(); 86 87 return ifindex; 88 } 89 90 static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) 91 { 92 struct net_device *dev; 93 int rc = 0; 94 95 if (ifindex) { 96 rcu_read_lock(); 97 98 dev = dev_get_by_index_rcu(net, ifindex); 99 if (dev) 100 rc = l3mdev_master_ifindex_rcu(dev); 101 102 rcu_read_unlock(); 103 } 104 105 return rc; 106 } 107 108 static inline 109 struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev) 110 { 111 /* netdev_master_upper_dev_get_rcu calls 112 * list_first_or_null_rcu to walk the upper dev list. 113 * list_first_or_null_rcu does not handle a const arg. We aren't 114 * making changes, just want the master device from that list so 115 * typecast to remove the const 116 */ 117 struct net_device *dev = (struct net_device *)_dev; 118 struct net_device *master; 119 120 if (!dev) 121 return NULL; 122 123 if (netif_is_l3_master(dev)) 124 master = dev; 125 else if (netif_is_l3_slave(dev)) 126 master = netdev_master_upper_dev_get_rcu(dev); 127 else 128 master = NULL; 129 130 return master; 131 } 132 133 int l3mdev_master_upper_ifindex_by_index_rcu(struct net *net, int ifindex); 134 static inline 135 int l3mdev_master_upper_ifindex_by_index(struct net *net, int ifindex) 136 { 137 rcu_read_lock(); 138 ifindex = l3mdev_master_upper_ifindex_by_index_rcu(net, ifindex); 139 rcu_read_unlock(); 140 141 return ifindex; 142 } 143 144 u32 l3mdev_fib_table_rcu(const struct net_device *dev); 145 u32 l3mdev_fib_table_by_index(struct net *net, int ifindex); 146 static inline u32 l3mdev_fib_table(const struct net_device *dev) 147 { 148 u32 tb_id; 149 150 rcu_read_lock(); 151 tb_id = l3mdev_fib_table_rcu(dev); 152 rcu_read_unlock(); 153 154 return tb_id; 155 } 156 157 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 158 { 159 struct net_device *dev; 160 bool rc = false; 161 162 if (ifindex == 0) 163 return false; 164 165 rcu_read_lock(); 166 167 dev = dev_get_by_index_rcu(net, ifindex); 168 if (dev) 169 rc = netif_is_l3_master(dev); 170 171 rcu_read_unlock(); 172 173 return rc; 174 } 175 176 struct dst_entry *l3mdev_link_scope_lookup(struct net *net, 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 netif_has_l3_rx_handler(skb->dev)) 187 master = skb->dev; 188 189 if (master && master->l3mdev_ops->l3mdev_l3_rcv) 190 skb = master->l3mdev_ops->l3mdev_l3_rcv(master, skb, proto); 191 192 return skb; 193 } 194 195 static inline 196 struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) 197 { 198 return l3mdev_l3_rcv(skb, AF_INET); 199 } 200 201 static inline 202 struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) 203 { 204 return l3mdev_l3_rcv(skb, AF_INET6); 205 } 206 207 static inline 208 struct sk_buff *l3mdev_l3_out(struct sock *sk, struct sk_buff *skb, u16 proto) 209 { 210 struct net_device *dev; 211 212 rcu_read_lock(); 213 dev = skb_dst_dev_rcu(skb); 214 if (netif_is_l3_slave(dev)) { 215 struct net_device *master; 216 217 master = netdev_master_upper_dev_get_rcu(dev); 218 if (master && master->l3mdev_ops->l3mdev_l3_out) 219 skb = master->l3mdev_ops->l3mdev_l3_out(master, sk, 220 skb, proto); 221 } 222 rcu_read_unlock(); 223 224 return skb; 225 } 226 227 static inline 228 struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) 229 { 230 return l3mdev_l3_out(sk, skb, AF_INET); 231 } 232 233 static inline 234 struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) 235 { 236 return l3mdev_l3_out(sk, skb, AF_INET6); 237 } 238 #else 239 240 static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev) 241 { 242 return 0; 243 } 244 static inline int l3mdev_master_ifindex(struct net_device *dev) 245 { 246 return 0; 247 } 248 249 static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) 250 { 251 return 0; 252 } 253 254 static inline 255 int l3mdev_master_upper_ifindex_by_index_rcu(struct net *net, int ifindex) 256 { 257 return 0; 258 } 259 static inline 260 int l3mdev_master_upper_ifindex_by_index(struct net *net, int ifindex) 261 { 262 return 0; 263 } 264 265 static inline 266 struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev) 267 { 268 return NULL; 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 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 296 struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) 297 { 298 return skb; 299 } 300 301 static inline 302 struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) 303 { 304 return skb; 305 } 306 307 static inline 308 struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) 309 { 310 return skb; 311 } 312 313 static inline 314 struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) 315 { 316 return skb; 317 } 318 319 static inline 320 int l3mdev_table_lookup_register(enum l3mdev_type l3type, 321 lookup_by_table_id_t fn) 322 { 323 return -EOPNOTSUPP; 324 } 325 326 static inline 327 void l3mdev_table_lookup_unregister(enum l3mdev_type l3type, 328 lookup_by_table_id_t fn) 329 { 330 } 331 332 static inline 333 int l3mdev_ifindex_lookup_by_table_id(enum l3mdev_type l3type, struct net *net, 334 u32 table_id) 335 { 336 return -ENODEV; 337 } 338 339 static inline 340 int l3mdev_fib_rule_match(struct net *net, struct flowi *fl, 341 struct fib_lookup_arg *arg) 342 { 343 return 1; 344 } 345 346 static inline 347 bool l3mdev_fib_rule_iif_match(const struct flowi *fl, int iifindex) 348 { 349 return false; 350 } 351 352 static inline 353 bool l3mdev_fib_rule_oif_match(const struct flowi *fl, int oifindex) 354 { 355 return false; 356 } 357 358 static inline 359 void l3mdev_update_flow(struct net *net, struct flowi *fl) 360 { 361 } 362 #endif 363 364 #endif /* _NET_L3MDEV_H_ */ 365