blob: 53d5274920e3ac37d71a5e462d54fd5b8f745d85 [file] [log] [blame]
David Ahern1b69c6d2015-09-29 20:07:11 -07001/*
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
David Aherna8e3e1a2016-09-10 12:09:53 -070014#include <net/dst.h>
David Ahern96c63fa2016-06-08 10:55:39 -070015#include <net/fib_rules.h>
16
David Ahern1b69c6d2015-09-29 20:07:11 -070017/**
18 * struct l3mdev_ops - l3mdev operations
19 *
20 * @l3mdev_fib_table: Get FIB table id to use for lookups
21 *
David Aherna8e3e1a2016-09-10 12:09:53 -070022 * @l3mdev_l3_rcv: Hook in L3 receive path
23 *
24 * @l3mdev_l3_out: Hook in L3 output path
25 *
David Ahern1b69c6d2015-09-29 20:07:11 -070026 * @l3mdev_get_rtable: Get cached IPv4 rtable (dst_entry) for device
David Ahern8cbb512c2015-10-05 08:51:26 -070027 *
28 * @l3mdev_get_saddr: Get source address for a flow
David Ahernccf3c8c2015-10-12 11:47:07 -070029 *
30 * @l3mdev_get_rt6_dst: Get cached IPv6 rt6_info (dst_entry) for device
David Ahern1b69c6d2015-09-29 20:07:11 -070031 */
32
33struct l3mdev_ops {
34 u32 (*l3mdev_fib_table)(const struct net_device *dev);
David Ahern74b20582016-05-10 11:19:50 -070035 struct sk_buff * (*l3mdev_l3_rcv)(struct net_device *dev,
36 struct sk_buff *skb, u16 proto);
David Aherna8e3e1a2016-09-10 12:09:53 -070037 struct sk_buff * (*l3mdev_l3_out)(struct net_device *dev,
38 struct sock *sk, struct sk_buff *skb,
39 u16 proto);
David Ahernccf3c8c2015-10-12 11:47:07 -070040
41 /* IPv4 ops */
David Ahern1b69c6d2015-09-29 20:07:11 -070042 struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev,
43 const struct flowi4 *fl4);
David Ahernb5bdacf2016-01-04 09:09:27 -080044 int (*l3mdev_get_saddr)(struct net_device *dev,
David Ahern8cbb512c2015-10-05 08:51:26 -070045 struct flowi4 *fl4);
David Ahernccf3c8c2015-10-12 11:47:07 -070046
47 /* IPv6 ops */
48 struct dst_entry * (*l3mdev_get_rt6_dst)(const struct net_device *dev,
David Aherncd2a9e62016-06-13 13:44:17 -070049 struct flowi6 *fl6);
David Ahern0d240e72016-06-16 16:24:25 -070050 int (*l3mdev_get_saddr6)(struct net_device *dev,
51 const struct sock *sk,
52 struct flowi6 *fl6);
David Ahern1b69c6d2015-09-29 20:07:11 -070053};
54
55#ifdef CONFIG_NET_L3_MASTER_DEV
56
David Ahern96c63fa2016-06-08 10:55:39 -070057int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
58 struct fib_lookup_arg *arg);
59
David Ahern9ee00342016-09-10 12:09:52 -070060void l3mdev_update_flow(struct net *net, struct flowi *fl);
61
David Ahern3f2fb9a2016-02-24 11:47:02 -080062int l3mdev_master_ifindex_rcu(const struct net_device *dev);
David Ahern1b69c6d2015-09-29 20:07:11 -070063static 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
David Ahern1a852472015-12-16 13:20:43 -080074static 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
David Ahernafbac6012016-06-16 16:24:26 -070092static 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
David Ahern1b69c6d2015-09-29 20:07:11 -0700117/* 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
David Ahern9478d122015-09-29 20:07:18 -0700159static 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
David Ahern4a658962016-05-07 16:48:59 -0700178int l3mdev_get_saddr(struct net *net, int ifindex, struct flowi4 *fl4);
David Ahern8cbb512c2015-10-05 08:51:26 -0700179
David Aherncd2a9e62016-06-13 13:44:17 -0700180struct dst_entry *l3mdev_get_rt6_dst(struct net *net, struct flowi6 *fl6);
David Ahern0d240e72016-06-16 16:24:25 -0700181int l3mdev_get_saddr6(struct net *net, const struct sock *sk,
182 struct flowi6 *fl6);
David Ahernccf3c8c2015-10-12 11:47:07 -0700183
David Ahern74b20582016-05-10 11:19:50 -0700184static 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
David Aherna8e3e1a2016-09-10 12:09:53 -0700212static 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}
David Ahern1b69c6d2015-09-29 20:07:11 -0700240#else
241
David Ahern3f2fb9a2016-02-24 11:47:02 -0800242static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev)
David Ahern1b69c6d2015-09-29 20:07:11 -0700243{
244 return 0;
245}
246static inline int l3mdev_master_ifindex(struct net_device *dev)
247{
248 return 0;
249}
250
David Ahern1a852472015-12-16 13:20:43 -0800251static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
252{
253 return 0;
254}
255
David Ahernafbac6012016-06-16 16:24:26 -0700256static inline
257const struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev)
258{
259 return NULL;
260}
261
David Ahern1b69c6d2015-09-29 20:07:11 -0700262static 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
David Ahern9478d122015-09-29 20:07:18 -0700290static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
291{
292 return false;
293}
294
David Ahernb5bdacf2016-01-04 09:09:27 -0800295static inline int l3mdev_get_saddr(struct net *net, int ifindex,
296 struct flowi4 *fl4)
David Ahern8cbb512c2015-10-05 08:51:26 -0700297{
David Ahernb5bdacf2016-01-04 09:09:27 -0800298 return 0;
David Ahern8cbb512c2015-10-05 08:51:26 -0700299}
David Ahernccf3c8c2015-10-12 11:47:07 -0700300
301static inline
David Aherncd2a9e62016-06-13 13:44:17 -0700302struct dst_entry *l3mdev_get_rt6_dst(struct net *net, struct flowi6 *fl6)
David Ahernccf3c8c2015-10-12 11:47:07 -0700303{
304 return NULL;
305}
David Ahern74b20582016-05-10 11:19:50 -0700306
David Ahern0d240e72016-06-16 16:24:25 -0700307static inline int l3mdev_get_saddr6(struct net *net, const struct sock *sk,
308 struct flowi6 *fl6)
309{
310 return 0;
311}
312
David Ahern74b20582016-05-10 11:19:50 -0700313static 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}
David Ahern96c63fa2016-06-08 10:55:39 -0700324
325static inline
David Aherna8e3e1a2016-09-10 12:09:53 -0700326struct 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
337static inline
David Ahern96c63fa2016-06-08 10:55:39 -0700338int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
339 struct fib_lookup_arg *arg)
340{
341 return 1;
342}
David Ahern9ee00342016-09-10 12:09:52 -0700343static inline
344void l3mdev_update_flow(struct net *net, struct flowi *fl)
345{
346}
David Ahern1b69c6d2015-09-29 20:07:11 -0700347#endif
348
349#endif /* _NET_L3MDEV_H_ */