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 29 struct 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 44 int l3mdev_fib_rule_match(struct net *net, struct flowi *fl, 45 struct fib_lookup_arg *arg); 46 47 void l3mdev_update_flow(struct net *net, struct flowi *fl); 48 49 int l3mdev_master_ifindex_rcu(const struct net_device *dev); 50 static 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 61 static 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 79 static inline 80 struct 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 104 u32 l3mdev_fib_table_rcu(const struct net_device *dev); 105 u32 l3mdev_fib_table_by_index(struct net *net, int ifindex); 106 static inline u32 l3mdev_fib_table(const struct net_device *dev) 107 { 108 u32 tb_id; 109 110 rcu_read_lock(); 111 tb_id = l3mdev_fib_table_rcu(dev); 112 rcu_read_unlock(); 113 114 return tb_id; 115 } 116 117 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 118 { 119 struct net_device *dev; 120 bool rc = false; 121 122 if (ifindex == 0) 123 return false; 124 125 rcu_read_lock(); 126 127 dev = dev_get_by_index_rcu(net, ifindex); 128 if (dev) 129 rc = netif_is_l3_master(dev); 130 131 rcu_read_unlock(); 132 133 return rc; 134 } 135 136 struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6); 137 138 static inline 139 struct sk_buff *l3mdev_l3_rcv(struct sk_buff *skb, u16 proto) 140 { 141 struct net_device *master = NULL; 142 143 if (netif_is_l3_slave(skb->dev)) 144 master = netdev_master_upper_dev_get_rcu(skb->dev); 145 else if (netif_is_l3_master(skb->dev)) 146 master = skb->dev; 147 148 if (master && master->l3mdev_ops->l3mdev_l3_rcv) 149 skb = master->l3mdev_ops->l3mdev_l3_rcv(master, skb, proto); 150 151 return skb; 152 } 153 154 static inline 155 struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) 156 { 157 return l3mdev_l3_rcv(skb, AF_INET); 158 } 159 160 static inline 161 struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) 162 { 163 return l3mdev_l3_rcv(skb, AF_INET6); 164 } 165 166 static inline 167 struct sk_buff *l3mdev_l3_out(struct sock *sk, struct sk_buff *skb, u16 proto) 168 { 169 struct net_device *dev = skb_dst(skb)->dev; 170 171 if (netif_is_l3_slave(dev)) { 172 struct net_device *master; 173 174 master = netdev_master_upper_dev_get_rcu(dev); 175 if (master && master->l3mdev_ops->l3mdev_l3_out) 176 skb = master->l3mdev_ops->l3mdev_l3_out(master, sk, 177 skb, proto); 178 } 179 180 return skb; 181 } 182 183 static inline 184 struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) 185 { 186 return l3mdev_l3_out(sk, skb, AF_INET); 187 } 188 189 static inline 190 struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) 191 { 192 return l3mdev_l3_out(sk, skb, AF_INET6); 193 } 194 #else 195 196 static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev) 197 { 198 return 0; 199 } 200 static inline int l3mdev_master_ifindex(struct net_device *dev) 201 { 202 return 0; 203 } 204 205 static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) 206 { 207 return 0; 208 } 209 210 static inline 211 struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev) 212 { 213 return NULL; 214 } 215 216 static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev) 217 { 218 return 0; 219 } 220 static inline u32 l3mdev_fib_table(const struct net_device *dev) 221 { 222 return 0; 223 } 224 static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) 225 { 226 return 0; 227 } 228 229 static inline bool netif_index_is_l3_master(struct net *net, int ifindex) 230 { 231 return false; 232 } 233 234 static inline 235 struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6) 236 { 237 return NULL; 238 } 239 240 static inline 241 struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) 242 { 243 return skb; 244 } 245 246 static inline 247 struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) 248 { 249 return skb; 250 } 251 252 static inline 253 struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) 254 { 255 return skb; 256 } 257 258 static inline 259 struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) 260 { 261 return skb; 262 } 263 264 static inline 265 int l3mdev_fib_rule_match(struct net *net, struct flowi *fl, 266 struct fib_lookup_arg *arg) 267 { 268 return 1; 269 } 270 static inline 271 void l3mdev_update_flow(struct net *net, struct flowi *fl) 272 { 273 } 274 #endif 275 276 #endif /* _NET_L3MDEV_H_ */ 277