]>
Commit | Line | Data |
---|---|---|
1b69c6d0 DA |
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 | ||
a8e3e1a9 | 14 | #include <net/dst.h> |
96c63fa7 DA |
15 | #include <net/fib_rules.h> |
16 | ||
1b69c6d0 DA |
17 | /** |
18 | * struct l3mdev_ops - l3mdev operations | |
19 | * | |
20 | * @l3mdev_fib_table: Get FIB table id to use for lookups | |
21 | * | |
a8e3e1a9 DA |
22 | * @l3mdev_l3_rcv: Hook in L3 receive path |
23 | * | |
24 | * @l3mdev_l3_out: Hook in L3 output path | |
25 | * | |
1b69c6d0 | 26 | * @l3mdev_get_rtable: Get cached IPv4 rtable (dst_entry) for device |
8cbb512c DA |
27 | * |
28 | * @l3mdev_get_saddr: Get source address for a flow | |
ccf3c8c3 DA |
29 | * |
30 | * @l3mdev_get_rt6_dst: Get cached IPv6 rt6_info (dst_entry) for device | |
1b69c6d0 DA |
31 | */ |
32 | ||
33 | struct l3mdev_ops { | |
34 | u32 (*l3mdev_fib_table)(const struct net_device *dev); | |
74b20582 DA |
35 | struct sk_buff * (*l3mdev_l3_rcv)(struct net_device *dev, |
36 | struct sk_buff *skb, u16 proto); | |
a8e3e1a9 DA |
37 | struct sk_buff * (*l3mdev_l3_out)(struct net_device *dev, |
38 | struct sock *sk, struct sk_buff *skb, | |
39 | u16 proto); | |
ccf3c8c3 DA |
40 | |
41 | /* IPv4 ops */ | |
1b69c6d0 DA |
42 | struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev, |
43 | const struct flowi4 *fl4); | |
b5bdacf3 | 44 | int (*l3mdev_get_saddr)(struct net_device *dev, |
8cbb512c | 45 | struct flowi4 *fl4); |
ccf3c8c3 DA |
46 | |
47 | /* IPv6 ops */ | |
48 | struct dst_entry * (*l3mdev_get_rt6_dst)(const struct net_device *dev, | |
cd2a9e62 | 49 | struct flowi6 *fl6); |
0d240e78 DA |
50 | int (*l3mdev_get_saddr6)(struct net_device *dev, |
51 | const struct sock *sk, | |
52 | struct flowi6 *fl6); | |
1b69c6d0 DA |
53 | }; |
54 | ||
55 | #ifdef CONFIG_NET_L3_MASTER_DEV | |
56 | ||
96c63fa7 DA |
57 | int l3mdev_fib_rule_match(struct net *net, struct flowi *fl, |
58 | struct fib_lookup_arg *arg); | |
59 | ||
9ee0034b DA |
60 | void l3mdev_update_flow(struct net *net, struct flowi *fl); |
61 | ||
3f2fb9a8 | 62 | int l3mdev_master_ifindex_rcu(const struct net_device *dev); |
1b69c6d0 DA |
63 | static inline int l3mdev_master_ifindex(struct net_device *dev) |
64 | { | |
65 | int ifindex; | |
66 | ||
67 | rcu_read_lock(); | |
68 | ifindex = l3mdev_master_ifindex_rcu(dev); | |
69 | rcu_read_unlock(); | |
70 | ||
71 | return ifindex; | |
72 | } | |
73 | ||
1a852479 DA |
74 | static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) |
75 | { | |
76 | struct net_device *dev; | |
77 | int rc = 0; | |
78 | ||
79 | if (likely(ifindex)) { | |
80 | rcu_read_lock(); | |
81 | ||
82 | dev = dev_get_by_index_rcu(net, ifindex); | |
83 | if (dev) | |
84 | rc = l3mdev_master_ifindex_rcu(dev); | |
85 | ||
86 | rcu_read_unlock(); | |
87 | } | |
88 | ||
89 | return rc; | |
90 | } | |
91 | ||
afbac601 DA |
92 | static inline |
93 | const struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev) | |
94 | { | |
95 | /* netdev_master_upper_dev_get_rcu calls | |
96 | * list_first_or_null_rcu to walk the upper dev list. | |
97 | * list_first_or_null_rcu does not handle a const arg. We aren't | |
98 | * making changes, just want the master device from that list so | |
99 | * typecast to remove the const | |
100 | */ | |
101 | struct net_device *dev = (struct net_device *)_dev; | |
102 | const struct net_device *master; | |
103 | ||
104 | if (!dev) | |
105 | return NULL; | |
106 | ||
107 | if (netif_is_l3_master(dev)) | |
108 | master = dev; | |
109 | else if (netif_is_l3_slave(dev)) | |
110 | master = netdev_master_upper_dev_get_rcu(dev); | |
111 | else | |
112 | master = NULL; | |
113 | ||
114 | return master; | |
115 | } | |
116 | ||
1b69c6d0 DA |
117 | /* get index of an interface to use for FIB lookups. For devices |
118 | * enslaved to an L3 master device FIB lookups are based on the | |
119 | * master index | |
120 | */ | |
121 | static inline int l3mdev_fib_oif_rcu(struct net_device *dev) | |
122 | { | |
123 | return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex; | |
124 | } | |
125 | ||
126 | static inline int l3mdev_fib_oif(struct net_device *dev) | |
127 | { | |
128 | int oif; | |
129 | ||
130 | rcu_read_lock(); | |
131 | oif = l3mdev_fib_oif_rcu(dev); | |
132 | rcu_read_unlock(); | |
133 | ||
134 | return oif; | |
135 | } | |
136 | ||
137 | u32 l3mdev_fib_table_rcu(const struct net_device *dev); | |
138 | u32 l3mdev_fib_table_by_index(struct net *net, int ifindex); | |
139 | static inline u32 l3mdev_fib_table(const struct net_device *dev) | |
140 | { | |
141 | u32 tb_id; | |
142 | ||
143 | rcu_read_lock(); | |
144 | tb_id = l3mdev_fib_table_rcu(dev); | |
145 | rcu_read_unlock(); | |
146 | ||
147 | return tb_id; | |
148 | } | |
149 | ||
150 | static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, | |
151 | const struct flowi4 *fl4) | |
152 | { | |
153 | if (netif_is_l3_master(dev) && dev->l3mdev_ops->l3mdev_get_rtable) | |
154 | return dev->l3mdev_ops->l3mdev_get_rtable(dev, fl4); | |
155 | ||
156 | return NULL; | |
157 | } | |
158 | ||
9478d12d DA |
159 | static inline bool netif_index_is_l3_master(struct net *net, int ifindex) |
160 | { | |
161 | struct net_device *dev; | |
162 | bool rc = false; | |
163 | ||
164 | if (ifindex == 0) | |
165 | return false; | |
166 | ||
167 | rcu_read_lock(); | |
168 | ||
169 | dev = dev_get_by_index_rcu(net, ifindex); | |
170 | if (dev) | |
171 | rc = netif_is_l3_master(dev); | |
172 | ||
173 | rcu_read_unlock(); | |
174 | ||
175 | return rc; | |
176 | } | |
177 | ||
4a65896f | 178 | int l3mdev_get_saddr(struct net *net, int ifindex, struct flowi4 *fl4); |
8cbb512c | 179 | |
cd2a9e62 | 180 | struct dst_entry *l3mdev_get_rt6_dst(struct net *net, struct flowi6 *fl6); |
0d240e78 DA |
181 | int l3mdev_get_saddr6(struct net *net, const struct sock *sk, |
182 | struct flowi6 *fl6); | |
ccf3c8c3 | 183 | |
74b20582 DA |
184 | static inline |
185 | struct sk_buff *l3mdev_l3_rcv(struct sk_buff *skb, u16 proto) | |
186 | { | |
187 | struct net_device *master = NULL; | |
188 | ||
189 | if (netif_is_l3_slave(skb->dev)) | |
190 | master = netdev_master_upper_dev_get_rcu(skb->dev); | |
191 | else if (netif_is_l3_master(skb->dev)) | |
192 | master = skb->dev; | |
193 | ||
194 | if (master && master->l3mdev_ops->l3mdev_l3_rcv) | |
195 | skb = master->l3mdev_ops->l3mdev_l3_rcv(master, skb, proto); | |
196 | ||
197 | return skb; | |
198 | } | |
199 | ||
200 | static inline | |
201 | struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) | |
202 | { | |
203 | return l3mdev_l3_rcv(skb, AF_INET); | |
204 | } | |
205 | ||
206 | static inline | |
207 | struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) | |
208 | { | |
209 | return l3mdev_l3_rcv(skb, AF_INET6); | |
210 | } | |
211 | ||
a8e3e1a9 DA |
212 | static inline |
213 | struct sk_buff *l3mdev_l3_out(struct sock *sk, struct sk_buff *skb, u16 proto) | |
214 | { | |
215 | struct net_device *dev = skb_dst(skb)->dev; | |
216 | ||
217 | if (netif_is_l3_slave(dev)) { | |
218 | struct net_device *master; | |
219 | ||
220 | master = netdev_master_upper_dev_get_rcu(dev); | |
221 | if (master && master->l3mdev_ops->l3mdev_l3_out) | |
222 | skb = master->l3mdev_ops->l3mdev_l3_out(master, sk, | |
223 | skb, proto); | |
224 | } | |
225 | ||
226 | return skb; | |
227 | } | |
228 | ||
229 | static inline | |
230 | struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) | |
231 | { | |
232 | return l3mdev_l3_out(sk, skb, AF_INET); | |
233 | } | |
234 | ||
235 | static inline | |
236 | struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) | |
237 | { | |
238 | return l3mdev_l3_out(sk, skb, AF_INET6); | |
239 | } | |
1b69c6d0 DA |
240 | #else |
241 | ||
3f2fb9a8 | 242 | static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev) |
1b69c6d0 DA |
243 | { |
244 | return 0; | |
245 | } | |
246 | static inline int l3mdev_master_ifindex(struct net_device *dev) | |
247 | { | |
248 | return 0; | |
249 | } | |
250 | ||
1a852479 DA |
251 | static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) |
252 | { | |
253 | return 0; | |
254 | } | |
255 | ||
afbac601 DA |
256 | static inline |
257 | const struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev) | |
258 | { | |
259 | return NULL; | |
260 | } | |
261 | ||
1b69c6d0 DA |
262 | static inline int l3mdev_fib_oif_rcu(struct net_device *dev) |
263 | { | |
264 | return dev ? dev->ifindex : 0; | |
265 | } | |
266 | static inline int l3mdev_fib_oif(struct net_device *dev) | |
267 | { | |
268 | return dev ? dev->ifindex : 0; | |
269 | } | |
270 | ||
271 | static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev) | |
272 | { | |
273 | return 0; | |
274 | } | |
275 | static inline u32 l3mdev_fib_table(const struct net_device *dev) | |
276 | { | |
277 | return 0; | |
278 | } | |
279 | static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) | |
280 | { | |
281 | return 0; | |
282 | } | |
283 | ||
284 | static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev, | |
285 | const struct flowi4 *fl4) | |
286 | { | |
287 | return NULL; | |
288 | } | |
289 | ||
9478d12d DA |
290 | static inline bool netif_index_is_l3_master(struct net *net, int ifindex) |
291 | { | |
292 | return false; | |
293 | } | |
294 | ||
b5bdacf3 DA |
295 | static inline int l3mdev_get_saddr(struct net *net, int ifindex, |
296 | struct flowi4 *fl4) | |
8cbb512c | 297 | { |
b5bdacf3 | 298 | return 0; |
8cbb512c | 299 | } |
ccf3c8c3 DA |
300 | |
301 | static inline | |
cd2a9e62 | 302 | struct dst_entry *l3mdev_get_rt6_dst(struct net *net, struct flowi6 *fl6) |
ccf3c8c3 DA |
303 | { |
304 | return NULL; | |
305 | } | |
74b20582 | 306 | |
0d240e78 DA |
307 | static inline int l3mdev_get_saddr6(struct net *net, const struct sock *sk, |
308 | struct flowi6 *fl6) | |
309 | { | |
310 | return 0; | |
311 | } | |
312 | ||
74b20582 DA |
313 | static inline |
314 | struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) | |
315 | { | |
316 | return skb; | |
317 | } | |
318 | ||
319 | static inline | |
320 | struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) | |
321 | { | |
322 | return skb; | |
323 | } | |
96c63fa7 | 324 | |
a8e3e1a9 DA |
325 | static inline |
326 | struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) | |
327 | { | |
328 | return skb; | |
329 | } | |
330 | ||
331 | static inline | |
332 | struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) | |
333 | { | |
334 | return skb; | |
335 | } | |
336 | ||
96c63fa7 DA |
337 | static inline |
338 | int l3mdev_fib_rule_match(struct net *net, struct flowi *fl, | |
339 | struct fib_lookup_arg *arg) | |
340 | { | |
341 | return 1; | |
342 | } | |
9ee0034b DA |
343 | static inline |
344 | void l3mdev_update_flow(struct net *net, struct flowi *fl) | |
345 | { | |
346 | } | |
1b69c6d0 DA |
347 | #endif |
348 | ||
349 | #endif /* _NET_L3MDEV_H_ */ |