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 void l3mdev_update_flow(struct net *net, struct flowi *fl); 63 64 int l3mdev_master_ifindex_rcu(const struct net_device *dev); 65 static inline int l3mdev_master_ifindex(struct net_device *dev) 66 { 67 int ifindex; 68 69 rcu_read_lock(); 70 ifindex = l3mdev_master_ifindex_rcu(dev); 71 rcu_read_unlock(); 72 73 return ifindex; 74 } 75 76 static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) 77 { 78 struct net_device *dev; 79 int rc = 0; 80 81 if (likely(ifindex)) { 82 rcu_read_lock(); 83 84 dev = dev_get_by_index_rcu(net, ifindex); 85 if (dev) 86 rc = l3mdev_master_ifindex_rcu(dev); 87 88 rcu_read_unlock(); 89 } 90 91 return rc; 92 } 93 94 static inline 95 struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev) 96 { 97 /* netdev_master_upper_dev_get_rcu calls 98 * list_first_or_null_rcu to walk the upper dev list. 99 * list_first_or_null_rcu does not handle a const arg. We aren't 100 * making changes, just want the master device from that list so 101 * typecast to remove the const 102 */ 103 struct net_device *dev = (struct net_device *)_dev; 104 struct net_device *master; 105 106 if (!dev) 107 return NULL; 108 109 if (netif_is_l3_master(dev)) 110 master = dev; 111 else if (netif_is_l3_slave(dev)) 112 master = netdev_master_upper_dev_get_rcu(dev); 113 else 114 master = NULL; 115 116 return master; 117 } 118 119 int l3mdev_master_upper_ifindex_by_index_rcu(struct net *net, int ifindex); 120 static inline 121 int l3mdev_master_upper_ifindex_by_index(struct net *net, int ifindex) 122 { 123 rcu_read_lock(); 124 ifindex = l3mdev_master_upper_ifindex_by_index_rcu(net, ifindex); 125 rcu_read_unlock(); 126 127 return ifindex; 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 bool netif_index_is_l3_master(struct net *net, int ifindex) 144 { 145 struct net_device *dev; 146 bool rc = false; 147 148 if (ifindex == 0) 149 return false; 150 151 rcu_read_lock(); 152 153 dev = dev_get_by_index_rcu(net, ifindex); 154 if (dev) 155 rc = netif_is_l3_master(dev); 156 157 rcu_read_unlock(); 158 159 return rc; 160 } 161 162 struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6); 163 164 static inline 165 struct sk_buff *l3mdev_l3_rcv(struct sk_buff *skb, u16 proto) 166 { 167 struct net_device *master = NULL; 168 169 if (netif_is_l3_slave(skb->dev)) 170 master = netdev_master_upper_dev_get_rcu(skb->dev); 171 else if (netif_is_l3_master(skb->dev) || 172 netif_has_l3_rx_handler(skb->dev)) 173 master = skb->dev; 174 175 if (master && master->l3mdev_ops->l3mdev_l3_rcv) 176 skb = master->l3mdev_ops->l3mdev_l3_rcv(master, skb, proto); 177 178 return skb; 179 } 180 181 static inline 182 struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) 183 { 184 return l3mdev_l3_rcv(skb, AF_INET); 185 } 186 187 static inline 188 struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) 189 { 190 return l3mdev_l3_rcv(skb, AF_INET6); 191 } 192 193 static inline 194 struct sk_buff *l3mdev_l3_out(struct sock *sk, struct sk_buff *skb, u16 proto) 195 { 196 struct net_device *dev = skb_dst(skb)->dev; 197 198 if (netif_is_l3_slave(dev)) { 199 struct net_device *master; 200 201 master = netdev_master_upper_dev_get_rcu(dev); 202 if (master && master->l3mdev_ops->l3mdev_l3_out) 203 skb = master->l3mdev_ops->l3mdev_l3_out(master, sk, 204 skb, proto); 205 } 206 207 return skb; 208 } 209 210 static inline 211 struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) 212 { 213 return l3mdev_l3_out(sk, skb, AF_INET); 214 } 215 216 static inline 217 struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) 218 { 219 return l3mdev_l3_out(sk, skb, AF_INET6); 220 } 221 #else 222 223 static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev) 224 { 225 return 0; 226 } 227 static inline int l3mdev_master_ifindex(struct net_device *dev) 228 { 229 return 0; 230 } 231 232 static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) 233 { 234 return 0; 235 } 236 237 static inline 238 int l3mdev_master_upper_ifindex_by_index_rcu(struct net *net, int ifindex) 239 { 240 return 0; 241 } 242 static inline 243 int l3mdev_master_upper_ifindex_by_index(struct net *net, int ifindex) 244 { 245 return 0; 246 } 247 248 static inline 249 struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev) 250 { 251 return NULL; 252 } 253 254 static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev) 255 { 256 return 0; 257 } 258 static inline u32 l3mdev_fib_table(const struct net_device *dev) 259 { 260 return 0; 261 } 262 static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) 263 { 264 return 0; 265 } 266 267 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 268 { 269 return false; 270 } 271 272 static inline 273 struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6) 274 { 275 return NULL; 276 } 277 278 static inline 279 struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) 280 { 281 return skb; 282 } 283 284 static inline 285 struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) 286 { 287 return skb; 288 } 289 290 static inline 291 struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) 292 { 293 return skb; 294 } 295 296 static inline 297 struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) 298 { 299 return skb; 300 } 301 302 static inline 303 int l3mdev_table_lookup_register(enum l3mdev_type l3type, 304 lookup_by_table_id_t fn) 305 { 306 return -EOPNOTSUPP; 307 } 308 309 static inline 310 void l3mdev_table_lookup_unregister(enum l3mdev_type l3type, 311 lookup_by_table_id_t fn) 312 { 313 } 314 315 static inline 316 int l3mdev_ifindex_lookup_by_table_id(enum l3mdev_type l3type, struct net *net, 317 u32 table_id) 318 { 319 return -ENODEV; 320 } 321 322 static inline 323 int l3mdev_fib_rule_match(struct net *net, struct flowi *fl, 324 struct fib_lookup_arg *arg) 325 { 326 return 1; 327 } 328 static inline 329 void l3mdev_update_flow(struct net *net, struct flowi *fl) 330 { 331 } 332 #endif 333 334 #endif /* _NET_L3MDEV_H_ */ 335
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.