Branch data 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 : : /**
14 : : * struct l3mdev_ops - l3mdev operations
15 : : *
16 : : * @l3mdev_fib_table: Get FIB table id to use for lookups
17 : : *
18 : : * @l3mdev_l3_rcv: Hook in L3 receive path
19 : : *
20 : : * @l3mdev_l3_out: Hook in L3 output path
21 : : *
22 : : * @l3mdev_link_scope_lookup: IPv6 lookup for linklocal and mcast destinations
23 : : */
24 : :
25 : : struct l3mdev_ops {
26 : : u32 (*l3mdev_fib_table)(const struct net_device *dev);
27 : : struct sk_buff * (*l3mdev_l3_rcv)(struct net_device *dev,
28 : : struct sk_buff *skb, u16 proto);
29 : : struct sk_buff * (*l3mdev_l3_out)(struct net_device *dev,
30 : : struct sock *sk, struct sk_buff *skb,
31 : : u16 proto);
32 : :
33 : : /* IPv6 ops */
34 : : struct dst_entry * (*l3mdev_link_scope_lookup)(const struct net_device *dev,
35 : : struct flowi6 *fl6);
36 : : };
37 : :
38 : : #ifdef CONFIG_NET_L3_MASTER_DEV
39 : :
40 : : int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
41 : : struct fib_lookup_arg *arg);
42 : :
43 : : void l3mdev_update_flow(struct net *net, struct flowi *fl);
44 : :
45 : : int l3mdev_master_ifindex_rcu(const struct net_device *dev);
46 : : static inline int l3mdev_master_ifindex(struct net_device *dev)
47 : : {
48 : : int ifindex;
49 : :
50 : : rcu_read_lock();
51 : 1656 : ifindex = l3mdev_master_ifindex_rcu(dev);
52 : : rcu_read_unlock();
53 : :
54 : : return ifindex;
55 : : }
56 : :
57 : 0 : static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
58 : : {
59 : : struct net_device *dev;
60 : : int rc = 0;
61 : :
62 [ # # ]: 0 : if (likely(ifindex)) {
63 : : rcu_read_lock();
64 : :
65 : 0 : dev = dev_get_by_index_rcu(net, ifindex);
66 [ # # ]: 0 : if (dev)
67 : 0 : rc = l3mdev_master_ifindex_rcu(dev);
68 : :
69 : : rcu_read_unlock();
70 : : }
71 : :
72 : 0 : return rc;
73 : : }
74 : :
75 : : static inline
76 : 6841 : struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev)
77 : : {
78 : : /* netdev_master_upper_dev_get_rcu calls
79 : : * list_first_or_null_rcu to walk the upper dev list.
80 : : * list_first_or_null_rcu does not handle a const arg. We aren't
81 : : * making changes, just want the master device from that list so
82 : : * typecast to remove the const
83 : : */
84 : : struct net_device *dev = (struct net_device *)_dev;
85 : : struct net_device *master;
86 : :
87 [ + + ]: 6841 : if (!dev)
88 : : return NULL;
89 : :
90 [ + - ]: 6013 : if (netif_is_l3_master(dev))
91 : : master = dev;
92 [ - + ]: 6013 : else if (netif_is_l3_slave(dev))
93 : 0 : master = netdev_master_upper_dev_get_rcu(dev);
94 : : else
95 : : master = NULL;
96 : :
97 : 6013 : return master;
98 : : }
99 : :
100 : : int l3mdev_master_upper_ifindex_by_index_rcu(struct net *net, int ifindex);
101 : : static inline
102 : : int l3mdev_master_upper_ifindex_by_index(struct net *net, int ifindex)
103 : : {
104 : : rcu_read_lock();
105 : : ifindex = l3mdev_master_upper_ifindex_by_index_rcu(net, ifindex);
106 : : rcu_read_unlock();
107 : :
108 : : return ifindex;
109 : : }
110 : :
111 : : u32 l3mdev_fib_table_rcu(const struct net_device *dev);
112 : : u32 l3mdev_fib_table_by_index(struct net *net, int ifindex);
113 : : static inline u32 l3mdev_fib_table(const struct net_device *dev)
114 : : {
115 : : u32 tb_id;
116 : :
117 : : rcu_read_lock();
118 : 5811 : tb_id = l3mdev_fib_table_rcu(dev);
119 : : rcu_read_unlock();
120 : :
121 : : return tb_id;
122 : : }
123 : :
124 : 1264 : static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
125 : : {
126 : : struct net_device *dev;
127 : : bool rc = false;
128 : :
129 [ + - ]: 1264 : if (ifindex == 0)
130 : : return false;
131 : :
132 : : rcu_read_lock();
133 : :
134 : 1264 : dev = dev_get_by_index_rcu(net, ifindex);
135 [ + - ]: 1264 : if (dev)
136 : : rc = netif_is_l3_master(dev);
137 : :
138 : : rcu_read_unlock();
139 : :
140 : 1264 : return rc;
141 : : }
142 : :
143 : : struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6);
144 : :
145 : : static inline
146 : 6998 : struct sk_buff *l3mdev_l3_rcv(struct sk_buff *skb, u16 proto)
147 : : {
148 : : struct net_device *master = NULL;
149 : :
150 [ - + ]: 13996 : if (netif_is_l3_slave(skb->dev))
151 : 0 : master = netdev_master_upper_dev_get_rcu(skb->dev);
152 [ + - - + ]: 13996 : else if (netif_is_l3_master(skb->dev) ||
153 : : netif_has_l3_rx_handler(skb->dev))
154 : : master = skb->dev;
155 : :
156 [ - + # # ]: 6998 : if (master && master->l3mdev_ops->l3mdev_l3_rcv)
157 : 0 : skb = master->l3mdev_ops->l3mdev_l3_rcv(master, skb, proto);
158 : :
159 : 6998 : return skb;
160 : : }
161 : :
162 : : static inline
163 : : struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb)
164 : : {
165 : 6048 : return l3mdev_l3_rcv(skb, AF_INET);
166 : : }
167 : :
168 : : static inline
169 : : struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb)
170 : : {
171 : 950 : return l3mdev_l3_rcv(skb, AF_INET6);
172 : : }
173 : :
174 : : static inline
175 : 4616 : struct sk_buff *l3mdev_l3_out(struct sock *sk, struct sk_buff *skb, u16 proto)
176 : : {
177 : 4616 : struct net_device *dev = skb_dst(skb)->dev;
178 : :
179 [ - + ]: 4616 : if (netif_is_l3_slave(dev)) {
180 : : struct net_device *master;
181 : :
182 : 0 : master = netdev_master_upper_dev_get_rcu(dev);
183 [ # # # # ]: 0 : if (master && master->l3mdev_ops->l3mdev_l3_out)
184 : 0 : skb = master->l3mdev_ops->l3mdev_l3_out(master, sk,
185 : : skb, proto);
186 : : }
187 : :
188 : 4616 : return skb;
189 : : }
190 : :
191 : : static inline
192 : : struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb)
193 : : {
194 : 3397 : return l3mdev_l3_out(sk, skb, AF_INET);
195 : : }
196 : :
197 : : static inline
198 : : struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb)
199 : : {
200 : 1219 : return l3mdev_l3_out(sk, skb, AF_INET6);
201 : : }
202 : : #else
203 : :
204 : : static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev)
205 : : {
206 : : return 0;
207 : : }
208 : : static inline int l3mdev_master_ifindex(struct net_device *dev)
209 : : {
210 : : return 0;
211 : : }
212 : :
213 : : static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex)
214 : : {
215 : : return 0;
216 : : }
217 : :
218 : : static inline
219 : : int l3mdev_master_upper_ifindex_by_index_rcu(struct net *net, int ifindex)
220 : : {
221 : : return 0;
222 : : }
223 : : static inline
224 : : int l3mdev_master_upper_ifindex_by_index(struct net *net, int ifindex)
225 : : {
226 : : return 0;
227 : : }
228 : :
229 : : static inline
230 : : struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev)
231 : : {
232 : : return NULL;
233 : : }
234 : :
235 : : static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev)
236 : : {
237 : : return 0;
238 : : }
239 : : static inline u32 l3mdev_fib_table(const struct net_device *dev)
240 : : {
241 : : return 0;
242 : : }
243 : : static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex)
244 : : {
245 : : return 0;
246 : : }
247 : :
248 : : static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
249 : : {
250 : : return false;
251 : : }
252 : :
253 : : static inline
254 : : struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6)
255 : : {
256 : : return NULL;
257 : : }
258 : :
259 : : static inline
260 : : struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb)
261 : : {
262 : : return skb;
263 : : }
264 : :
265 : : static inline
266 : : struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb)
267 : : {
268 : : return skb;
269 : : }
270 : :
271 : : static inline
272 : : struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb)
273 : : {
274 : : return skb;
275 : : }
276 : :
277 : : static inline
278 : : struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb)
279 : : {
280 : : return skb;
281 : : }
282 : :
283 : : static inline
284 : : int l3mdev_fib_rule_match(struct net *net, struct flowi *fl,
285 : : struct fib_lookup_arg *arg)
286 : : {
287 : : return 1;
288 : : }
289 : : static inline
290 : : void l3mdev_update_flow(struct net *net, struct flowi *fl)
291 : : {
292 : : }
293 : : #endif
294 : :
295 : : #endif /* _NET_L3MDEV_H_ */
|