Branch data Line data Source code
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 : 3 : ifindex = l3mdev_master_ifindex_rcu(dev); 52 : : rcu_read_unlock(); 53 : : 54 : : return ifindex; 55 : : } 56 : : 57 : 1 : 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 : 1 : if (likely(ifindex)) { 63 : : rcu_read_lock(); 64 : : 65 : 0 : dev = dev_get_by_index_rcu(net, ifindex); 66 : 0 : if (dev) 67 : 0 : rc = l3mdev_master_ifindex_rcu(dev); 68 : : 69 : : rcu_read_unlock(); 70 : : } 71 : : 72 : 1 : return rc; 73 : : } 74 : : 75 : : static inline 76 : 3 : 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 : 3 : if (!dev) 88 : : return NULL; 89 : : 90 : 3 : if (netif_is_l3_master(dev)) 91 : : master = dev; 92 : 3 : else if (netif_is_l3_slave(dev)) 93 : 0 : master = netdev_master_upper_dev_get_rcu(dev); 94 : : else 95 : : master = NULL; 96 : : 97 : 3 : 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 : 3 : tb_id = l3mdev_fib_table_rcu(dev); 119 : : rcu_read_unlock(); 120 : : 121 : : return tb_id; 122 : : } 123 : : 124 : 3 : 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 : 3 : if (ifindex == 0) 130 : : return false; 131 : : 132 : : rcu_read_lock(); 133 : : 134 : 3 : dev = dev_get_by_index_rcu(net, ifindex); 135 : 3 : if (dev) 136 : : rc = netif_is_l3_master(dev); 137 : : 138 : : rcu_read_unlock(); 139 : : 140 : 3 : return rc; 141 : : } 142 : : 143 : : struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6); 144 : : 145 : : static inline 146 : 3 : struct sk_buff *l3mdev_l3_rcv(struct sk_buff *skb, u16 proto) 147 : : { 148 : : struct net_device *master = NULL; 149 : : 150 : 3 : if (netif_is_l3_slave(skb->dev)) 151 : 0 : master = netdev_master_upper_dev_get_rcu(skb->dev); 152 : 3 : else if (netif_is_l3_master(skb->dev) || 153 : : netif_has_l3_rx_handler(skb->dev)) 154 : : master = skb->dev; 155 : : 156 : 3 : if (master && master->l3mdev_ops->l3mdev_l3_rcv) 157 : 0 : skb = master->l3mdev_ops->l3mdev_l3_rcv(master, skb, proto); 158 : : 159 : 3 : return skb; 160 : : } 161 : : 162 : : static inline 163 : : struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) 164 : : { 165 : 3 : 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 : 3 : return l3mdev_l3_rcv(skb, AF_INET6); 172 : : } 173 : : 174 : : static inline 175 : 3 : struct sk_buff *l3mdev_l3_out(struct sock *sk, struct sk_buff *skb, u16 proto) 176 : : { 177 : 3 : struct net_device *dev = skb_dst(skb)->dev; 178 : : 179 : 3 : if (netif_is_l3_slave(dev)) { 180 : : struct net_device *master; 181 : : 182 : 0 : master = netdev_master_upper_dev_get_rcu(dev); 183 : 0 : if (master && master->l3mdev_ops->l3mdev_l3_out) 184 : 0 : skb = master->l3mdev_ops->l3mdev_l3_out(master, sk, 185 : : skb, proto); 186 : : } 187 : : 188 : 3 : return skb; 189 : : } 190 : : 191 : : static inline 192 : : struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) 193 : : { 194 : 3 : 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 : 3 : 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_ */