hc
2024-05-10 ee930fffee469d076998274a2ca55e13dc1efb67
kernel/include/net/nexthop.h
....@@ -1,34 +1,465 @@
11 /* SPDX-License-Identifier: GPL-2.0 */
2
-#ifndef __NET_NEXTHOP_H
3
-#define __NET_NEXTHOP_H
2
+/*
3
+ * Generic nexthop implementation
4
+ *
5
+ * Copyright (c) 2017-19 Cumulus Networks
6
+ * Copyright (c) 2017-19 David Ahern <dsa@cumulusnetworks.com>
7
+ */
48
5
-#include <linux/rtnetlink.h>
9
+#ifndef __LINUX_NEXTHOP_H
10
+#define __LINUX_NEXTHOP_H
11
+
12
+#include <linux/netdevice.h>
13
+#include <linux/notifier.h>
14
+#include <linux/route.h>
15
+#include <linux/types.h>
16
+#include <net/ip_fib.h>
17
+#include <net/ip6_fib.h>
618 #include <net/netlink.h>
719
8
-static inline int rtnh_ok(const struct rtnexthop *rtnh, int remaining)
20
+#define NEXTHOP_VALID_USER_FLAGS RTNH_F_ONLINK
21
+
22
+struct nexthop;
23
+
24
+struct nh_config {
25
+ u32 nh_id;
26
+
27
+ u8 nh_family;
28
+ u8 nh_protocol;
29
+ u8 nh_blackhole;
30
+ u8 nh_fdb;
31
+ u32 nh_flags;
32
+
33
+ int nh_ifindex;
34
+ struct net_device *dev;
35
+
36
+ union {
37
+ __be32 ipv4;
38
+ struct in6_addr ipv6;
39
+ } gw;
40
+
41
+ struct nlattr *nh_grp;
42
+ u16 nh_grp_type;
43
+
44
+ struct nlattr *nh_encap;
45
+ u16 nh_encap_type;
46
+
47
+ u32 nlflags;
48
+ struct nl_info nlinfo;
49
+};
50
+
51
+struct nh_info {
52
+ struct hlist_node dev_hash; /* entry on netns devhash */
53
+ struct nexthop *nh_parent;
54
+
55
+ u8 family;
56
+ bool reject_nh;
57
+ bool fdb_nh;
58
+
59
+ union {
60
+ struct fib_nh_common fib_nhc;
61
+ struct fib_nh fib_nh;
62
+ struct fib6_nh fib6_nh;
63
+ };
64
+};
65
+
66
+struct nh_grp_entry {
67
+ struct nexthop *nh;
68
+ u8 weight;
69
+ atomic_t upper_bound;
70
+
71
+ struct list_head nh_list;
72
+ struct nexthop *nh_parent; /* nexthop of group with this entry */
73
+};
74
+
75
+struct nh_group {
76
+ struct nh_group *spare; /* spare group for removals */
77
+ u16 num_nh;
78
+ bool mpath;
79
+ bool fdb_nh;
80
+ bool has_v4;
81
+ struct nh_grp_entry nh_entries[];
82
+};
83
+
84
+struct nexthop {
85
+ struct rb_node rb_node; /* entry on netns rbtree */
86
+ struct list_head fi_list; /* v4 entries using nh */
87
+ struct list_head f6i_list; /* v6 entries using nh */
88
+ struct list_head fdb_list; /* fdb entries using this nh */
89
+ struct list_head grp_list; /* nh group entries using this nh */
90
+ struct net *net;
91
+
92
+ u32 id;
93
+
94
+ u8 protocol; /* app managing this nh */
95
+ u8 nh_flags;
96
+ bool is_group;
97
+
98
+ refcount_t refcnt;
99
+ struct rcu_head rcu;
100
+
101
+ union {
102
+ struct nh_info __rcu *nh_info;
103
+ struct nh_group __rcu *nh_grp;
104
+ };
105
+};
106
+
107
+enum nexthop_event_type {
108
+ NEXTHOP_EVENT_DEL
109
+};
110
+
111
+int register_nexthop_notifier(struct net *net, struct notifier_block *nb);
112
+int unregister_nexthop_notifier(struct net *net, struct notifier_block *nb);
113
+
114
+/* caller is holding rcu or rtnl; no reference taken to nexthop */
115
+struct nexthop *nexthop_find_by_id(struct net *net, u32 id);
116
+void nexthop_free_rcu(struct rcu_head *head);
117
+
118
+static inline bool nexthop_get(struct nexthop *nh)
9119 {
10
- return remaining >= (int)sizeof(*rtnh) &&
11
- rtnh->rtnh_len >= sizeof(*rtnh) &&
12
- rtnh->rtnh_len <= remaining;
120
+ return refcount_inc_not_zero(&nh->refcnt);
13121 }
14122
15
-static inline struct rtnexthop *rtnh_next(const struct rtnexthop *rtnh,
16
- int *remaining)
123
+static inline void nexthop_put(struct nexthop *nh)
17124 {
18
- int totlen = NLA_ALIGN(rtnh->rtnh_len);
19
-
20
- *remaining -= totlen;
21
- return (struct rtnexthop *) ((char *) rtnh + totlen);
125
+ if (refcount_dec_and_test(&nh->refcnt))
126
+ call_rcu(&nh->rcu, nexthop_free_rcu);
22127 }
23128
24
-static inline struct nlattr *rtnh_attrs(const struct rtnexthop *rtnh)
129
+static inline bool nexthop_cmp(const struct nexthop *nh1,
130
+ const struct nexthop *nh2)
25131 {
26
- return (struct nlattr *) ((char *) rtnh + NLA_ALIGN(sizeof(*rtnh)));
132
+ return nh1 == nh2;
27133 }
28134
29
-static inline int rtnh_attrlen(const struct rtnexthop *rtnh)
135
+static inline bool nexthop_is_fdb(const struct nexthop *nh)
30136 {
31
- return rtnh->rtnh_len - NLA_ALIGN(sizeof(*rtnh));
137
+ if (nh->is_group) {
138
+ const struct nh_group *nh_grp;
139
+
140
+ nh_grp = rcu_dereference_rtnl(nh->nh_grp);
141
+ return nh_grp->fdb_nh;
142
+ } else {
143
+ const struct nh_info *nhi;
144
+
145
+ nhi = rcu_dereference_rtnl(nh->nh_info);
146
+ return nhi->fdb_nh;
147
+ }
32148 }
33149
150
+static inline bool nexthop_has_v4(const struct nexthop *nh)
151
+{
152
+ if (nh->is_group) {
153
+ struct nh_group *nh_grp;
154
+
155
+ nh_grp = rcu_dereference_rtnl(nh->nh_grp);
156
+ return nh_grp->has_v4;
157
+ }
158
+ return false;
159
+}
160
+
161
+static inline bool nexthop_is_multipath(const struct nexthop *nh)
162
+{
163
+ if (nh->is_group) {
164
+ struct nh_group *nh_grp;
165
+
166
+ nh_grp = rcu_dereference_rtnl(nh->nh_grp);
167
+ return nh_grp->mpath;
168
+ }
169
+ return false;
170
+}
171
+
172
+struct nexthop *nexthop_select_path(struct nexthop *nh, int hash);
173
+
174
+static inline unsigned int nexthop_num_path(const struct nexthop *nh)
175
+{
176
+ unsigned int rc = 1;
177
+
178
+ if (nh->is_group) {
179
+ struct nh_group *nh_grp;
180
+
181
+ nh_grp = rcu_dereference_rtnl(nh->nh_grp);
182
+ if (nh_grp->mpath)
183
+ rc = nh_grp->num_nh;
184
+ }
185
+
186
+ return rc;
187
+}
188
+
189
+static inline
190
+struct nexthop *nexthop_mpath_select(const struct nh_group *nhg, int nhsel)
191
+{
192
+ /* for_nexthops macros in fib_semantics.c grabs a pointer to
193
+ * the nexthop before checking nhsel
194
+ */
195
+ if (nhsel >= nhg->num_nh)
196
+ return NULL;
197
+
198
+ return nhg->nh_entries[nhsel].nh;
199
+}
200
+
201
+static inline
202
+int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh,
203
+ u8 rt_family)
204
+{
205
+ struct nh_group *nhg = rtnl_dereference(nh->nh_grp);
206
+ int i;
207
+
208
+ for (i = 0; i < nhg->num_nh; i++) {
209
+ struct nexthop *nhe = nhg->nh_entries[i].nh;
210
+ struct nh_info *nhi = rcu_dereference_rtnl(nhe->nh_info);
211
+ struct fib_nh_common *nhc = &nhi->fib_nhc;
212
+ int weight = nhg->nh_entries[i].weight;
213
+
214
+ if (fib_add_nexthop(skb, nhc, weight, rt_family, 0) < 0)
215
+ return -EMSGSIZE;
216
+ }
217
+
218
+ return 0;
219
+}
220
+
221
+/* called with rcu lock */
222
+static inline bool nexthop_is_blackhole(const struct nexthop *nh)
223
+{
224
+ const struct nh_info *nhi;
225
+
226
+ if (nh->is_group) {
227
+ struct nh_group *nh_grp;
228
+
229
+ nh_grp = rcu_dereference_rtnl(nh->nh_grp);
230
+ if (nh_grp->num_nh > 1)
231
+ return false;
232
+
233
+ nh = nh_grp->nh_entries[0].nh;
234
+ }
235
+
236
+ nhi = rcu_dereference_rtnl(nh->nh_info);
237
+ return nhi->reject_nh;
238
+}
239
+
240
+static inline void nexthop_path_fib_result(struct fib_result *res, int hash)
241
+{
242
+ struct nh_info *nhi;
243
+ struct nexthop *nh;
244
+
245
+ nh = nexthop_select_path(res->fi->nh, hash);
246
+ nhi = rcu_dereference(nh->nh_info);
247
+ res->nhc = &nhi->fib_nhc;
248
+}
249
+
250
+/* called with rcu read lock or rtnl held */
251
+static inline
252
+struct fib_nh_common *nexthop_fib_nhc(struct nexthop *nh, int nhsel)
253
+{
254
+ struct nh_info *nhi;
255
+
256
+ BUILD_BUG_ON(offsetof(struct fib_nh, nh_common) != 0);
257
+ BUILD_BUG_ON(offsetof(struct fib6_nh, nh_common) != 0);
258
+
259
+ if (nh->is_group) {
260
+ struct nh_group *nh_grp;
261
+
262
+ nh_grp = rcu_dereference_rtnl(nh->nh_grp);
263
+ if (nh_grp->mpath) {
264
+ nh = nexthop_mpath_select(nh_grp, nhsel);
265
+ if (!nh)
266
+ return NULL;
267
+ }
268
+ }
269
+
270
+ nhi = rcu_dereference_rtnl(nh->nh_info);
271
+ return &nhi->fib_nhc;
272
+}
273
+
274
+/* called from fib_table_lookup with rcu_lock */
275
+static inline
276
+struct fib_nh_common *nexthop_get_nhc_lookup(const struct nexthop *nh,
277
+ int fib_flags,
278
+ const struct flowi4 *flp,
279
+ int *nhsel)
280
+{
281
+ struct nh_info *nhi;
282
+
283
+ if (nh->is_group) {
284
+ struct nh_group *nhg = rcu_dereference(nh->nh_grp);
285
+ int i;
286
+
287
+ for (i = 0; i < nhg->num_nh; i++) {
288
+ struct nexthop *nhe = nhg->nh_entries[i].nh;
289
+
290
+ nhi = rcu_dereference(nhe->nh_info);
291
+ if (fib_lookup_good_nhc(&nhi->fib_nhc, fib_flags, flp)) {
292
+ *nhsel = i;
293
+ return &nhi->fib_nhc;
294
+ }
295
+ }
296
+ } else {
297
+ nhi = rcu_dereference(nh->nh_info);
298
+ if (fib_lookup_good_nhc(&nhi->fib_nhc, fib_flags, flp)) {
299
+ *nhsel = 0;
300
+ return &nhi->fib_nhc;
301
+ }
302
+ }
303
+
304
+ return NULL;
305
+}
306
+
307
+static inline bool nexthop_uses_dev(const struct nexthop *nh,
308
+ const struct net_device *dev)
309
+{
310
+ struct nh_info *nhi;
311
+
312
+ if (nh->is_group) {
313
+ struct nh_group *nhg = rcu_dereference(nh->nh_grp);
314
+ int i;
315
+
316
+ for (i = 0; i < nhg->num_nh; i++) {
317
+ struct nexthop *nhe = nhg->nh_entries[i].nh;
318
+
319
+ nhi = rcu_dereference(nhe->nh_info);
320
+ if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev))
321
+ return true;
322
+ }
323
+ } else {
324
+ nhi = rcu_dereference(nh->nh_info);
325
+ if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev))
326
+ return true;
327
+ }
328
+
329
+ return false;
330
+}
331
+
332
+static inline unsigned int fib_info_num_path(const struct fib_info *fi)
333
+{
334
+ if (unlikely(fi->nh))
335
+ return nexthop_num_path(fi->nh);
336
+
337
+ return fi->fib_nhs;
338
+}
339
+
340
+int fib_check_nexthop(struct nexthop *nh, u8 scope,
341
+ struct netlink_ext_ack *extack);
342
+
343
+static inline struct fib_nh_common *fib_info_nhc(struct fib_info *fi, int nhsel)
344
+{
345
+ if (unlikely(fi->nh))
346
+ return nexthop_fib_nhc(fi->nh, nhsel);
347
+
348
+ return &fi->fib_nh[nhsel].nh_common;
349
+}
350
+
351
+/* only used when fib_nh is built into fib_info */
352
+static inline struct fib_nh *fib_info_nh(struct fib_info *fi, int nhsel)
353
+{
354
+ WARN_ON(fi->nh);
355
+
356
+ return &fi->fib_nh[nhsel];
357
+}
358
+
359
+/*
360
+ * IPv6 variants
361
+ */
362
+int fib6_check_nexthop(struct nexthop *nh, struct fib6_config *cfg,
363
+ struct netlink_ext_ack *extack);
364
+
365
+/* Caller should either hold rcu_read_lock(), or RTNL. */
366
+static inline struct fib6_nh *nexthop_fib6_nh(struct nexthop *nh)
367
+{
368
+ struct nh_info *nhi;
369
+
370
+ if (nh->is_group) {
371
+ struct nh_group *nh_grp;
372
+
373
+ nh_grp = rcu_dereference_rtnl(nh->nh_grp);
374
+ nh = nexthop_mpath_select(nh_grp, 0);
375
+ if (!nh)
376
+ return NULL;
377
+ }
378
+
379
+ nhi = rcu_dereference_rtnl(nh->nh_info);
380
+ if (nhi->family == AF_INET6)
381
+ return &nhi->fib6_nh;
382
+
383
+ return NULL;
384
+}
385
+
386
+/* Variant of nexthop_fib6_nh().
387
+ * Caller should either hold rcu_read_lock_bh(), or RTNL.
388
+ */
389
+static inline struct fib6_nh *nexthop_fib6_nh_bh(struct nexthop *nh)
390
+{
391
+ struct nh_info *nhi;
392
+
393
+ if (nh->is_group) {
394
+ struct nh_group *nh_grp;
395
+
396
+ nh_grp = rcu_dereference_bh_rtnl(nh->nh_grp);
397
+ nh = nexthop_mpath_select(nh_grp, 0);
398
+ if (!nh)
399
+ return NULL;
400
+ }
401
+
402
+ nhi = rcu_dereference_bh_rtnl(nh->nh_info);
403
+ if (nhi->family == AF_INET6)
404
+ return &nhi->fib6_nh;
405
+
406
+ return NULL;
407
+}
408
+
409
+static inline struct net_device *fib6_info_nh_dev(struct fib6_info *f6i)
410
+{
411
+ struct fib6_nh *fib6_nh;
412
+
413
+ fib6_nh = f6i->nh ? nexthop_fib6_nh(f6i->nh) : f6i->fib6_nh;
414
+ return fib6_nh->fib_nh_dev;
415
+}
416
+
417
+static inline void nexthop_path_fib6_result(struct fib6_result *res, int hash)
418
+{
419
+ struct nexthop *nh = res->f6i->nh;
420
+ struct nh_info *nhi;
421
+
422
+ nh = nexthop_select_path(nh, hash);
423
+
424
+ nhi = rcu_dereference_rtnl(nh->nh_info);
425
+ if (nhi->reject_nh) {
426
+ res->fib6_type = RTN_BLACKHOLE;
427
+ res->fib6_flags |= RTF_REJECT;
428
+ res->nh = nexthop_fib6_nh(nh);
429
+ } else {
430
+ res->nh = &nhi->fib6_nh;
431
+ }
432
+}
433
+
434
+int nexthop_for_each_fib6_nh(struct nexthop *nh,
435
+ int (*cb)(struct fib6_nh *nh, void *arg),
436
+ void *arg);
437
+
438
+static inline int nexthop_get_family(struct nexthop *nh)
439
+{
440
+ struct nh_info *nhi = rcu_dereference_rtnl(nh->nh_info);
441
+
442
+ return nhi->family;
443
+}
444
+
445
+static inline
446
+struct fib_nh_common *nexthop_fdb_nhc(struct nexthop *nh)
447
+{
448
+ struct nh_info *nhi = rcu_dereference_rtnl(nh->nh_info);
449
+
450
+ return &nhi->fib_nhc;
451
+}
452
+
453
+static inline struct fib_nh_common *nexthop_path_fdb_result(struct nexthop *nh,
454
+ int hash)
455
+{
456
+ struct nh_info *nhi;
457
+ struct nexthop *nhp;
458
+
459
+ nhp = nexthop_select_path(nh, hash);
460
+ if (unlikely(!nhp))
461
+ return NULL;
462
+ nhi = rcu_dereference(nhp->nh_info);
463
+ return &nhi->fib_nhc;
464
+}
34465 #endif