]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - include/net/l3mdev.h
net: l3mdev: Add hook to output path
[mirror_ubuntu-bionic-kernel.git] / include / net / l3mdev.h
CommitLineData
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
33struct 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
57int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
58 struct fib_lookup_arg *arg);
59
9ee0034b
DA
60void l3mdev_update_flow(struct net *net, struct flowi *fl);
61
3f2fb9a8 62int l3mdev_master_ifindex_rcu(const struct net_device *dev);
1b69c6d0
DA
63static 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
74static 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
92static inline
93const 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 */
121static inline int l3mdev_fib_oif_rcu(struct net_device *dev)
122{
123 return l3mdev_master_ifindex_rcu(dev) ? : dev->ifindex;
124}
125
126static 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
137u32 l3mdev_fib_table_rcu(const struct net_device *dev);
138u32 l3mdev_fib_table_by_index(struct net *net, int ifindex);
139static 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
150static 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
159static 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 178int l3mdev_get_saddr(struct net *net, int ifindex, struct flowi4 *fl4);
8cbb512c 179
cd2a9e62 180struct dst_entry *l3mdev_get_rt6_dst(struct net *net, struct flowi6 *fl6);
0d240e78
DA
181int l3mdev_get_saddr6(struct net *net, const struct sock *sk,
182 struct flowi6 *fl6);
ccf3c8c3 183
74b20582
DA
184static inline
185struct 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
200static inline
201struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb)
202{
203 return l3mdev_l3_rcv(skb, AF_INET);
204}
205
206static inline
207struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb)
208{
209 return l3mdev_l3_rcv(skb, AF_INET6);
210}
211
a8e3e1a9
DA
212static inline
213struct 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
229static inline
230struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb)
231{
232 return l3mdev_l3_out(sk, skb, AF_INET);
233}
234
235static inline
236struct 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 242static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev)
1b69c6d0
DA
243{
244 return 0;
245}
246static inline int l3mdev_master_ifindex(struct net_device *dev)
247{
248 return 0;
249}
250
1a852479
DA
251static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
252{
253 return 0;
254}
255
afbac601
DA
256static inline
257const struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev)
258{
259 return NULL;
260}
261
1b69c6d0
DA
262static inline int l3mdev_fib_oif_rcu(struct net_device *dev)
263{
264 return dev ? dev->ifindex : 0;
265}
266static inline int l3mdev_fib_oif(struct net_device *dev)
267{
268 return dev ? dev->ifindex : 0;
269}
270
271static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev)
272{
273 return 0;
274}
275static inline u32 l3mdev_fib_table(const struct net_device *dev)
276{
277 return 0;
278}
279static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex)
280{
281 return 0;
282}
283
284static inline struct rtable *l3mdev_get_rtable(const struct net_device *dev,
285 const struct flowi4 *fl4)
286{
287 return NULL;
288}
289
9478d12d
DA
290static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
291{
292 return false;
293}
294
b5bdacf3
DA
295static 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
301static inline
cd2a9e62 302struct dst_entry *l3mdev_get_rt6_dst(struct net *net, struct flowi6 *fl6)
ccf3c8c3
DA
303{
304 return NULL;
305}
74b20582 306
0d240e78
DA
307static inline int l3mdev_get_saddr6(struct net *net, const struct sock *sk,
308 struct flowi6 *fl6)
309{
310 return 0;
311}
312
74b20582
DA
313static inline
314struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb)
315{
316 return skb;
317}
318
319static inline
320struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb)
321{
322 return skb;
323}
96c63fa7 324
a8e3e1a9
DA
325static inline
326struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb)
327{
328 return skb;
329}
330
331static inline
332struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb)
333{
334 return skb;
335}
336
96c63fa7
DA
337static inline
338int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
339 struct fib_lookup_arg *arg)
340{
341 return 1;
342}
9ee0034b
DA
343static inline
344void l3mdev_update_flow(struct net *net, struct flowi *fl)
345{
346}
1b69c6d0
DA
347#endif
348
349#endif /* _NET_L3MDEV_H_ */