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