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