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