1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
3
4 #include <linux/kernel.h>
5 #include <linux/types.h>
6 #include <linux/rhashtable.h>
7 #include <linux/bitops.h>
8 #include <linux/in6.h>
9 #include <linux/notifier.h>
10 #include <linux/inetdevice.h>
11 #include <linux/netdevice.h>
12 #include <linux/if_bridge.h>
13 #include <linux/socket.h>
14 #include <linux/route.h>
15 #include <linux/gcd.h>
16 #include <linux/if_macvlan.h>
17 #include <linux/refcount.h>
18 #include <linux/jhash.h>
19 #include <linux/net_namespace.h>
20 #include <linux/mutex.h>
21 #include <linux/genalloc.h>
22 #include <linux/xarray.h>
23 #include <net/netevent.h>
24 #include <net/neighbour.h>
25 #include <net/arp.h>
26 #include <net/inet_dscp.h>
27 #include <net/ip_fib.h>
28 #include <net/ip6_fib.h>
29 #include <net/nexthop.h>
30 #include <net/fib_rules.h>
31 #include <net/ip_tunnels.h>
32 #include <net/l3mdev.h>
33 #include <net/addrconf.h>
34 #include <net/ndisc.h>
35 #include <net/ipv6.h>
36 #include <net/fib_notifier.h>
37 #include <net/switchdev.h>
38
39 #include "spectrum.h"
40 #include "core.h"
41 #include "reg.h"
42 #include "spectrum_cnt.h"
43 #include "spectrum_dpipe.h"
44 #include "spectrum_ipip.h"
45 #include "spectrum_mr.h"
46 #include "spectrum_mr_tcam.h"
47 #include "spectrum_router.h"
48 #include "spectrum_span.h"
49
50 struct mlxsw_sp_fib;
51 struct mlxsw_sp_vr;
52 struct mlxsw_sp_lpm_tree;
53 struct mlxsw_sp_rif_ops;
54
55 struct mlxsw_sp_crif_key {
56 struct net_device *dev;
57 };
58
59 struct mlxsw_sp_crif {
60 struct mlxsw_sp_crif_key key;
61 struct rhash_head ht_node;
62 bool can_destroy;
63 struct list_head nexthop_list;
64 struct mlxsw_sp_rif *rif;
65 };
66
67 static const struct rhashtable_params mlxsw_sp_crif_ht_params = {
68 .key_offset = offsetof(struct mlxsw_sp_crif, key),
69 .key_len = sizeof_field(struct mlxsw_sp_crif, key),
70 .head_offset = offsetof(struct mlxsw_sp_crif, ht_node),
71 };
72
73 struct mlxsw_sp_rif {
74 struct mlxsw_sp_crif *crif; /* NULL for underlay RIF */
75 netdevice_tracker dev_tracker;
76 struct list_head neigh_list;
77 struct mlxsw_sp_fid *fid;
78 unsigned char addr[ETH_ALEN];
79 int mtu;
80 u16 rif_index;
81 u8 mac_profile_id;
82 u8 rif_entries;
83 u16 vr_id;
84 const struct mlxsw_sp_rif_ops *ops;
85 struct mlxsw_sp *mlxsw_sp;
86
87 unsigned int counter_ingress;
88 bool counter_ingress_valid;
89 unsigned int counter_egress;
90 bool counter_egress_valid;
91 };
92
mlxsw_sp_rif_dev(const struct mlxsw_sp_rif * rif)93 static struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif)
94 {
95 if (!rif->crif)
96 return NULL;
97 return rif->crif->key.dev;
98 }
99
100 struct mlxsw_sp_rif_params {
101 struct net_device *dev;
102 union {
103 u16 system_port;
104 u16 lag_id;
105 };
106 u16 vid;
107 bool lag;
108 bool double_entry;
109 };
110
111 struct mlxsw_sp_rif_subport {
112 struct mlxsw_sp_rif common;
113 refcount_t ref_count;
114 union {
115 u16 system_port;
116 u16 lag_id;
117 };
118 u16 vid;
119 bool lag;
120 };
121
122 struct mlxsw_sp_rif_ipip_lb {
123 struct mlxsw_sp_rif common;
124 struct mlxsw_sp_rif_ipip_lb_config lb_config;
125 u16 ul_vr_id; /* Spectrum-1. */
126 u16 ul_rif_id; /* Spectrum-2+. */
127 };
128
129 struct mlxsw_sp_rif_params_ipip_lb {
130 struct mlxsw_sp_rif_params common;
131 struct mlxsw_sp_rif_ipip_lb_config lb_config;
132 };
133
134 struct mlxsw_sp_rif_ops {
135 enum mlxsw_sp_rif_type type;
136 size_t rif_size;
137
138 void (*setup)(struct mlxsw_sp_rif *rif,
139 const struct mlxsw_sp_rif_params *params);
140 int (*configure)(struct mlxsw_sp_rif *rif,
141 struct netlink_ext_ack *extack);
142 void (*deconfigure)(struct mlxsw_sp_rif *rif);
143 struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif,
144 const struct mlxsw_sp_rif_params *params,
145 struct netlink_ext_ack *extack);
146 void (*fdb_del)(struct mlxsw_sp_rif *rif, const char *mac);
147 };
148
149 struct mlxsw_sp_rif_mac_profile {
150 unsigned char mac_prefix[ETH_ALEN];
151 refcount_t ref_count;
152 u8 id;
153 };
154
155 struct mlxsw_sp_router_ops {
156 int (*init)(struct mlxsw_sp *mlxsw_sp);
157 int (*ipips_init)(struct mlxsw_sp *mlxsw_sp);
158 };
159
160 static struct mlxsw_sp_rif *
161 mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
162 const struct net_device *dev);
163 static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif);
164 static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree);
165 static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
166 struct mlxsw_sp_lpm_tree *lpm_tree);
167 static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
168 const struct mlxsw_sp_fib *fib,
169 u8 tree_id);
170 static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
171 const struct mlxsw_sp_fib *fib);
172
173 static unsigned int *
mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir)174 mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif,
175 enum mlxsw_sp_rif_counter_dir dir)
176 {
177 switch (dir) {
178 case MLXSW_SP_RIF_COUNTER_EGRESS:
179 return &rif->counter_egress;
180 case MLXSW_SP_RIF_COUNTER_INGRESS:
181 return &rif->counter_ingress;
182 }
183 return NULL;
184 }
185
186 static bool
mlxsw_sp_rif_counter_valid_get(struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir)187 mlxsw_sp_rif_counter_valid_get(struct mlxsw_sp_rif *rif,
188 enum mlxsw_sp_rif_counter_dir dir)
189 {
190 switch (dir) {
191 case MLXSW_SP_RIF_COUNTER_EGRESS:
192 return rif->counter_egress_valid;
193 case MLXSW_SP_RIF_COUNTER_INGRESS:
194 return rif->counter_ingress_valid;
195 }
196 return false;
197 }
198
199 static void
mlxsw_sp_rif_counter_valid_set(struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir,bool valid)200 mlxsw_sp_rif_counter_valid_set(struct mlxsw_sp_rif *rif,
201 enum mlxsw_sp_rif_counter_dir dir,
202 bool valid)
203 {
204 switch (dir) {
205 case MLXSW_SP_RIF_COUNTER_EGRESS:
206 rif->counter_egress_valid = valid;
207 break;
208 case MLXSW_SP_RIF_COUNTER_INGRESS:
209 rif->counter_ingress_valid = valid;
210 break;
211 }
212 }
213
mlxsw_sp_rif_counter_edit(struct mlxsw_sp * mlxsw_sp,u16 rif_index,unsigned int counter_index,bool enable,enum mlxsw_sp_rif_counter_dir dir)214 static int mlxsw_sp_rif_counter_edit(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
215 unsigned int counter_index, bool enable,
216 enum mlxsw_sp_rif_counter_dir dir)
217 {
218 char ritr_pl[MLXSW_REG_RITR_LEN];
219 bool is_egress = false;
220 int err;
221
222 if (dir == MLXSW_SP_RIF_COUNTER_EGRESS)
223 is_egress = true;
224 mlxsw_reg_ritr_rif_pack(ritr_pl, rif_index);
225 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
226 if (err)
227 return err;
228
229 mlxsw_reg_ritr_counter_pack(ritr_pl, counter_index, enable,
230 is_egress);
231 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
232 }
233
mlxsw_sp_rif_counter_value_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir,u64 * cnt)234 int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp *mlxsw_sp,
235 struct mlxsw_sp_rif *rif,
236 enum mlxsw_sp_rif_counter_dir dir, u64 *cnt)
237 {
238 char ricnt_pl[MLXSW_REG_RICNT_LEN];
239 unsigned int *p_counter_index;
240 bool valid;
241 int err;
242
243 valid = mlxsw_sp_rif_counter_valid_get(rif, dir);
244 if (!valid)
245 return -EINVAL;
246
247 p_counter_index = mlxsw_sp_rif_p_counter_get(rif, dir);
248 if (!p_counter_index)
249 return -EINVAL;
250 mlxsw_reg_ricnt_pack(ricnt_pl, *p_counter_index,
251 MLXSW_REG_RICNT_OPCODE_NOP);
252 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ricnt), ricnt_pl);
253 if (err)
254 return err;
255 *cnt = mlxsw_reg_ricnt_good_unicast_packets_get(ricnt_pl);
256 return 0;
257 }
258
259 struct mlxsw_sp_rif_counter_set_basic {
260 u64 good_unicast_packets;
261 u64 good_multicast_packets;
262 u64 good_broadcast_packets;
263 u64 good_unicast_bytes;
264 u64 good_multicast_bytes;
265 u64 good_broadcast_bytes;
266 u64 error_packets;
267 u64 discard_packets;
268 u64 error_bytes;
269 u64 discard_bytes;
270 };
271
272 static int
mlxsw_sp_rif_counter_fetch_clear(struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir,struct mlxsw_sp_rif_counter_set_basic * set)273 mlxsw_sp_rif_counter_fetch_clear(struct mlxsw_sp_rif *rif,
274 enum mlxsw_sp_rif_counter_dir dir,
275 struct mlxsw_sp_rif_counter_set_basic *set)
276 {
277 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
278 char ricnt_pl[MLXSW_REG_RICNT_LEN];
279 unsigned int *p_counter_index;
280 int err;
281
282 if (!mlxsw_sp_rif_counter_valid_get(rif, dir))
283 return -EINVAL;
284
285 p_counter_index = mlxsw_sp_rif_p_counter_get(rif, dir);
286 if (!p_counter_index)
287 return -EINVAL;
288
289 mlxsw_reg_ricnt_pack(ricnt_pl, *p_counter_index,
290 MLXSW_REG_RICNT_OPCODE_CLEAR);
291 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ricnt), ricnt_pl);
292 if (err)
293 return err;
294
295 if (!set)
296 return 0;
297
298 #define MLXSW_SP_RIF_COUNTER_EXTRACT(NAME) \
299 (set->NAME = mlxsw_reg_ricnt_ ## NAME ## _get(ricnt_pl))
300
301 MLXSW_SP_RIF_COUNTER_EXTRACT(good_unicast_packets);
302 MLXSW_SP_RIF_COUNTER_EXTRACT(good_multicast_packets);
303 MLXSW_SP_RIF_COUNTER_EXTRACT(good_broadcast_packets);
304 MLXSW_SP_RIF_COUNTER_EXTRACT(good_unicast_bytes);
305 MLXSW_SP_RIF_COUNTER_EXTRACT(good_multicast_bytes);
306 MLXSW_SP_RIF_COUNTER_EXTRACT(good_broadcast_bytes);
307 MLXSW_SP_RIF_COUNTER_EXTRACT(error_packets);
308 MLXSW_SP_RIF_COUNTER_EXTRACT(discard_packets);
309 MLXSW_SP_RIF_COUNTER_EXTRACT(error_bytes);
310 MLXSW_SP_RIF_COUNTER_EXTRACT(discard_bytes);
311
312 #undef MLXSW_SP_RIF_COUNTER_EXTRACT
313
314 return 0;
315 }
316
mlxsw_sp_rif_counter_clear(struct mlxsw_sp * mlxsw_sp,unsigned int counter_index)317 static int mlxsw_sp_rif_counter_clear(struct mlxsw_sp *mlxsw_sp,
318 unsigned int counter_index)
319 {
320 char ricnt_pl[MLXSW_REG_RICNT_LEN];
321
322 mlxsw_reg_ricnt_pack(ricnt_pl, counter_index,
323 MLXSW_REG_RICNT_OPCODE_CLEAR);
324 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ricnt), ricnt_pl);
325 }
326
mlxsw_sp_rif_counter_alloc(struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir)327 int mlxsw_sp_rif_counter_alloc(struct mlxsw_sp_rif *rif,
328 enum mlxsw_sp_rif_counter_dir dir)
329 {
330 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
331 unsigned int *p_counter_index;
332 int err;
333
334 if (mlxsw_sp_rif_counter_valid_get(rif, dir))
335 return 0;
336
337 p_counter_index = mlxsw_sp_rif_p_counter_get(rif, dir);
338 if (!p_counter_index)
339 return -EINVAL;
340
341 err = mlxsw_sp_counter_alloc(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_RIF,
342 p_counter_index);
343 if (err)
344 return err;
345
346 err = mlxsw_sp_rif_counter_clear(mlxsw_sp, *p_counter_index);
347 if (err)
348 goto err_counter_clear;
349
350 err = mlxsw_sp_rif_counter_edit(mlxsw_sp, rif->rif_index,
351 *p_counter_index, true, dir);
352 if (err)
353 goto err_counter_edit;
354 mlxsw_sp_rif_counter_valid_set(rif, dir, true);
355 return 0;
356
357 err_counter_edit:
358 err_counter_clear:
359 mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_RIF,
360 *p_counter_index);
361 return err;
362 }
363
mlxsw_sp_rif_counter_free(struct mlxsw_sp_rif * rif,enum mlxsw_sp_rif_counter_dir dir)364 void mlxsw_sp_rif_counter_free(struct mlxsw_sp_rif *rif,
365 enum mlxsw_sp_rif_counter_dir dir)
366 {
367 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
368 unsigned int *p_counter_index;
369
370 if (!mlxsw_sp_rif_counter_valid_get(rif, dir))
371 return;
372
373 p_counter_index = mlxsw_sp_rif_p_counter_get(rif, dir);
374 if (WARN_ON(!p_counter_index))
375 return;
376 mlxsw_sp_rif_counter_edit(mlxsw_sp, rif->rif_index,
377 *p_counter_index, false, dir);
378 mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_RIF,
379 *p_counter_index);
380 mlxsw_sp_rif_counter_valid_set(rif, dir, false);
381 }
382
mlxsw_sp_rif_counters_alloc(struct mlxsw_sp_rif * rif)383 static void mlxsw_sp_rif_counters_alloc(struct mlxsw_sp_rif *rif)
384 {
385 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
386 struct devlink *devlink;
387
388 devlink = priv_to_devlink(mlxsw_sp->core);
389 if (!devlink_dpipe_table_counter_enabled(devlink,
390 MLXSW_SP_DPIPE_TABLE_NAME_ERIF))
391 return;
392 mlxsw_sp_rif_counter_alloc(rif, MLXSW_SP_RIF_COUNTER_EGRESS);
393 }
394
mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif * rif)395 static void mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif *rif)
396 {
397 mlxsw_sp_rif_counter_free(rif, MLXSW_SP_RIF_COUNTER_EGRESS);
398 }
399
400 #define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE + 1)
401
402 struct mlxsw_sp_prefix_usage {
403 DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT);
404 };
405
406 #define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \
407 for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
408
409 static bool
mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage * prefix_usage1,struct mlxsw_sp_prefix_usage * prefix_usage2)410 mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage *prefix_usage1,
411 struct mlxsw_sp_prefix_usage *prefix_usage2)
412 {
413 return !memcmp(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1));
414 }
415
416 static void
mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage * prefix_usage1,struct mlxsw_sp_prefix_usage * prefix_usage2)417 mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage *prefix_usage1,
418 struct mlxsw_sp_prefix_usage *prefix_usage2)
419 {
420 memcpy(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1));
421 }
422
423 static void
mlxsw_sp_prefix_usage_set(struct mlxsw_sp_prefix_usage * prefix_usage,unsigned char prefix_len)424 mlxsw_sp_prefix_usage_set(struct mlxsw_sp_prefix_usage *prefix_usage,
425 unsigned char prefix_len)
426 {
427 set_bit(prefix_len, prefix_usage->b);
428 }
429
430 static void
mlxsw_sp_prefix_usage_clear(struct mlxsw_sp_prefix_usage * prefix_usage,unsigned char prefix_len)431 mlxsw_sp_prefix_usage_clear(struct mlxsw_sp_prefix_usage *prefix_usage,
432 unsigned char prefix_len)
433 {
434 clear_bit(prefix_len, prefix_usage->b);
435 }
436
437 struct mlxsw_sp_fib_key {
438 unsigned char addr[sizeof(struct in6_addr)];
439 unsigned char prefix_len;
440 };
441
442 enum mlxsw_sp_fib_entry_type {
443 MLXSW_SP_FIB_ENTRY_TYPE_REMOTE,
444 MLXSW_SP_FIB_ENTRY_TYPE_LOCAL,
445 MLXSW_SP_FIB_ENTRY_TYPE_TRAP,
446 MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE,
447 MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE,
448
449 /* This is a special case of local delivery, where a packet should be
450 * decapsulated on reception. Note that there is no corresponding ENCAP,
451 * because that's a type of next hop, not of FIB entry. (There can be
452 * several next hops in a REMOTE entry, and some of them may be
453 * encapsulating entries.)
454 */
455 MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP,
456 MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP,
457 };
458
459 struct mlxsw_sp_nexthop_group_info;
460 struct mlxsw_sp_nexthop_group;
461 struct mlxsw_sp_fib_entry;
462
463 struct mlxsw_sp_fib_node {
464 struct mlxsw_sp_fib_entry *fib_entry;
465 struct list_head list;
466 struct rhash_head ht_node;
467 struct mlxsw_sp_fib *fib;
468 struct mlxsw_sp_fib_key key;
469 };
470
471 struct mlxsw_sp_fib_entry_decap {
472 struct mlxsw_sp_ipip_entry *ipip_entry;
473 u32 tunnel_index;
474 };
475
476 struct mlxsw_sp_fib_entry {
477 struct mlxsw_sp_fib_node *fib_node;
478 enum mlxsw_sp_fib_entry_type type;
479 struct list_head nexthop_group_node;
480 struct mlxsw_sp_nexthop_group *nh_group;
481 struct mlxsw_sp_fib_entry_decap decap; /* Valid for decap entries. */
482 };
483
484 struct mlxsw_sp_fib4_entry {
485 struct mlxsw_sp_fib_entry common;
486 struct fib_info *fi;
487 u32 tb_id;
488 dscp_t dscp;
489 u8 type;
490 };
491
492 struct mlxsw_sp_fib6_entry {
493 struct mlxsw_sp_fib_entry common;
494 struct list_head rt6_list;
495 unsigned int nrt6;
496 };
497
498 struct mlxsw_sp_rt6 {
499 struct list_head list;
500 struct fib6_info *rt;
501 };
502
503 struct mlxsw_sp_lpm_tree {
504 u8 id; /* tree ID */
505 refcount_t ref_count;
506 enum mlxsw_sp_l3proto proto;
507 unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT];
508 struct mlxsw_sp_prefix_usage prefix_usage;
509 };
510
511 struct mlxsw_sp_fib {
512 struct rhashtable ht;
513 struct list_head node_list;
514 struct mlxsw_sp_vr *vr;
515 struct mlxsw_sp_lpm_tree *lpm_tree;
516 enum mlxsw_sp_l3proto proto;
517 };
518
519 struct mlxsw_sp_vr {
520 u16 id; /* virtual router ID */
521 u32 tb_id; /* kernel fib table id */
522 unsigned int rif_count;
523 struct mlxsw_sp_fib *fib4;
524 struct mlxsw_sp_fib *fib6;
525 struct mlxsw_sp_mr_table *mr_table[MLXSW_SP_L3_PROTO_MAX];
526 struct mlxsw_sp_rif *ul_rif;
527 refcount_t ul_rif_refcnt;
528 };
529
530 static const struct rhashtable_params mlxsw_sp_fib_ht_params;
531
mlxsw_sp_fib_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_vr * vr,enum mlxsw_sp_l3proto proto)532 static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp *mlxsw_sp,
533 struct mlxsw_sp_vr *vr,
534 enum mlxsw_sp_l3proto proto)
535 {
536 struct mlxsw_sp_lpm_tree *lpm_tree;
537 struct mlxsw_sp_fib *fib;
538 int err;
539
540 lpm_tree = mlxsw_sp->router->lpm.proto_trees[proto];
541 fib = kzalloc_obj(*fib);
542 if (!fib)
543 return ERR_PTR(-ENOMEM);
544 err = rhashtable_init(&fib->ht, &mlxsw_sp_fib_ht_params);
545 if (err)
546 goto err_rhashtable_init;
547 INIT_LIST_HEAD(&fib->node_list);
548 fib->proto = proto;
549 fib->vr = vr;
550 fib->lpm_tree = lpm_tree;
551 mlxsw_sp_lpm_tree_hold(lpm_tree);
552 err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, lpm_tree->id);
553 if (err)
554 goto err_lpm_tree_bind;
555 return fib;
556
557 err_lpm_tree_bind:
558 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
559 err_rhashtable_init:
560 kfree(fib);
561 return ERR_PTR(err);
562 }
563
mlxsw_sp_fib_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib * fib)564 static void mlxsw_sp_fib_destroy(struct mlxsw_sp *mlxsw_sp,
565 struct mlxsw_sp_fib *fib)
566 {
567 mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, fib);
568 mlxsw_sp_lpm_tree_put(mlxsw_sp, fib->lpm_tree);
569 WARN_ON(!list_empty(&fib->node_list));
570 rhashtable_destroy(&fib->ht);
571 kfree(fib);
572 }
573
574 static struct mlxsw_sp_lpm_tree *
mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp * mlxsw_sp)575 mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp)
576 {
577 static struct mlxsw_sp_lpm_tree *lpm_tree;
578 int i;
579
580 for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
581 lpm_tree = &mlxsw_sp->router->lpm.trees[i];
582 if (refcount_read(&lpm_tree->ref_count) == 0)
583 return lpm_tree;
584 }
585 return NULL;
586 }
587
mlxsw_sp_lpm_tree_alloc(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_lpm_tree * lpm_tree)588 static int mlxsw_sp_lpm_tree_alloc(struct mlxsw_sp *mlxsw_sp,
589 struct mlxsw_sp_lpm_tree *lpm_tree)
590 {
591 char ralta_pl[MLXSW_REG_RALTA_LEN];
592
593 mlxsw_reg_ralta_pack(ralta_pl, true,
594 (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
595 lpm_tree->id);
596 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
597 }
598
mlxsw_sp_lpm_tree_free(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_lpm_tree * lpm_tree)599 static void mlxsw_sp_lpm_tree_free(struct mlxsw_sp *mlxsw_sp,
600 struct mlxsw_sp_lpm_tree *lpm_tree)
601 {
602 char ralta_pl[MLXSW_REG_RALTA_LEN];
603
604 mlxsw_reg_ralta_pack(ralta_pl, false,
605 (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
606 lpm_tree->id);
607 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
608 }
609
610 static int
mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_prefix_usage * prefix_usage,struct mlxsw_sp_lpm_tree * lpm_tree)611 mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp *mlxsw_sp,
612 struct mlxsw_sp_prefix_usage *prefix_usage,
613 struct mlxsw_sp_lpm_tree *lpm_tree)
614 {
615 char ralst_pl[MLXSW_REG_RALST_LEN];
616 u8 root_bin = 0;
617 u8 prefix;
618 u8 last_prefix = MLXSW_REG_RALST_BIN_NO_CHILD;
619
620 mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage)
621 root_bin = prefix;
622
623 mlxsw_reg_ralst_pack(ralst_pl, root_bin, lpm_tree->id);
624 mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) {
625 if (prefix == 0)
626 continue;
627 mlxsw_reg_ralst_bin_pack(ralst_pl, prefix, last_prefix,
628 MLXSW_REG_RALST_BIN_NO_CHILD);
629 last_prefix = prefix;
630 }
631 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl);
632 }
633
634 static struct mlxsw_sp_lpm_tree *
mlxsw_sp_lpm_tree_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_prefix_usage * prefix_usage,enum mlxsw_sp_l3proto proto)635 mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
636 struct mlxsw_sp_prefix_usage *prefix_usage,
637 enum mlxsw_sp_l3proto proto)
638 {
639 struct mlxsw_sp_lpm_tree *lpm_tree;
640 int err;
641
642 lpm_tree = mlxsw_sp_lpm_tree_find_unused(mlxsw_sp);
643 if (!lpm_tree)
644 return ERR_PTR(-EBUSY);
645 lpm_tree->proto = proto;
646 err = mlxsw_sp_lpm_tree_alloc(mlxsw_sp, lpm_tree);
647 if (err)
648 return ERR_PTR(err);
649
650 err = mlxsw_sp_lpm_tree_left_struct_set(mlxsw_sp, prefix_usage,
651 lpm_tree);
652 if (err)
653 goto err_left_struct_set;
654 memcpy(&lpm_tree->prefix_usage, prefix_usage,
655 sizeof(lpm_tree->prefix_usage));
656 memset(&lpm_tree->prefix_ref_count, 0,
657 sizeof(lpm_tree->prefix_ref_count));
658 refcount_set(&lpm_tree->ref_count, 1);
659 return lpm_tree;
660
661 err_left_struct_set:
662 mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
663 return ERR_PTR(err);
664 }
665
mlxsw_sp_lpm_tree_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_lpm_tree * lpm_tree)666 static void mlxsw_sp_lpm_tree_destroy(struct mlxsw_sp *mlxsw_sp,
667 struct mlxsw_sp_lpm_tree *lpm_tree)
668 {
669 mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
670 }
671
672 static struct mlxsw_sp_lpm_tree *
mlxsw_sp_lpm_tree_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_prefix_usage * prefix_usage,enum mlxsw_sp_l3proto proto)673 mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
674 struct mlxsw_sp_prefix_usage *prefix_usage,
675 enum mlxsw_sp_l3proto proto)
676 {
677 struct mlxsw_sp_lpm_tree *lpm_tree;
678 int i;
679
680 for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
681 lpm_tree = &mlxsw_sp->router->lpm.trees[i];
682 if (refcount_read(&lpm_tree->ref_count) &&
683 lpm_tree->proto == proto &&
684 mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage,
685 prefix_usage)) {
686 mlxsw_sp_lpm_tree_hold(lpm_tree);
687 return lpm_tree;
688 }
689 }
690 return mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage, proto);
691 }
692
mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree * lpm_tree)693 static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree)
694 {
695 refcount_inc(&lpm_tree->ref_count);
696 }
697
mlxsw_sp_lpm_tree_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_lpm_tree * lpm_tree)698 static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
699 struct mlxsw_sp_lpm_tree *lpm_tree)
700 {
701 if (!refcount_dec_and_test(&lpm_tree->ref_count))
702 return;
703 mlxsw_sp_lpm_tree_destroy(mlxsw_sp, lpm_tree);
704 }
705
706 #define MLXSW_SP_LPM_TREE_MIN 1 /* tree 0 is reserved */
707
mlxsw_sp_lpm_init(struct mlxsw_sp * mlxsw_sp)708 static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
709 {
710 struct mlxsw_sp_prefix_usage req_prefix_usage = {{ 0 } };
711 struct mlxsw_sp_lpm_tree *lpm_tree;
712 u64 max_trees;
713 int err, i;
714
715 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LPM_TREES))
716 return -EIO;
717
718 max_trees = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LPM_TREES);
719 mlxsw_sp->router->lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN;
720 mlxsw_sp->router->lpm.trees = kzalloc_objs(struct mlxsw_sp_lpm_tree,
721 mlxsw_sp->router->lpm.tree_count);
722 if (!mlxsw_sp->router->lpm.trees)
723 return -ENOMEM;
724
725 for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
726 lpm_tree = &mlxsw_sp->router->lpm.trees[i];
727 lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN;
728 }
729
730 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
731 MLXSW_SP_L3_PROTO_IPV4);
732 if (IS_ERR(lpm_tree)) {
733 err = PTR_ERR(lpm_tree);
734 goto err_ipv4_tree_get;
735 }
736 mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4] = lpm_tree;
737
738 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
739 MLXSW_SP_L3_PROTO_IPV6);
740 if (IS_ERR(lpm_tree)) {
741 err = PTR_ERR(lpm_tree);
742 goto err_ipv6_tree_get;
743 }
744 mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV6] = lpm_tree;
745
746 return 0;
747
748 err_ipv6_tree_get:
749 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4];
750 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
751 err_ipv4_tree_get:
752 kfree(mlxsw_sp->router->lpm.trees);
753 return err;
754 }
755
mlxsw_sp_lpm_fini(struct mlxsw_sp * mlxsw_sp)756 static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp)
757 {
758 struct mlxsw_sp_lpm_tree *lpm_tree;
759
760 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV6];
761 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
762
763 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4];
764 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
765
766 kfree(mlxsw_sp->router->lpm.trees);
767 }
768
mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr * vr)769 static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr *vr)
770 {
771 return !!vr->fib4 || !!vr->fib6 ||
772 !!vr->mr_table[MLXSW_SP_L3_PROTO_IPV4] ||
773 !!vr->mr_table[MLXSW_SP_L3_PROTO_IPV6];
774 }
775
mlxsw_sp_vr_find_unused(struct mlxsw_sp * mlxsw_sp)776 static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp)
777 {
778 int max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS);
779 struct mlxsw_sp_vr *vr;
780 int i;
781
782 for (i = 0; i < max_vrs; i++) {
783 vr = &mlxsw_sp->router->vrs[i];
784 if (!mlxsw_sp_vr_is_used(vr))
785 return vr;
786 }
787 return NULL;
788 }
789
mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_fib * fib,u8 tree_id)790 static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
791 const struct mlxsw_sp_fib *fib, u8 tree_id)
792 {
793 char raltb_pl[MLXSW_REG_RALTB_LEN];
794
795 mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
796 (enum mlxsw_reg_ralxx_protocol) fib->proto,
797 tree_id);
798 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
799 }
800
mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_fib * fib)801 static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
802 const struct mlxsw_sp_fib *fib)
803 {
804 char raltb_pl[MLXSW_REG_RALTB_LEN];
805
806 /* Bind to tree 0 which is default */
807 mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
808 (enum mlxsw_reg_ralxx_protocol) fib->proto, 0);
809 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
810 }
811
mlxsw_sp_fix_tb_id(u32 tb_id)812 static u32 mlxsw_sp_fix_tb_id(u32 tb_id)
813 {
814 /* For our purpose, squash main, default and local tables into one */
815 if (tb_id == RT_TABLE_LOCAL || tb_id == RT_TABLE_DEFAULT)
816 tb_id = RT_TABLE_MAIN;
817 return tb_id;
818 }
819
mlxsw_sp_vr_find(struct mlxsw_sp * mlxsw_sp,u32 tb_id)820 static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp,
821 u32 tb_id)
822 {
823 int max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS);
824 struct mlxsw_sp_vr *vr;
825 int i;
826
827 tb_id = mlxsw_sp_fix_tb_id(tb_id);
828
829 for (i = 0; i < max_vrs; i++) {
830 vr = &mlxsw_sp->router->vrs[i];
831 if (mlxsw_sp_vr_is_used(vr) && vr->tb_id == tb_id)
832 return vr;
833 }
834 return NULL;
835 }
836
mlxsw_sp_router_tb_id_vr_id(struct mlxsw_sp * mlxsw_sp,u32 tb_id,u16 * vr_id)837 int mlxsw_sp_router_tb_id_vr_id(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
838 u16 *vr_id)
839 {
840 struct mlxsw_sp_vr *vr;
841 int err = 0;
842
843 mutex_lock(&mlxsw_sp->router->lock);
844 vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id);
845 if (!vr) {
846 err = -ESRCH;
847 goto out;
848 }
849 *vr_id = vr->id;
850 out:
851 mutex_unlock(&mlxsw_sp->router->lock);
852 return err;
853 }
854
mlxsw_sp_vr_fib(const struct mlxsw_sp_vr * vr,enum mlxsw_sp_l3proto proto)855 static struct mlxsw_sp_fib *mlxsw_sp_vr_fib(const struct mlxsw_sp_vr *vr,
856 enum mlxsw_sp_l3proto proto)
857 {
858 switch (proto) {
859 case MLXSW_SP_L3_PROTO_IPV4:
860 return vr->fib4;
861 case MLXSW_SP_L3_PROTO_IPV6:
862 return vr->fib6;
863 }
864 return NULL;
865 }
866
mlxsw_sp_vr_create(struct mlxsw_sp * mlxsw_sp,u32 tb_id,struct netlink_ext_ack * extack)867 static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
868 u32 tb_id,
869 struct netlink_ext_ack *extack)
870 {
871 struct mlxsw_sp_mr_table *mr4_table, *mr6_table;
872 struct mlxsw_sp_fib *fib4;
873 struct mlxsw_sp_fib *fib6;
874 struct mlxsw_sp_vr *vr;
875 int err;
876
877 vr = mlxsw_sp_vr_find_unused(mlxsw_sp);
878 if (!vr) {
879 NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported virtual routers");
880 return ERR_PTR(-EBUSY);
881 }
882 fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
883 if (IS_ERR(fib4))
884 return ERR_CAST(fib4);
885 fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
886 if (IS_ERR(fib6)) {
887 err = PTR_ERR(fib6);
888 goto err_fib6_create;
889 }
890 mr4_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id,
891 MLXSW_SP_L3_PROTO_IPV4);
892 if (IS_ERR(mr4_table)) {
893 err = PTR_ERR(mr4_table);
894 goto err_mr4_table_create;
895 }
896 mr6_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id,
897 MLXSW_SP_L3_PROTO_IPV6);
898 if (IS_ERR(mr6_table)) {
899 err = PTR_ERR(mr6_table);
900 goto err_mr6_table_create;
901 }
902
903 vr->fib4 = fib4;
904 vr->fib6 = fib6;
905 vr->mr_table[MLXSW_SP_L3_PROTO_IPV4] = mr4_table;
906 vr->mr_table[MLXSW_SP_L3_PROTO_IPV6] = mr6_table;
907 vr->tb_id = tb_id;
908 return vr;
909
910 err_mr6_table_create:
911 mlxsw_sp_mr_table_destroy(mr4_table);
912 err_mr4_table_create:
913 mlxsw_sp_fib_destroy(mlxsw_sp, fib6);
914 err_fib6_create:
915 mlxsw_sp_fib_destroy(mlxsw_sp, fib4);
916 return ERR_PTR(err);
917 }
918
mlxsw_sp_vr_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_vr * vr)919 static void mlxsw_sp_vr_destroy(struct mlxsw_sp *mlxsw_sp,
920 struct mlxsw_sp_vr *vr)
921 {
922 mlxsw_sp_mr_table_destroy(vr->mr_table[MLXSW_SP_L3_PROTO_IPV6]);
923 vr->mr_table[MLXSW_SP_L3_PROTO_IPV6] = NULL;
924 mlxsw_sp_mr_table_destroy(vr->mr_table[MLXSW_SP_L3_PROTO_IPV4]);
925 vr->mr_table[MLXSW_SP_L3_PROTO_IPV4] = NULL;
926 mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib6);
927 vr->fib6 = NULL;
928 mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib4);
929 vr->fib4 = NULL;
930 }
931
mlxsw_sp_vr_get(struct mlxsw_sp * mlxsw_sp,u32 tb_id,struct netlink_ext_ack * extack)932 static struct mlxsw_sp_vr *mlxsw_sp_vr_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
933 struct netlink_ext_ack *extack)
934 {
935 struct mlxsw_sp_vr *vr;
936
937 tb_id = mlxsw_sp_fix_tb_id(tb_id);
938 vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id);
939 if (!vr)
940 vr = mlxsw_sp_vr_create(mlxsw_sp, tb_id, extack);
941 return vr;
942 }
943
mlxsw_sp_vr_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_vr * vr)944 static void mlxsw_sp_vr_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr)
945 {
946 if (!vr->rif_count && list_empty(&vr->fib4->node_list) &&
947 list_empty(&vr->fib6->node_list) &&
948 mlxsw_sp_mr_table_empty(vr->mr_table[MLXSW_SP_L3_PROTO_IPV4]) &&
949 mlxsw_sp_mr_table_empty(vr->mr_table[MLXSW_SP_L3_PROTO_IPV6]))
950 mlxsw_sp_vr_destroy(mlxsw_sp, vr);
951 }
952
953 static bool
mlxsw_sp_vr_lpm_tree_should_replace(struct mlxsw_sp_vr * vr,enum mlxsw_sp_l3proto proto,u8 tree_id)954 mlxsw_sp_vr_lpm_tree_should_replace(struct mlxsw_sp_vr *vr,
955 enum mlxsw_sp_l3proto proto, u8 tree_id)
956 {
957 struct mlxsw_sp_fib *fib = mlxsw_sp_vr_fib(vr, proto);
958
959 if (!mlxsw_sp_vr_is_used(vr))
960 return false;
961 if (fib->lpm_tree->id == tree_id)
962 return true;
963 return false;
964 }
965
mlxsw_sp_vr_lpm_tree_replace(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib * fib,struct mlxsw_sp_lpm_tree * new_tree)966 static int mlxsw_sp_vr_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
967 struct mlxsw_sp_fib *fib,
968 struct mlxsw_sp_lpm_tree *new_tree)
969 {
970 struct mlxsw_sp_lpm_tree *old_tree = fib->lpm_tree;
971 int err;
972
973 fib->lpm_tree = new_tree;
974 mlxsw_sp_lpm_tree_hold(new_tree);
975 err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, new_tree->id);
976 if (err)
977 goto err_tree_bind;
978 mlxsw_sp_lpm_tree_put(mlxsw_sp, old_tree);
979 return 0;
980
981 err_tree_bind:
982 mlxsw_sp_lpm_tree_put(mlxsw_sp, new_tree);
983 fib->lpm_tree = old_tree;
984 return err;
985 }
986
mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib * fib,struct mlxsw_sp_lpm_tree * new_tree)987 static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
988 struct mlxsw_sp_fib *fib,
989 struct mlxsw_sp_lpm_tree *new_tree)
990 {
991 int max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS);
992 enum mlxsw_sp_l3proto proto = fib->proto;
993 struct mlxsw_sp_lpm_tree *old_tree;
994 u8 old_id, new_id = new_tree->id;
995 struct mlxsw_sp_vr *vr;
996 int i, err;
997
998 old_tree = mlxsw_sp->router->lpm.proto_trees[proto];
999 old_id = old_tree->id;
1000
1001 for (i = 0; i < max_vrs; i++) {
1002 vr = &mlxsw_sp->router->vrs[i];
1003 if (!mlxsw_sp_vr_lpm_tree_should_replace(vr, proto, old_id))
1004 continue;
1005 err = mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp,
1006 mlxsw_sp_vr_fib(vr, proto),
1007 new_tree);
1008 if (err)
1009 goto err_tree_replace;
1010 }
1011
1012 memcpy(new_tree->prefix_ref_count, old_tree->prefix_ref_count,
1013 sizeof(new_tree->prefix_ref_count));
1014 mlxsw_sp->router->lpm.proto_trees[proto] = new_tree;
1015 mlxsw_sp_lpm_tree_put(mlxsw_sp, old_tree);
1016
1017 return 0;
1018
1019 err_tree_replace:
1020 for (i--; i >= 0; i--) {
1021 if (!mlxsw_sp_vr_lpm_tree_should_replace(vr, proto, new_id))
1022 continue;
1023 mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp,
1024 mlxsw_sp_vr_fib(vr, proto),
1025 old_tree);
1026 }
1027 return err;
1028 }
1029
mlxsw_sp_vrs_init(struct mlxsw_sp * mlxsw_sp)1030 static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
1031 {
1032 struct mlxsw_sp_vr *vr;
1033 u64 max_vrs;
1034 int i;
1035
1036 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_VRS))
1037 return -EIO;
1038
1039 max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS);
1040 mlxsw_sp->router->vrs = kzalloc_objs(struct mlxsw_sp_vr, max_vrs);
1041 if (!mlxsw_sp->router->vrs)
1042 return -ENOMEM;
1043
1044 for (i = 0; i < max_vrs; i++) {
1045 vr = &mlxsw_sp->router->vrs[i];
1046 vr->id = i;
1047 }
1048
1049 return 0;
1050 }
1051
1052 static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp);
1053
mlxsw_sp_vrs_fini(struct mlxsw_sp * mlxsw_sp)1054 static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp)
1055 {
1056 /* At this stage we're guaranteed not to have new incoming
1057 * FIB notifications and the work queue is free from FIBs
1058 * sitting on top of mlxsw netdevs. However, we can still
1059 * have other FIBs queued. Flush the queue before flushing
1060 * the device's tables. No need for locks, as we're the only
1061 * writer.
1062 */
1063 mlxsw_core_flush_owq();
1064 mlxsw_sp_router_fib_flush(mlxsw_sp);
1065 kfree(mlxsw_sp->router->vrs);
1066 }
1067
mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device * ol_dev)1068 u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev)
1069 {
1070 struct net_device *d;
1071 u32 tb_id;
1072
1073 rcu_read_lock();
1074 d = mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
1075 if (d)
1076 tb_id = l3mdev_fib_table(d) ? : RT_TABLE_MAIN;
1077 else
1078 tb_id = RT_TABLE_MAIN;
1079 rcu_read_unlock();
1080
1081 return tb_id;
1082 }
1083
1084 static void
mlxsw_sp_crif_init(struct mlxsw_sp_crif * crif,struct net_device * dev)1085 mlxsw_sp_crif_init(struct mlxsw_sp_crif *crif, struct net_device *dev)
1086 {
1087 crif->key.dev = dev;
1088 INIT_LIST_HEAD(&crif->nexthop_list);
1089 }
1090
1091 static struct mlxsw_sp_crif *
mlxsw_sp_crif_alloc(struct net_device * dev)1092 mlxsw_sp_crif_alloc(struct net_device *dev)
1093 {
1094 struct mlxsw_sp_crif *crif;
1095
1096 crif = kzalloc_obj(*crif);
1097 if (!crif)
1098 return NULL;
1099
1100 mlxsw_sp_crif_init(crif, dev);
1101 return crif;
1102 }
1103
mlxsw_sp_crif_free(struct mlxsw_sp_crif * crif)1104 static void mlxsw_sp_crif_free(struct mlxsw_sp_crif *crif)
1105 {
1106 if (WARN_ON(crif->rif))
1107 return;
1108
1109 WARN_ON(!list_empty(&crif->nexthop_list));
1110 kfree(crif);
1111 }
1112
mlxsw_sp_crif_insert(struct mlxsw_sp_router * router,struct mlxsw_sp_crif * crif)1113 static int mlxsw_sp_crif_insert(struct mlxsw_sp_router *router,
1114 struct mlxsw_sp_crif *crif)
1115 {
1116 return rhashtable_insert_fast(&router->crif_ht, &crif->ht_node,
1117 mlxsw_sp_crif_ht_params);
1118 }
1119
mlxsw_sp_crif_remove(struct mlxsw_sp_router * router,struct mlxsw_sp_crif * crif)1120 static void mlxsw_sp_crif_remove(struct mlxsw_sp_router *router,
1121 struct mlxsw_sp_crif *crif)
1122 {
1123 rhashtable_remove_fast(&router->crif_ht, &crif->ht_node,
1124 mlxsw_sp_crif_ht_params);
1125 }
1126
1127 static struct mlxsw_sp_crif *
mlxsw_sp_crif_lookup(struct mlxsw_sp_router * router,const struct net_device * dev)1128 mlxsw_sp_crif_lookup(struct mlxsw_sp_router *router,
1129 const struct net_device *dev)
1130 {
1131 struct mlxsw_sp_crif_key key = {
1132 .dev = (struct net_device *)dev,
1133 };
1134
1135 return rhashtable_lookup_fast(&router->crif_ht, &key,
1136 mlxsw_sp_crif_ht_params);
1137 }
1138
1139 static struct mlxsw_sp_rif *
1140 mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
1141 const struct mlxsw_sp_rif_params *params,
1142 struct netlink_ext_ack *extack);
1143
1144 static struct mlxsw_sp_rif_ipip_lb *
mlxsw_sp_ipip_ol_ipip_lb_create(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_ipip_type ipipt,struct net_device * ol_dev,struct netlink_ext_ack * extack)1145 mlxsw_sp_ipip_ol_ipip_lb_create(struct mlxsw_sp *mlxsw_sp,
1146 enum mlxsw_sp_ipip_type ipipt,
1147 struct net_device *ol_dev,
1148 struct netlink_ext_ack *extack)
1149 {
1150 struct mlxsw_sp_rif_params_ipip_lb lb_params;
1151 const struct mlxsw_sp_ipip_ops *ipip_ops;
1152 struct mlxsw_sp_rif *rif;
1153
1154 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipipt];
1155 lb_params = (struct mlxsw_sp_rif_params_ipip_lb) {
1156 .common.dev = ol_dev,
1157 .common.lag = false,
1158 .common.double_entry = ipip_ops->double_rif_entry,
1159 .lb_config = ipip_ops->ol_loopback_config(mlxsw_sp, ol_dev),
1160 };
1161
1162 rif = mlxsw_sp_rif_create(mlxsw_sp, &lb_params.common, extack);
1163 if (IS_ERR(rif))
1164 return ERR_CAST(rif);
1165 return container_of(rif, struct mlxsw_sp_rif_ipip_lb, common);
1166 }
1167
1168 static struct mlxsw_sp_ipip_entry *
mlxsw_sp_ipip_entry_alloc(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_ipip_type ipipt,struct net_device * ol_dev)1169 mlxsw_sp_ipip_entry_alloc(struct mlxsw_sp *mlxsw_sp,
1170 enum mlxsw_sp_ipip_type ipipt,
1171 struct net_device *ol_dev)
1172 {
1173 const struct mlxsw_sp_ipip_ops *ipip_ops;
1174 struct mlxsw_sp_ipip_entry *ipip_entry;
1175 struct mlxsw_sp_ipip_entry *ret = NULL;
1176 int err;
1177
1178 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipipt];
1179 ipip_entry = kzalloc_obj(*ipip_entry);
1180 if (!ipip_entry)
1181 return ERR_PTR(-ENOMEM);
1182
1183 ipip_entry->ol_lb = mlxsw_sp_ipip_ol_ipip_lb_create(mlxsw_sp, ipipt,
1184 ol_dev, NULL);
1185 if (IS_ERR(ipip_entry->ol_lb)) {
1186 ret = ERR_CAST(ipip_entry->ol_lb);
1187 goto err_ol_ipip_lb_create;
1188 }
1189
1190 ipip_entry->ipipt = ipipt;
1191 ipip_entry->ol_dev = ol_dev;
1192 ipip_entry->parms = ipip_ops->parms_init(ol_dev);
1193
1194 err = ipip_ops->rem_ip_addr_set(mlxsw_sp, ipip_entry);
1195 if (err) {
1196 ret = ERR_PTR(err);
1197 goto err_rem_ip_addr_set;
1198 }
1199
1200 return ipip_entry;
1201
1202 err_rem_ip_addr_set:
1203 mlxsw_sp_rif_destroy(&ipip_entry->ol_lb->common);
1204 err_ol_ipip_lb_create:
1205 kfree(ipip_entry);
1206 return ret;
1207 }
1208
mlxsw_sp_ipip_entry_dealloc(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1209 static void mlxsw_sp_ipip_entry_dealloc(struct mlxsw_sp *mlxsw_sp,
1210 struct mlxsw_sp_ipip_entry *ipip_entry)
1211 {
1212 const struct mlxsw_sp_ipip_ops *ipip_ops =
1213 mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
1214
1215 ipip_ops->rem_ip_addr_unset(mlxsw_sp, ipip_entry);
1216 mlxsw_sp_rif_destroy(&ipip_entry->ol_lb->common);
1217 kfree(ipip_entry);
1218 }
1219
1220 static bool
mlxsw_sp_ipip_entry_saddr_matches(struct mlxsw_sp * mlxsw_sp,const enum mlxsw_sp_l3proto ul_proto,union mlxsw_sp_l3addr saddr,u32 ul_tb_id,struct mlxsw_sp_ipip_entry * ipip_entry)1221 mlxsw_sp_ipip_entry_saddr_matches(struct mlxsw_sp *mlxsw_sp,
1222 const enum mlxsw_sp_l3proto ul_proto,
1223 union mlxsw_sp_l3addr saddr,
1224 u32 ul_tb_id,
1225 struct mlxsw_sp_ipip_entry *ipip_entry)
1226 {
1227 u32 tun_ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
1228 enum mlxsw_sp_ipip_type ipipt = ipip_entry->ipipt;
1229 union mlxsw_sp_l3addr tun_saddr;
1230
1231 if (mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto != ul_proto)
1232 return false;
1233
1234 tun_saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ipip_entry->ol_dev);
1235 return tun_ul_tb_id == ul_tb_id &&
1236 mlxsw_sp_l3addr_eq(&tun_saddr, &saddr);
1237 }
1238
mlxsw_sp_ipip_decap_parsing_depth_inc(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_ipip_type ipipt)1239 static int mlxsw_sp_ipip_decap_parsing_depth_inc(struct mlxsw_sp *mlxsw_sp,
1240 enum mlxsw_sp_ipip_type ipipt)
1241 {
1242 const struct mlxsw_sp_ipip_ops *ipip_ops;
1243
1244 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipipt];
1245
1246 /* Not all tunnels require to increase the default pasing depth
1247 * (96 bytes).
1248 */
1249 if (ipip_ops->inc_parsing_depth)
1250 return mlxsw_sp_parsing_depth_inc(mlxsw_sp);
1251
1252 return 0;
1253 }
1254
mlxsw_sp_ipip_decap_parsing_depth_dec(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_ipip_type ipipt)1255 static void mlxsw_sp_ipip_decap_parsing_depth_dec(struct mlxsw_sp *mlxsw_sp,
1256 enum mlxsw_sp_ipip_type ipipt)
1257 {
1258 const struct mlxsw_sp_ipip_ops *ipip_ops =
1259 mlxsw_sp->router->ipip_ops_arr[ipipt];
1260
1261 if (ipip_ops->inc_parsing_depth)
1262 mlxsw_sp_parsing_depth_dec(mlxsw_sp);
1263 }
1264
1265 static int
mlxsw_sp_fib_entry_decap_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,struct mlxsw_sp_ipip_entry * ipip_entry)1266 mlxsw_sp_fib_entry_decap_init(struct mlxsw_sp *mlxsw_sp,
1267 struct mlxsw_sp_fib_entry *fib_entry,
1268 struct mlxsw_sp_ipip_entry *ipip_entry)
1269 {
1270 u32 tunnel_index;
1271 int err;
1272
1273 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
1274 1, &tunnel_index);
1275 if (err)
1276 return err;
1277
1278 err = mlxsw_sp_ipip_decap_parsing_depth_inc(mlxsw_sp,
1279 ipip_entry->ipipt);
1280 if (err)
1281 goto err_parsing_depth_inc;
1282
1283 ipip_entry->decap_fib_entry = fib_entry;
1284 fib_entry->decap.ipip_entry = ipip_entry;
1285 fib_entry->decap.tunnel_index = tunnel_index;
1286
1287 return 0;
1288
1289 err_parsing_depth_inc:
1290 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
1291 fib_entry->decap.tunnel_index);
1292 return err;
1293 }
1294
mlxsw_sp_fib_entry_decap_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)1295 static void mlxsw_sp_fib_entry_decap_fini(struct mlxsw_sp *mlxsw_sp,
1296 struct mlxsw_sp_fib_entry *fib_entry)
1297 {
1298 enum mlxsw_sp_ipip_type ipipt = fib_entry->decap.ipip_entry->ipipt;
1299
1300 /* Unlink this node from the IPIP entry that it's the decap entry of. */
1301 fib_entry->decap.ipip_entry->decap_fib_entry = NULL;
1302 fib_entry->decap.ipip_entry = NULL;
1303 mlxsw_sp_ipip_decap_parsing_depth_dec(mlxsw_sp, ipipt);
1304 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
1305 1, fib_entry->decap.tunnel_index);
1306 }
1307
1308 static struct mlxsw_sp_fib_node *
1309 mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib *fib, const void *addr,
1310 size_t addr_len, unsigned char prefix_len);
1311 static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
1312 struct mlxsw_sp_fib_entry *fib_entry);
1313
1314 static void
mlxsw_sp_ipip_entry_demote_decap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1315 mlxsw_sp_ipip_entry_demote_decap(struct mlxsw_sp *mlxsw_sp,
1316 struct mlxsw_sp_ipip_entry *ipip_entry)
1317 {
1318 struct mlxsw_sp_fib_entry *fib_entry = ipip_entry->decap_fib_entry;
1319
1320 mlxsw_sp_fib_entry_decap_fini(mlxsw_sp, fib_entry);
1321 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
1322
1323 mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
1324 }
1325
1326 static void
mlxsw_sp_ipip_entry_promote_decap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,struct mlxsw_sp_fib_entry * decap_fib_entry)1327 mlxsw_sp_ipip_entry_promote_decap(struct mlxsw_sp *mlxsw_sp,
1328 struct mlxsw_sp_ipip_entry *ipip_entry,
1329 struct mlxsw_sp_fib_entry *decap_fib_entry)
1330 {
1331 if (mlxsw_sp_fib_entry_decap_init(mlxsw_sp, decap_fib_entry,
1332 ipip_entry))
1333 return;
1334 decap_fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
1335
1336 if (mlxsw_sp_fib_entry_update(mlxsw_sp, decap_fib_entry))
1337 mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
1338 }
1339
1340 static struct mlxsw_sp_fib_entry *
mlxsw_sp_router_ip2me_fib_entry_find(struct mlxsw_sp * mlxsw_sp,u32 tb_id,enum mlxsw_sp_l3proto proto,const union mlxsw_sp_l3addr * addr,enum mlxsw_sp_fib_entry_type type)1341 mlxsw_sp_router_ip2me_fib_entry_find(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
1342 enum mlxsw_sp_l3proto proto,
1343 const union mlxsw_sp_l3addr *addr,
1344 enum mlxsw_sp_fib_entry_type type)
1345 {
1346 struct mlxsw_sp_fib_node *fib_node;
1347 unsigned char addr_prefix_len;
1348 struct mlxsw_sp_fib *fib;
1349 struct mlxsw_sp_vr *vr;
1350 const void *addrp;
1351 size_t addr_len;
1352 u32 addr4;
1353
1354 vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id);
1355 if (!vr)
1356 return NULL;
1357 fib = mlxsw_sp_vr_fib(vr, proto);
1358
1359 switch (proto) {
1360 case MLXSW_SP_L3_PROTO_IPV4:
1361 addr4 = be32_to_cpu(addr->addr4);
1362 addrp = &addr4;
1363 addr_len = 4;
1364 addr_prefix_len = 32;
1365 break;
1366 case MLXSW_SP_L3_PROTO_IPV6:
1367 addrp = &addr->addr6;
1368 addr_len = 16;
1369 addr_prefix_len = 128;
1370 break;
1371 default:
1372 WARN_ON(1);
1373 return NULL;
1374 }
1375
1376 fib_node = mlxsw_sp_fib_node_lookup(fib, addrp, addr_len,
1377 addr_prefix_len);
1378 if (!fib_node || fib_node->fib_entry->type != type)
1379 return NULL;
1380
1381 return fib_node->fib_entry;
1382 }
1383
1384 /* Given an IPIP entry, find the corresponding decap route. */
1385 static struct mlxsw_sp_fib_entry *
mlxsw_sp_ipip_entry_find_decap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1386 mlxsw_sp_ipip_entry_find_decap(struct mlxsw_sp *mlxsw_sp,
1387 struct mlxsw_sp_ipip_entry *ipip_entry)
1388 {
1389 static struct mlxsw_sp_fib_node *fib_node;
1390 const struct mlxsw_sp_ipip_ops *ipip_ops;
1391 unsigned char saddr_prefix_len;
1392 union mlxsw_sp_l3addr saddr;
1393 struct mlxsw_sp_fib *ul_fib;
1394 struct mlxsw_sp_vr *ul_vr;
1395 const void *saddrp;
1396 size_t saddr_len;
1397 u32 ul_tb_id;
1398 u32 saddr4;
1399
1400 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
1401
1402 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
1403 ul_vr = mlxsw_sp_vr_find(mlxsw_sp, ul_tb_id);
1404 if (!ul_vr)
1405 return NULL;
1406
1407 ul_fib = mlxsw_sp_vr_fib(ul_vr, ipip_ops->ul_proto);
1408 saddr = mlxsw_sp_ipip_netdev_saddr(ipip_ops->ul_proto,
1409 ipip_entry->ol_dev);
1410
1411 switch (ipip_ops->ul_proto) {
1412 case MLXSW_SP_L3_PROTO_IPV4:
1413 saddr4 = be32_to_cpu(saddr.addr4);
1414 saddrp = &saddr4;
1415 saddr_len = 4;
1416 saddr_prefix_len = 32;
1417 break;
1418 case MLXSW_SP_L3_PROTO_IPV6:
1419 saddrp = &saddr.addr6;
1420 saddr_len = 16;
1421 saddr_prefix_len = 128;
1422 break;
1423 default:
1424 WARN_ON(1);
1425 return NULL;
1426 }
1427
1428 fib_node = mlxsw_sp_fib_node_lookup(ul_fib, saddrp, saddr_len,
1429 saddr_prefix_len);
1430 if (!fib_node ||
1431 fib_node->fib_entry->type != MLXSW_SP_FIB_ENTRY_TYPE_TRAP)
1432 return NULL;
1433
1434 return fib_node->fib_entry;
1435 }
1436
1437 static struct mlxsw_sp_ipip_entry *
mlxsw_sp_ipip_entry_create(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_ipip_type ipipt,struct net_device * ol_dev)1438 mlxsw_sp_ipip_entry_create(struct mlxsw_sp *mlxsw_sp,
1439 enum mlxsw_sp_ipip_type ipipt,
1440 struct net_device *ol_dev)
1441 {
1442 struct mlxsw_sp_ipip_entry *ipip_entry;
1443
1444 ipip_entry = mlxsw_sp_ipip_entry_alloc(mlxsw_sp, ipipt, ol_dev);
1445 if (IS_ERR(ipip_entry))
1446 return ipip_entry;
1447
1448 list_add_tail(&ipip_entry->ipip_list_node,
1449 &mlxsw_sp->router->ipip_list);
1450
1451 return ipip_entry;
1452 }
1453
1454 static void
mlxsw_sp_ipip_entry_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1455 mlxsw_sp_ipip_entry_destroy(struct mlxsw_sp *mlxsw_sp,
1456 struct mlxsw_sp_ipip_entry *ipip_entry)
1457 {
1458 list_del(&ipip_entry->ipip_list_node);
1459 mlxsw_sp_ipip_entry_dealloc(mlxsw_sp, ipip_entry);
1460 }
1461
1462 static bool
mlxsw_sp_ipip_entry_matches_decap(struct mlxsw_sp * mlxsw_sp,const struct net_device * ul_dev,enum mlxsw_sp_l3proto ul_proto,union mlxsw_sp_l3addr ul_dip,struct mlxsw_sp_ipip_entry * ipip_entry)1463 mlxsw_sp_ipip_entry_matches_decap(struct mlxsw_sp *mlxsw_sp,
1464 const struct net_device *ul_dev,
1465 enum mlxsw_sp_l3proto ul_proto,
1466 union mlxsw_sp_l3addr ul_dip,
1467 struct mlxsw_sp_ipip_entry *ipip_entry)
1468 {
1469 u32 ul_tb_id = l3mdev_fib_table(ul_dev) ? : RT_TABLE_MAIN;
1470 enum mlxsw_sp_ipip_type ipipt = ipip_entry->ipipt;
1471
1472 if (mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto != ul_proto)
1473 return false;
1474
1475 return mlxsw_sp_ipip_entry_saddr_matches(mlxsw_sp, ul_proto, ul_dip,
1476 ul_tb_id, ipip_entry);
1477 }
1478
1479 /* Given decap parameters, find the corresponding IPIP entry. */
1480 static struct mlxsw_sp_ipip_entry *
mlxsw_sp_ipip_entry_find_by_decap(struct mlxsw_sp * mlxsw_sp,int ul_dev_ifindex,enum mlxsw_sp_l3proto ul_proto,union mlxsw_sp_l3addr ul_dip)1481 mlxsw_sp_ipip_entry_find_by_decap(struct mlxsw_sp *mlxsw_sp, int ul_dev_ifindex,
1482 enum mlxsw_sp_l3proto ul_proto,
1483 union mlxsw_sp_l3addr ul_dip)
1484 {
1485 struct mlxsw_sp_ipip_entry *ipip_entry = NULL;
1486 struct net_device *ul_dev;
1487
1488 rcu_read_lock();
1489
1490 ul_dev = dev_get_by_index_rcu(mlxsw_sp_net(mlxsw_sp), ul_dev_ifindex);
1491 if (!ul_dev)
1492 goto out_unlock;
1493
1494 list_for_each_entry(ipip_entry, &mlxsw_sp->router->ipip_list,
1495 ipip_list_node)
1496 if (mlxsw_sp_ipip_entry_matches_decap(mlxsw_sp, ul_dev,
1497 ul_proto, ul_dip,
1498 ipip_entry))
1499 goto out_unlock;
1500
1501 rcu_read_unlock();
1502
1503 return NULL;
1504
1505 out_unlock:
1506 rcu_read_unlock();
1507 return ipip_entry;
1508 }
1509
mlxsw_sp_netdev_ipip_type(const struct mlxsw_sp * mlxsw_sp,const struct net_device * dev,enum mlxsw_sp_ipip_type * p_type)1510 static bool mlxsw_sp_netdev_ipip_type(const struct mlxsw_sp *mlxsw_sp,
1511 const struct net_device *dev,
1512 enum mlxsw_sp_ipip_type *p_type)
1513 {
1514 struct mlxsw_sp_router *router = mlxsw_sp->router;
1515 const struct mlxsw_sp_ipip_ops *ipip_ops;
1516 enum mlxsw_sp_ipip_type ipipt;
1517
1518 for (ipipt = 0; ipipt < MLXSW_SP_IPIP_TYPE_MAX; ++ipipt) {
1519 ipip_ops = router->ipip_ops_arr[ipipt];
1520 if (dev->type == ipip_ops->dev_type) {
1521 if (p_type)
1522 *p_type = ipipt;
1523 return true;
1524 }
1525 }
1526 return false;
1527 }
1528
mlxsw_sp_netdev_is_ipip_ol(const struct mlxsw_sp * mlxsw_sp,const struct net_device * dev)1529 static bool mlxsw_sp_netdev_is_ipip_ol(const struct mlxsw_sp *mlxsw_sp,
1530 const struct net_device *dev)
1531 {
1532 return mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, NULL);
1533 }
1534
1535 static struct mlxsw_sp_ipip_entry *
mlxsw_sp_ipip_entry_find_by_ol_dev(struct mlxsw_sp * mlxsw_sp,const struct net_device * ol_dev)1536 mlxsw_sp_ipip_entry_find_by_ol_dev(struct mlxsw_sp *mlxsw_sp,
1537 const struct net_device *ol_dev)
1538 {
1539 struct mlxsw_sp_ipip_entry *ipip_entry;
1540
1541 list_for_each_entry(ipip_entry, &mlxsw_sp->router->ipip_list,
1542 ipip_list_node)
1543 if (ipip_entry->ol_dev == ol_dev)
1544 return ipip_entry;
1545
1546 return NULL;
1547 }
1548
1549 static struct mlxsw_sp_ipip_entry *
mlxsw_sp_ipip_entry_find_by_ul_dev(const struct mlxsw_sp * mlxsw_sp,const struct net_device * ul_dev,struct mlxsw_sp_ipip_entry * start)1550 mlxsw_sp_ipip_entry_find_by_ul_dev(const struct mlxsw_sp *mlxsw_sp,
1551 const struct net_device *ul_dev,
1552 struct mlxsw_sp_ipip_entry *start)
1553 {
1554 struct mlxsw_sp_ipip_entry *ipip_entry;
1555
1556 ipip_entry = list_prepare_entry(start, &mlxsw_sp->router->ipip_list,
1557 ipip_list_node);
1558 list_for_each_entry_continue(ipip_entry, &mlxsw_sp->router->ipip_list,
1559 ipip_list_node) {
1560 struct net_device *ol_dev = ipip_entry->ol_dev;
1561 struct net_device *ipip_ul_dev;
1562
1563 rcu_read_lock();
1564 ipip_ul_dev = mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
1565 rcu_read_unlock();
1566
1567 if (ipip_ul_dev == ul_dev)
1568 return ipip_entry;
1569 }
1570
1571 return NULL;
1572 }
1573
mlxsw_sp_netdev_is_ipip_ul(struct mlxsw_sp * mlxsw_sp,const struct net_device * dev)1574 static bool mlxsw_sp_netdev_is_ipip_ul(struct mlxsw_sp *mlxsw_sp,
1575 const struct net_device *dev)
1576 {
1577 return mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, dev, NULL);
1578 }
1579
mlxsw_sp_netdevice_ipip_can_offload(struct mlxsw_sp * mlxsw_sp,const struct net_device * ol_dev,enum mlxsw_sp_ipip_type ipipt)1580 static bool mlxsw_sp_netdevice_ipip_can_offload(struct mlxsw_sp *mlxsw_sp,
1581 const struct net_device *ol_dev,
1582 enum mlxsw_sp_ipip_type ipipt)
1583 {
1584 const struct mlxsw_sp_ipip_ops *ops
1585 = mlxsw_sp->router->ipip_ops_arr[ipipt];
1586
1587 return ops->can_offload(mlxsw_sp, ol_dev);
1588 }
1589
mlxsw_sp_netdevice_ipip_ol_reg_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev)1590 static int mlxsw_sp_netdevice_ipip_ol_reg_event(struct mlxsw_sp *mlxsw_sp,
1591 struct net_device *ol_dev)
1592 {
1593 enum mlxsw_sp_ipip_type ipipt = MLXSW_SP_IPIP_TYPE_MAX;
1594 struct mlxsw_sp_ipip_entry *ipip_entry;
1595 enum mlxsw_sp_l3proto ul_proto;
1596 union mlxsw_sp_l3addr saddr;
1597 u32 ul_tb_id;
1598
1599 mlxsw_sp_netdev_ipip_type(mlxsw_sp, ol_dev, &ipipt);
1600 if (mlxsw_sp_netdevice_ipip_can_offload(mlxsw_sp, ol_dev, ipipt)) {
1601 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ol_dev);
1602 ul_proto = mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto;
1603 saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ol_dev);
1604 if (!mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, ul_proto,
1605 saddr, ul_tb_id,
1606 NULL)) {
1607 ipip_entry = mlxsw_sp_ipip_entry_create(mlxsw_sp, ipipt,
1608 ol_dev);
1609 if (IS_ERR(ipip_entry))
1610 return PTR_ERR(ipip_entry);
1611 }
1612 }
1613
1614 return 0;
1615 }
1616
mlxsw_sp_netdevice_ipip_ol_unreg_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev)1617 static void mlxsw_sp_netdevice_ipip_ol_unreg_event(struct mlxsw_sp *mlxsw_sp,
1618 struct net_device *ol_dev)
1619 {
1620 struct mlxsw_sp_ipip_entry *ipip_entry;
1621
1622 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1623 if (ipip_entry)
1624 mlxsw_sp_ipip_entry_destroy(mlxsw_sp, ipip_entry);
1625 }
1626
1627 static void
mlxsw_sp_ipip_entry_ol_up_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1628 mlxsw_sp_ipip_entry_ol_up_event(struct mlxsw_sp *mlxsw_sp,
1629 struct mlxsw_sp_ipip_entry *ipip_entry)
1630 {
1631 struct mlxsw_sp_fib_entry *decap_fib_entry;
1632
1633 decap_fib_entry = mlxsw_sp_ipip_entry_find_decap(mlxsw_sp, ipip_entry);
1634 if (decap_fib_entry)
1635 mlxsw_sp_ipip_entry_promote_decap(mlxsw_sp, ipip_entry,
1636 decap_fib_entry);
1637 }
1638
1639 static int
mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb * lb_rif,u16 ul_vr_id,u16 ul_rif_id,bool enable)1640 mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif, u16 ul_vr_id,
1641 u16 ul_rif_id, bool enable)
1642 {
1643 struct mlxsw_sp_rif_ipip_lb_config lb_cf = lb_rif->lb_config;
1644 struct net_device *dev = mlxsw_sp_rif_dev(&lb_rif->common);
1645 enum mlxsw_reg_ritr_loopback_ipip_options ipip_options;
1646 struct mlxsw_sp_rif *rif = &lb_rif->common;
1647 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
1648 char ritr_pl[MLXSW_REG_RITR_LEN];
1649 struct in6_addr *saddr6;
1650 u32 saddr4;
1651
1652 ipip_options = MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET;
1653 switch (lb_cf.ul_protocol) {
1654 case MLXSW_SP_L3_PROTO_IPV4:
1655 saddr4 = be32_to_cpu(lb_cf.saddr.addr4);
1656 mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF,
1657 rif->rif_index, rif->vr_id, dev->mtu);
1658 mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl, lb_cf.lb_ipipt,
1659 ipip_options, ul_vr_id,
1660 ul_rif_id, saddr4,
1661 lb_cf.okey);
1662 break;
1663
1664 case MLXSW_SP_L3_PROTO_IPV6:
1665 saddr6 = &lb_cf.saddr.addr6;
1666 mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF,
1667 rif->rif_index, rif->vr_id, dev->mtu);
1668 mlxsw_reg_ritr_loopback_ipip6_pack(ritr_pl, lb_cf.lb_ipipt,
1669 ipip_options, ul_vr_id,
1670 ul_rif_id, saddr6,
1671 lb_cf.okey);
1672 break;
1673 }
1674
1675 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
1676 }
1677
mlxsw_sp_netdevice_ipip_ol_update_mtu(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev)1678 static int mlxsw_sp_netdevice_ipip_ol_update_mtu(struct mlxsw_sp *mlxsw_sp,
1679 struct net_device *ol_dev)
1680 {
1681 struct mlxsw_sp_ipip_entry *ipip_entry;
1682 struct mlxsw_sp_rif_ipip_lb *lb_rif;
1683 int err = 0;
1684
1685 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1686 if (ipip_entry) {
1687 lb_rif = ipip_entry->ol_lb;
1688 err = mlxsw_sp_rif_ipip_lb_op(lb_rif, lb_rif->ul_vr_id,
1689 lb_rif->ul_rif_id, true);
1690 if (err)
1691 goto out;
1692 lb_rif->common.mtu = ol_dev->mtu;
1693 }
1694
1695 out:
1696 return err;
1697 }
1698
mlxsw_sp_netdevice_ipip_ol_up_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev)1699 static void mlxsw_sp_netdevice_ipip_ol_up_event(struct mlxsw_sp *mlxsw_sp,
1700 struct net_device *ol_dev)
1701 {
1702 struct mlxsw_sp_ipip_entry *ipip_entry;
1703
1704 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1705 if (ipip_entry)
1706 mlxsw_sp_ipip_entry_ol_up_event(mlxsw_sp, ipip_entry);
1707 }
1708
1709 static void
mlxsw_sp_ipip_entry_ol_down_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1710 mlxsw_sp_ipip_entry_ol_down_event(struct mlxsw_sp *mlxsw_sp,
1711 struct mlxsw_sp_ipip_entry *ipip_entry)
1712 {
1713 if (ipip_entry->decap_fib_entry)
1714 mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
1715 }
1716
mlxsw_sp_netdevice_ipip_ol_down_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev)1717 static void mlxsw_sp_netdevice_ipip_ol_down_event(struct mlxsw_sp *mlxsw_sp,
1718 struct net_device *ol_dev)
1719 {
1720 struct mlxsw_sp_ipip_entry *ipip_entry;
1721
1722 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1723 if (ipip_entry)
1724 mlxsw_sp_ipip_entry_ol_down_event(mlxsw_sp, ipip_entry);
1725 }
1726
1727 static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp,
1728 struct mlxsw_sp_rif *rif);
1729
mlxsw_sp_rif_migrate_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * old_rif,struct mlxsw_sp_rif * new_rif,bool migrate_nhs)1730 static void mlxsw_sp_rif_migrate_destroy(struct mlxsw_sp *mlxsw_sp,
1731 struct mlxsw_sp_rif *old_rif,
1732 struct mlxsw_sp_rif *new_rif,
1733 bool migrate_nhs)
1734 {
1735 struct mlxsw_sp_crif *crif = old_rif->crif;
1736 struct mlxsw_sp_crif mock_crif = {};
1737
1738 if (migrate_nhs)
1739 mlxsw_sp_nexthop_rif_update(mlxsw_sp, new_rif);
1740
1741 /* Plant a mock CRIF so that destroying the old RIF doesn't unoffload
1742 * our nexthops and IPIP tunnels, and doesn't sever the crif->rif link.
1743 */
1744 mlxsw_sp_crif_init(&mock_crif, crif->key.dev);
1745 old_rif->crif = &mock_crif;
1746 mock_crif.rif = old_rif;
1747 mlxsw_sp_rif_destroy(old_rif);
1748 }
1749
1750 static int
mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,bool keep_encap,struct netlink_ext_ack * extack)1751 mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp *mlxsw_sp,
1752 struct mlxsw_sp_ipip_entry *ipip_entry,
1753 bool keep_encap,
1754 struct netlink_ext_ack *extack)
1755 {
1756 struct mlxsw_sp_rif_ipip_lb *old_lb_rif = ipip_entry->ol_lb;
1757 struct mlxsw_sp_rif_ipip_lb *new_lb_rif;
1758
1759 new_lb_rif = mlxsw_sp_ipip_ol_ipip_lb_create(mlxsw_sp,
1760 ipip_entry->ipipt,
1761 ipip_entry->ol_dev,
1762 extack);
1763 if (IS_ERR(new_lb_rif))
1764 return PTR_ERR(new_lb_rif);
1765 ipip_entry->ol_lb = new_lb_rif;
1766
1767 mlxsw_sp_rif_migrate_destroy(mlxsw_sp, &old_lb_rif->common,
1768 &new_lb_rif->common, keep_encap);
1769 return 0;
1770 }
1771
1772 /**
1773 * __mlxsw_sp_ipip_entry_update_tunnel - Update offload related to IPIP entry.
1774 * @mlxsw_sp: mlxsw_sp.
1775 * @ipip_entry: IPIP entry.
1776 * @recreate_loopback: Recreates the associated loopback RIF.
1777 * @keep_encap: Updates next hops that use the tunnel netdevice. This is only
1778 * relevant when recreate_loopback is true.
1779 * @update_nexthops: Updates next hops, keeping the current loopback RIF. This
1780 * is only relevant when recreate_loopback is false.
1781 * @extack: extack.
1782 *
1783 * Return: Non-zero value on failure.
1784 */
__mlxsw_sp_ipip_entry_update_tunnel(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,bool recreate_loopback,bool keep_encap,bool update_nexthops,struct netlink_ext_ack * extack)1785 int __mlxsw_sp_ipip_entry_update_tunnel(struct mlxsw_sp *mlxsw_sp,
1786 struct mlxsw_sp_ipip_entry *ipip_entry,
1787 bool recreate_loopback,
1788 bool keep_encap,
1789 bool update_nexthops,
1790 struct netlink_ext_ack *extack)
1791 {
1792 int err;
1793
1794 /* RIFs can't be edited, so to update loopback, we need to destroy and
1795 * recreate it. That creates a window of opportunity where RALUE and
1796 * RATR registers end up referencing a RIF that's already gone. RATRs
1797 * are handled in mlxsw_sp_ipip_entry_ol_lb_update(), and to take care
1798 * of RALUE, demote the decap route back.
1799 */
1800 if (ipip_entry->decap_fib_entry)
1801 mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
1802
1803 if (recreate_loopback) {
1804 err = mlxsw_sp_ipip_entry_ol_lb_update(mlxsw_sp, ipip_entry,
1805 keep_encap, extack);
1806 if (err)
1807 return err;
1808 } else if (update_nexthops) {
1809 mlxsw_sp_nexthop_rif_update(mlxsw_sp,
1810 &ipip_entry->ol_lb->common);
1811 }
1812
1813 if (ipip_entry->ol_dev->flags & IFF_UP)
1814 mlxsw_sp_ipip_entry_ol_up_event(mlxsw_sp, ipip_entry);
1815
1816 return 0;
1817 }
1818
mlxsw_sp_netdevice_ipip_ol_vrf_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev,struct netlink_ext_ack * extack)1819 static int mlxsw_sp_netdevice_ipip_ol_vrf_event(struct mlxsw_sp *mlxsw_sp,
1820 struct net_device *ol_dev,
1821 struct netlink_ext_ack *extack)
1822 {
1823 struct mlxsw_sp_ipip_entry *ipip_entry =
1824 mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1825
1826 if (!ipip_entry)
1827 return 0;
1828
1829 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
1830 true, false, false, extack);
1831 }
1832
1833 static int
mlxsw_sp_netdevice_ipip_ul_vrf_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,struct net_device * ul_dev,bool * demote_this,struct netlink_ext_ack * extack)1834 mlxsw_sp_netdevice_ipip_ul_vrf_event(struct mlxsw_sp *mlxsw_sp,
1835 struct mlxsw_sp_ipip_entry *ipip_entry,
1836 struct net_device *ul_dev,
1837 bool *demote_this,
1838 struct netlink_ext_ack *extack)
1839 {
1840 u32 ul_tb_id = l3mdev_fib_table(ul_dev) ? : RT_TABLE_MAIN;
1841 enum mlxsw_sp_l3proto ul_proto;
1842 union mlxsw_sp_l3addr saddr;
1843
1844 /* Moving underlay to a different VRF might cause local address
1845 * conflict, and the conflicting tunnels need to be demoted.
1846 */
1847 ul_proto = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt]->ul_proto;
1848 saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ipip_entry->ol_dev);
1849 if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, ul_proto,
1850 saddr, ul_tb_id,
1851 ipip_entry)) {
1852 *demote_this = true;
1853 return 0;
1854 }
1855
1856 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
1857 true, true, false, extack);
1858 }
1859
1860 static int
mlxsw_sp_netdevice_ipip_ul_up_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,struct net_device * ul_dev)1861 mlxsw_sp_netdevice_ipip_ul_up_event(struct mlxsw_sp *mlxsw_sp,
1862 struct mlxsw_sp_ipip_entry *ipip_entry,
1863 struct net_device *ul_dev)
1864 {
1865 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
1866 false, false, true, NULL);
1867 }
1868
1869 static int
mlxsw_sp_netdevice_ipip_ul_down_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,struct net_device * ul_dev)1870 mlxsw_sp_netdevice_ipip_ul_down_event(struct mlxsw_sp *mlxsw_sp,
1871 struct mlxsw_sp_ipip_entry *ipip_entry,
1872 struct net_device *ul_dev)
1873 {
1874 /* A down underlay device causes encapsulated packets to not be
1875 * forwarded, but decap still works. So refresh next hops without
1876 * touching anything else.
1877 */
1878 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
1879 false, false, true, NULL);
1880 }
1881
1882 static int
mlxsw_sp_netdevice_ipip_ol_change_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev,struct netlink_ext_ack * extack)1883 mlxsw_sp_netdevice_ipip_ol_change_event(struct mlxsw_sp *mlxsw_sp,
1884 struct net_device *ol_dev,
1885 struct netlink_ext_ack *extack)
1886 {
1887 const struct mlxsw_sp_ipip_ops *ipip_ops;
1888 struct mlxsw_sp_ipip_entry *ipip_entry;
1889 int err;
1890
1891 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1892 if (!ipip_entry)
1893 /* A change might make a tunnel eligible for offloading, but
1894 * that is currently not implemented. What falls to slow path
1895 * stays there.
1896 */
1897 return 0;
1898
1899 /* A change might make a tunnel not eligible for offloading. */
1900 if (!mlxsw_sp_netdevice_ipip_can_offload(mlxsw_sp, ol_dev,
1901 ipip_entry->ipipt)) {
1902 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
1903 return 0;
1904 }
1905
1906 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
1907 err = ipip_ops->ol_netdev_change(mlxsw_sp, ipip_entry, extack);
1908 return err;
1909 }
1910
mlxsw_sp_ipip_entry_demote_tunnel(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry)1911 void mlxsw_sp_ipip_entry_demote_tunnel(struct mlxsw_sp *mlxsw_sp,
1912 struct mlxsw_sp_ipip_entry *ipip_entry)
1913 {
1914 struct net_device *ol_dev = ipip_entry->ol_dev;
1915
1916 if (ol_dev->flags & IFF_UP)
1917 mlxsw_sp_ipip_entry_ol_down_event(mlxsw_sp, ipip_entry);
1918 mlxsw_sp_ipip_entry_destroy(mlxsw_sp, ipip_entry);
1919 }
1920
1921 /* The configuration where several tunnels have the same local address in the
1922 * same underlay table needs special treatment in the HW. That is currently not
1923 * implemented in the driver. This function finds and demotes the first tunnel
1924 * with a given source address, except the one passed in the argument
1925 * `except'.
1926 */
1927 bool
mlxsw_sp_ipip_demote_tunnel_by_saddr(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_l3proto ul_proto,union mlxsw_sp_l3addr saddr,u32 ul_tb_id,const struct mlxsw_sp_ipip_entry * except)1928 mlxsw_sp_ipip_demote_tunnel_by_saddr(struct mlxsw_sp *mlxsw_sp,
1929 enum mlxsw_sp_l3proto ul_proto,
1930 union mlxsw_sp_l3addr saddr,
1931 u32 ul_tb_id,
1932 const struct mlxsw_sp_ipip_entry *except)
1933 {
1934 struct mlxsw_sp_ipip_entry *ipip_entry, *tmp;
1935
1936 list_for_each_entry_safe(ipip_entry, tmp, &mlxsw_sp->router->ipip_list,
1937 ipip_list_node) {
1938 if (ipip_entry != except &&
1939 mlxsw_sp_ipip_entry_saddr_matches(mlxsw_sp, ul_proto, saddr,
1940 ul_tb_id, ipip_entry)) {
1941 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
1942 return true;
1943 }
1944 }
1945
1946 return false;
1947 }
1948
mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(struct mlxsw_sp * mlxsw_sp,struct net_device * ul_dev)1949 static void mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(struct mlxsw_sp *mlxsw_sp,
1950 struct net_device *ul_dev)
1951 {
1952 struct mlxsw_sp_ipip_entry *ipip_entry, *tmp;
1953
1954 list_for_each_entry_safe(ipip_entry, tmp, &mlxsw_sp->router->ipip_list,
1955 ipip_list_node) {
1956 struct net_device *ol_dev = ipip_entry->ol_dev;
1957 struct net_device *ipip_ul_dev;
1958
1959 rcu_read_lock();
1960 ipip_ul_dev = mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
1961 rcu_read_unlock();
1962 if (ipip_ul_dev == ul_dev)
1963 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
1964 }
1965 }
1966
mlxsw_sp_netdevice_ipip_ol_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ol_dev,unsigned long event,struct netdev_notifier_info * info)1967 static int mlxsw_sp_netdevice_ipip_ol_event(struct mlxsw_sp *mlxsw_sp,
1968 struct net_device *ol_dev,
1969 unsigned long event,
1970 struct netdev_notifier_info *info)
1971 {
1972 struct netdev_notifier_changeupper_info *chup;
1973 struct netlink_ext_ack *extack;
1974 int err = 0;
1975
1976 switch (event) {
1977 case NETDEV_REGISTER:
1978 err = mlxsw_sp_netdevice_ipip_ol_reg_event(mlxsw_sp, ol_dev);
1979 break;
1980 case NETDEV_UNREGISTER:
1981 mlxsw_sp_netdevice_ipip_ol_unreg_event(mlxsw_sp, ol_dev);
1982 break;
1983 case NETDEV_UP:
1984 mlxsw_sp_netdevice_ipip_ol_up_event(mlxsw_sp, ol_dev);
1985 break;
1986 case NETDEV_DOWN:
1987 mlxsw_sp_netdevice_ipip_ol_down_event(mlxsw_sp, ol_dev);
1988 break;
1989 case NETDEV_CHANGEUPPER:
1990 chup = container_of(info, typeof(*chup), info);
1991 extack = info->extack;
1992 if (netif_is_l3_master(chup->upper_dev))
1993 err = mlxsw_sp_netdevice_ipip_ol_vrf_event(mlxsw_sp,
1994 ol_dev,
1995 extack);
1996 break;
1997 case NETDEV_CHANGE:
1998 extack = info->extack;
1999 err = mlxsw_sp_netdevice_ipip_ol_change_event(mlxsw_sp,
2000 ol_dev, extack);
2001 break;
2002 case NETDEV_CHANGEMTU:
2003 err = mlxsw_sp_netdevice_ipip_ol_update_mtu(mlxsw_sp, ol_dev);
2004 break;
2005 }
2006 return err;
2007 }
2008
2009 static int
__mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipip_entry * ipip_entry,struct net_device * ul_dev,bool * demote_this,unsigned long event,struct netdev_notifier_info * info)2010 __mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
2011 struct mlxsw_sp_ipip_entry *ipip_entry,
2012 struct net_device *ul_dev,
2013 bool *demote_this,
2014 unsigned long event,
2015 struct netdev_notifier_info *info)
2016 {
2017 struct netdev_notifier_changeupper_info *chup;
2018 struct netlink_ext_ack *extack;
2019
2020 switch (event) {
2021 case NETDEV_CHANGEUPPER:
2022 chup = container_of(info, typeof(*chup), info);
2023 extack = info->extack;
2024 if (netif_is_l3_master(chup->upper_dev))
2025 return mlxsw_sp_netdevice_ipip_ul_vrf_event(mlxsw_sp,
2026 ipip_entry,
2027 ul_dev,
2028 demote_this,
2029 extack);
2030 break;
2031
2032 case NETDEV_UP:
2033 return mlxsw_sp_netdevice_ipip_ul_up_event(mlxsw_sp, ipip_entry,
2034 ul_dev);
2035 case NETDEV_DOWN:
2036 return mlxsw_sp_netdevice_ipip_ul_down_event(mlxsw_sp,
2037 ipip_entry,
2038 ul_dev);
2039 }
2040 return 0;
2041 }
2042
2043 static int
mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp * mlxsw_sp,struct net_device * ul_dev,unsigned long event,struct netdev_notifier_info * info)2044 mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
2045 struct net_device *ul_dev,
2046 unsigned long event,
2047 struct netdev_notifier_info *info)
2048 {
2049 struct mlxsw_sp_ipip_entry *ipip_entry = NULL;
2050 int err;
2051
2052 while ((ipip_entry = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp,
2053 ul_dev,
2054 ipip_entry))) {
2055 struct mlxsw_sp_ipip_entry *prev;
2056 bool demote_this = false;
2057
2058 err = __mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, ipip_entry,
2059 ul_dev, &demote_this,
2060 event, info);
2061 if (err) {
2062 mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(mlxsw_sp,
2063 ul_dev);
2064 return err;
2065 }
2066
2067 if (demote_this) {
2068 if (list_is_first(&ipip_entry->ipip_list_node,
2069 &mlxsw_sp->router->ipip_list))
2070 prev = NULL;
2071 else
2072 /* This can't be cached from previous iteration,
2073 * because that entry could be gone now.
2074 */
2075 prev = list_prev_entry(ipip_entry,
2076 ipip_list_node);
2077 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
2078 ipip_entry = prev;
2079 }
2080 }
2081
2082 return 0;
2083 }
2084
mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp * mlxsw_sp,u32 ul_tb_id,enum mlxsw_sp_l3proto ul_proto,const union mlxsw_sp_l3addr * ul_sip,u32 tunnel_index)2085 int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
2086 enum mlxsw_sp_l3proto ul_proto,
2087 const union mlxsw_sp_l3addr *ul_sip,
2088 u32 tunnel_index)
2089 {
2090 enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
2091 struct mlxsw_sp_router *router = mlxsw_sp->router;
2092 struct mlxsw_sp_fib_entry *fib_entry;
2093 int err = 0;
2094
2095 mutex_lock(&mlxsw_sp->router->lock);
2096
2097 if (WARN_ON_ONCE(router->nve_decap_config.valid)) {
2098 err = -EINVAL;
2099 goto out;
2100 }
2101
2102 router->nve_decap_config.ul_tb_id = ul_tb_id;
2103 router->nve_decap_config.tunnel_index = tunnel_index;
2104 router->nve_decap_config.ul_proto = ul_proto;
2105 router->nve_decap_config.ul_sip = *ul_sip;
2106 router->nve_decap_config.valid = true;
2107
2108 /* It is valid to create a tunnel with a local IP and only later
2109 * assign this IP address to a local interface
2110 */
2111 fib_entry = mlxsw_sp_router_ip2me_fib_entry_find(mlxsw_sp, ul_tb_id,
2112 ul_proto, ul_sip,
2113 type);
2114 if (!fib_entry)
2115 goto out;
2116
2117 fib_entry->decap.tunnel_index = tunnel_index;
2118 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP;
2119
2120 err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
2121 if (err)
2122 goto err_fib_entry_update;
2123
2124 goto out;
2125
2126 err_fib_entry_update:
2127 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
2128 mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
2129 out:
2130 mutex_unlock(&mlxsw_sp->router->lock);
2131 return err;
2132 }
2133
mlxsw_sp_router_nve_demote_decap(struct mlxsw_sp * mlxsw_sp,u32 ul_tb_id,enum mlxsw_sp_l3proto ul_proto,const union mlxsw_sp_l3addr * ul_sip)2134 void mlxsw_sp_router_nve_demote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
2135 enum mlxsw_sp_l3proto ul_proto,
2136 const union mlxsw_sp_l3addr *ul_sip)
2137 {
2138 enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP;
2139 struct mlxsw_sp_router *router = mlxsw_sp->router;
2140 struct mlxsw_sp_fib_entry *fib_entry;
2141
2142 mutex_lock(&mlxsw_sp->router->lock);
2143
2144 if (WARN_ON_ONCE(!router->nve_decap_config.valid))
2145 goto out;
2146
2147 router->nve_decap_config.valid = false;
2148
2149 fib_entry = mlxsw_sp_router_ip2me_fib_entry_find(mlxsw_sp, ul_tb_id,
2150 ul_proto, ul_sip,
2151 type);
2152 if (!fib_entry)
2153 goto out;
2154
2155 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
2156 mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
2157 out:
2158 mutex_unlock(&mlxsw_sp->router->lock);
2159 }
2160
mlxsw_sp_router_nve_is_decap(struct mlxsw_sp * mlxsw_sp,u32 ul_tb_id,enum mlxsw_sp_l3proto ul_proto,const union mlxsw_sp_l3addr * ul_sip)2161 static bool mlxsw_sp_router_nve_is_decap(struct mlxsw_sp *mlxsw_sp,
2162 u32 ul_tb_id,
2163 enum mlxsw_sp_l3proto ul_proto,
2164 const union mlxsw_sp_l3addr *ul_sip)
2165 {
2166 struct mlxsw_sp_router *router = mlxsw_sp->router;
2167
2168 return router->nve_decap_config.valid &&
2169 router->nve_decap_config.ul_tb_id == ul_tb_id &&
2170 router->nve_decap_config.ul_proto == ul_proto &&
2171 !memcmp(&router->nve_decap_config.ul_sip, ul_sip,
2172 sizeof(*ul_sip));
2173 }
2174
2175 struct mlxsw_sp_neigh_key {
2176 struct neighbour *n;
2177 };
2178
2179 struct mlxsw_sp_neigh_entry {
2180 struct list_head rif_list_node;
2181 struct rhash_head ht_node;
2182 struct mlxsw_sp_neigh_key key;
2183 u16 rif;
2184 bool connected;
2185 unsigned char ha[ETH_ALEN];
2186 struct list_head nexthop_list; /* list of nexthops using
2187 * this neigh entry
2188 */
2189 struct list_head nexthop_neighs_list_node;
2190 unsigned int counter_index;
2191 bool counter_valid;
2192 };
2193
2194 static const struct rhashtable_params mlxsw_sp_neigh_ht_params = {
2195 .key_offset = offsetof(struct mlxsw_sp_neigh_entry, key),
2196 .head_offset = offsetof(struct mlxsw_sp_neigh_entry, ht_node),
2197 .key_len = sizeof(struct mlxsw_sp_neigh_key),
2198 };
2199
2200 struct mlxsw_sp_neigh_entry *
mlxsw_sp_rif_neigh_next(struct mlxsw_sp_rif * rif,struct mlxsw_sp_neigh_entry * neigh_entry)2201 mlxsw_sp_rif_neigh_next(struct mlxsw_sp_rif *rif,
2202 struct mlxsw_sp_neigh_entry *neigh_entry)
2203 {
2204 if (!neigh_entry) {
2205 if (list_empty(&rif->neigh_list))
2206 return NULL;
2207 else
2208 return list_first_entry(&rif->neigh_list,
2209 typeof(*neigh_entry),
2210 rif_list_node);
2211 }
2212 if (list_is_last(&neigh_entry->rif_list_node, &rif->neigh_list))
2213 return NULL;
2214 return list_next_entry(neigh_entry, rif_list_node);
2215 }
2216
mlxsw_sp_neigh_entry_type(struct mlxsw_sp_neigh_entry * neigh_entry)2217 int mlxsw_sp_neigh_entry_type(struct mlxsw_sp_neigh_entry *neigh_entry)
2218 {
2219 return neigh_entry->key.n->tbl->family;
2220 }
2221
2222 unsigned char *
mlxsw_sp_neigh_entry_ha(struct mlxsw_sp_neigh_entry * neigh_entry)2223 mlxsw_sp_neigh_entry_ha(struct mlxsw_sp_neigh_entry *neigh_entry)
2224 {
2225 return neigh_entry->ha;
2226 }
2227
mlxsw_sp_neigh4_entry_dip(struct mlxsw_sp_neigh_entry * neigh_entry)2228 u32 mlxsw_sp_neigh4_entry_dip(struct mlxsw_sp_neigh_entry *neigh_entry)
2229 {
2230 struct neighbour *n;
2231
2232 n = neigh_entry->key.n;
2233 return ntohl(*((__be32 *) n->primary_key));
2234 }
2235
2236 struct in6_addr *
mlxsw_sp_neigh6_entry_dip(struct mlxsw_sp_neigh_entry * neigh_entry)2237 mlxsw_sp_neigh6_entry_dip(struct mlxsw_sp_neigh_entry *neigh_entry)
2238 {
2239 struct neighbour *n;
2240
2241 n = neigh_entry->key.n;
2242 return (struct in6_addr *) &n->primary_key;
2243 }
2244
mlxsw_sp_neigh_counter_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,u64 * p_counter)2245 int mlxsw_sp_neigh_counter_get(struct mlxsw_sp *mlxsw_sp,
2246 struct mlxsw_sp_neigh_entry *neigh_entry,
2247 u64 *p_counter)
2248 {
2249 if (!neigh_entry->counter_valid)
2250 return -EINVAL;
2251
2252 return mlxsw_sp_flow_counter_get(mlxsw_sp, neigh_entry->counter_index,
2253 false, p_counter, NULL);
2254 }
2255
2256 static struct mlxsw_sp_neigh_entry *
mlxsw_sp_neigh_entry_alloc(struct mlxsw_sp * mlxsw_sp,struct neighbour * n,u16 rif)2257 mlxsw_sp_neigh_entry_alloc(struct mlxsw_sp *mlxsw_sp, struct neighbour *n,
2258 u16 rif)
2259 {
2260 struct mlxsw_sp_neigh_entry *neigh_entry;
2261
2262 neigh_entry = kzalloc_obj(*neigh_entry);
2263 if (!neigh_entry)
2264 return NULL;
2265
2266 neigh_hold(n);
2267 neigh_entry->key.n = n;
2268 neigh_entry->rif = rif;
2269 INIT_LIST_HEAD(&neigh_entry->nexthop_list);
2270
2271 return neigh_entry;
2272 }
2273
mlxsw_sp_neigh_entry_free(struct mlxsw_sp_neigh_entry * neigh_entry)2274 static void mlxsw_sp_neigh_entry_free(struct mlxsw_sp_neigh_entry *neigh_entry)
2275 {
2276 neigh_release(neigh_entry->key.n);
2277 kfree(neigh_entry);
2278 }
2279
2280 static int
mlxsw_sp_neigh_entry_insert(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)2281 mlxsw_sp_neigh_entry_insert(struct mlxsw_sp *mlxsw_sp,
2282 struct mlxsw_sp_neigh_entry *neigh_entry)
2283 {
2284 return rhashtable_insert_fast(&mlxsw_sp->router->neigh_ht,
2285 &neigh_entry->ht_node,
2286 mlxsw_sp_neigh_ht_params);
2287 }
2288
2289 static void
mlxsw_sp_neigh_entry_remove(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)2290 mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp,
2291 struct mlxsw_sp_neigh_entry *neigh_entry)
2292 {
2293 rhashtable_remove_fast(&mlxsw_sp->router->neigh_ht,
2294 &neigh_entry->ht_node,
2295 mlxsw_sp_neigh_ht_params);
2296 }
2297
2298 static bool
mlxsw_sp_neigh_counter_should_alloc(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)2299 mlxsw_sp_neigh_counter_should_alloc(struct mlxsw_sp *mlxsw_sp,
2300 struct mlxsw_sp_neigh_entry *neigh_entry)
2301 {
2302 struct devlink *devlink;
2303 const char *table_name;
2304
2305 switch (mlxsw_sp_neigh_entry_type(neigh_entry)) {
2306 case AF_INET:
2307 table_name = MLXSW_SP_DPIPE_TABLE_NAME_HOST4;
2308 break;
2309 case AF_INET6:
2310 table_name = MLXSW_SP_DPIPE_TABLE_NAME_HOST6;
2311 break;
2312 default:
2313 WARN_ON(1);
2314 return false;
2315 }
2316
2317 devlink = priv_to_devlink(mlxsw_sp->core);
2318 return devlink_dpipe_table_counter_enabled(devlink, table_name);
2319 }
2320
2321 static void
mlxsw_sp_neigh_counter_alloc(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)2322 mlxsw_sp_neigh_counter_alloc(struct mlxsw_sp *mlxsw_sp,
2323 struct mlxsw_sp_neigh_entry *neigh_entry)
2324 {
2325 if (!mlxsw_sp_neigh_counter_should_alloc(mlxsw_sp, neigh_entry))
2326 return;
2327
2328 if (mlxsw_sp_flow_counter_alloc(mlxsw_sp, &neigh_entry->counter_index))
2329 return;
2330
2331 neigh_entry->counter_valid = true;
2332 }
2333
2334 static void
mlxsw_sp_neigh_counter_free(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)2335 mlxsw_sp_neigh_counter_free(struct mlxsw_sp *mlxsw_sp,
2336 struct mlxsw_sp_neigh_entry *neigh_entry)
2337 {
2338 if (!neigh_entry->counter_valid)
2339 return;
2340 mlxsw_sp_flow_counter_free(mlxsw_sp,
2341 neigh_entry->counter_index);
2342 neigh_entry->counter_valid = false;
2343 }
2344
2345 static struct mlxsw_sp_neigh_entry *
mlxsw_sp_neigh_entry_create(struct mlxsw_sp * mlxsw_sp,struct neighbour * n)2346 mlxsw_sp_neigh_entry_create(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
2347 {
2348 struct mlxsw_sp_neigh_entry *neigh_entry;
2349 struct mlxsw_sp_rif *rif;
2350 int err;
2351
2352 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, n->dev);
2353 if (!rif)
2354 return ERR_PTR(-EINVAL);
2355
2356 neigh_entry = mlxsw_sp_neigh_entry_alloc(mlxsw_sp, n, rif->rif_index);
2357 if (!neigh_entry)
2358 return ERR_PTR(-ENOMEM);
2359
2360 err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
2361 if (err)
2362 goto err_neigh_entry_insert;
2363
2364 mlxsw_sp_neigh_counter_alloc(mlxsw_sp, neigh_entry);
2365 atomic_inc(&mlxsw_sp->router->neighs_update.neigh_count);
2366 list_add(&neigh_entry->rif_list_node, &rif->neigh_list);
2367
2368 return neigh_entry;
2369
2370 err_neigh_entry_insert:
2371 mlxsw_sp_neigh_entry_free(neigh_entry);
2372 return ERR_PTR(err);
2373 }
2374
2375 static void
mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)2376 mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp *mlxsw_sp,
2377 struct mlxsw_sp_neigh_entry *neigh_entry)
2378 {
2379 list_del(&neigh_entry->rif_list_node);
2380 atomic_dec(&mlxsw_sp->router->neighs_update.neigh_count);
2381 mlxsw_sp_neigh_counter_free(mlxsw_sp, neigh_entry);
2382 mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
2383 mlxsw_sp_neigh_entry_free(neigh_entry);
2384 }
2385
2386 static struct mlxsw_sp_neigh_entry *
mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp * mlxsw_sp,struct neighbour * n)2387 mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
2388 {
2389 struct mlxsw_sp_neigh_key key;
2390
2391 key.n = n;
2392 return rhashtable_lookup_fast(&mlxsw_sp->router->neigh_ht,
2393 &key, mlxsw_sp_neigh_ht_params);
2394 }
2395
2396 static void
mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp * mlxsw_sp)2397 mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp *mlxsw_sp)
2398 {
2399 unsigned long interval;
2400
2401 #if IS_ENABLED(CONFIG_IPV6)
2402 interval = min_t(unsigned long,
2403 NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME),
2404 NEIGH_VAR(&nd_tbl.parms, DELAY_PROBE_TIME));
2405 #else
2406 interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME);
2407 #endif
2408 mlxsw_sp->router->neighs_update.interval = jiffies_to_msecs(interval);
2409 }
2410
mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int ent_index)2411 static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
2412 char *rauhtd_pl,
2413 int ent_index)
2414 {
2415 u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
2416 struct net_device *dev;
2417 struct neighbour *n;
2418 __be32 dipn;
2419 u32 dip;
2420 u16 rif;
2421
2422 mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip);
2423
2424 if (WARN_ON_ONCE(rif >= max_rifs))
2425 return;
2426 if (!mlxsw_sp->router->rifs[rif]) {
2427 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
2428 return;
2429 }
2430
2431 dipn = htonl(dip);
2432 dev = mlxsw_sp_rif_dev(mlxsw_sp->router->rifs[rif]);
2433 n = neigh_lookup(&arp_tbl, &dipn, dev);
2434 if (!n)
2435 return;
2436
2437 netdev_dbg(dev, "Updating neighbour with IP=%pI4h\n", &dip);
2438 neigh_event_send(n, NULL);
2439 neigh_release(n);
2440 }
2441
2442 #if IS_ENABLED(CONFIG_IPV6)
mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int rec_index)2443 static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
2444 char *rauhtd_pl,
2445 int rec_index)
2446 {
2447 struct net_device *dev;
2448 struct neighbour *n;
2449 struct in6_addr dip;
2450 u16 rif;
2451
2452 mlxsw_reg_rauhtd_ent_ipv6_unpack(rauhtd_pl, rec_index, &rif,
2453 (char *) &dip);
2454
2455 if (!mlxsw_sp->router->rifs[rif]) {
2456 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
2457 return;
2458 }
2459
2460 dev = mlxsw_sp_rif_dev(mlxsw_sp->router->rifs[rif]);
2461 n = neigh_lookup(&nd_tbl, &dip, dev);
2462 if (!n)
2463 return;
2464
2465 netdev_dbg(dev, "Updating neighbour with IP=%pI6c\n", &dip);
2466 neigh_event_send(n, NULL);
2467 neigh_release(n);
2468 }
2469 #else
mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int rec_index)2470 static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
2471 char *rauhtd_pl,
2472 int rec_index)
2473 {
2474 }
2475 #endif
2476
mlxsw_sp_router_neigh_rec_ipv4_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int rec_index)2477 static void mlxsw_sp_router_neigh_rec_ipv4_process(struct mlxsw_sp *mlxsw_sp,
2478 char *rauhtd_pl,
2479 int rec_index)
2480 {
2481 u8 num_entries;
2482 int i;
2483
2484 num_entries = mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl,
2485 rec_index);
2486 /* Hardware starts counting at 0, so add 1. */
2487 num_entries++;
2488
2489 /* Each record consists of several neighbour entries. */
2490 for (i = 0; i < num_entries; i++) {
2491 int ent_index;
2492
2493 ent_index = rec_index * MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC + i;
2494 mlxsw_sp_router_neigh_ent_ipv4_process(mlxsw_sp, rauhtd_pl,
2495 ent_index);
2496 }
2497
2498 }
2499
mlxsw_sp_router_neigh_rec_ipv6_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int rec_index)2500 static void mlxsw_sp_router_neigh_rec_ipv6_process(struct mlxsw_sp *mlxsw_sp,
2501 char *rauhtd_pl,
2502 int rec_index)
2503 {
2504 /* One record contains one entry. */
2505 mlxsw_sp_router_neigh_ent_ipv6_process(mlxsw_sp, rauhtd_pl,
2506 rec_index);
2507 }
2508
mlxsw_sp_router_neigh_rec_process(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,int rec_index)2509 static void mlxsw_sp_router_neigh_rec_process(struct mlxsw_sp *mlxsw_sp,
2510 char *rauhtd_pl, int rec_index)
2511 {
2512 switch (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl, rec_index)) {
2513 case MLXSW_REG_RAUHTD_TYPE_IPV4:
2514 mlxsw_sp_router_neigh_rec_ipv4_process(mlxsw_sp, rauhtd_pl,
2515 rec_index);
2516 break;
2517 case MLXSW_REG_RAUHTD_TYPE_IPV6:
2518 mlxsw_sp_router_neigh_rec_ipv6_process(mlxsw_sp, rauhtd_pl,
2519 rec_index);
2520 break;
2521 }
2522 }
2523
mlxsw_sp_router_rauhtd_is_full(char * rauhtd_pl)2524 static bool mlxsw_sp_router_rauhtd_is_full(char *rauhtd_pl)
2525 {
2526 u8 num_rec, last_rec_index, num_entries;
2527
2528 num_rec = mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl);
2529 last_rec_index = num_rec - 1;
2530
2531 if (num_rec < MLXSW_REG_RAUHTD_REC_MAX_NUM)
2532 return false;
2533 if (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl, last_rec_index) ==
2534 MLXSW_REG_RAUHTD_TYPE_IPV6)
2535 return true;
2536
2537 num_entries = mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl,
2538 last_rec_index);
2539 if (++num_entries == MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC)
2540 return true;
2541 return false;
2542 }
2543
2544 static int
__mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp * mlxsw_sp,char * rauhtd_pl,enum mlxsw_reg_rauhtd_type type)2545 __mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp,
2546 char *rauhtd_pl,
2547 enum mlxsw_reg_rauhtd_type type)
2548 {
2549 int i, num_rec;
2550 int err;
2551
2552 /* Ensure the RIF we read from the device does not change mid-dump. */
2553 mutex_lock(&mlxsw_sp->router->lock);
2554 do {
2555 mlxsw_reg_rauhtd_pack(rauhtd_pl, type);
2556 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(rauhtd),
2557 rauhtd_pl);
2558 if (err) {
2559 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to dump neighbour table\n");
2560 break;
2561 }
2562 num_rec = mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl);
2563 for (i = 0; i < num_rec; i++)
2564 mlxsw_sp_router_neigh_rec_process(mlxsw_sp, rauhtd_pl,
2565 i);
2566 } while (mlxsw_sp_router_rauhtd_is_full(rauhtd_pl));
2567 mutex_unlock(&mlxsw_sp->router->lock);
2568
2569 return err;
2570 }
2571
mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp * mlxsw_sp)2572 static int mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp)
2573 {
2574 enum mlxsw_reg_rauhtd_type type;
2575 char *rauhtd_pl;
2576 int err;
2577
2578 if (!atomic_read(&mlxsw_sp->router->neighs_update.neigh_count))
2579 return 0;
2580
2581 rauhtd_pl = kmalloc(MLXSW_REG_RAUHTD_LEN, GFP_KERNEL);
2582 if (!rauhtd_pl)
2583 return -ENOMEM;
2584
2585 type = MLXSW_REG_RAUHTD_TYPE_IPV4;
2586 err = __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp, rauhtd_pl, type);
2587 if (err)
2588 goto out;
2589
2590 type = MLXSW_REG_RAUHTD_TYPE_IPV6;
2591 err = __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp, rauhtd_pl, type);
2592 out:
2593 kfree(rauhtd_pl);
2594 return err;
2595 }
2596
mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp * mlxsw_sp)2597 static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp)
2598 {
2599 struct mlxsw_sp_neigh_entry *neigh_entry;
2600
2601 mutex_lock(&mlxsw_sp->router->lock);
2602 list_for_each_entry(neigh_entry, &mlxsw_sp->router->nexthop_neighs_list,
2603 nexthop_neighs_list_node)
2604 /* If this neigh have nexthops, make the kernel think this neigh
2605 * is active regardless of the traffic.
2606 */
2607 neigh_event_send(neigh_entry->key.n, NULL);
2608 mutex_unlock(&mlxsw_sp->router->lock);
2609 }
2610
2611 static void
mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp * mlxsw_sp)2612 mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp *mlxsw_sp)
2613 {
2614 unsigned long interval = mlxsw_sp->router->neighs_update.interval;
2615
2616 mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw,
2617 msecs_to_jiffies(interval));
2618 }
2619
mlxsw_sp_router_neighs_update_work(struct work_struct * work)2620 static void mlxsw_sp_router_neighs_update_work(struct work_struct *work)
2621 {
2622 struct mlxsw_sp_router *router;
2623 int err;
2624
2625 router = container_of(work, struct mlxsw_sp_router,
2626 neighs_update.dw.work);
2627 err = mlxsw_sp_router_neighs_update_rauhtd(router->mlxsw_sp);
2628 if (err)
2629 dev_err(router->mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity");
2630
2631 mlxsw_sp_router_neighs_update_nh(router->mlxsw_sp);
2632
2633 mlxsw_sp_router_neighs_update_work_schedule(router->mlxsw_sp);
2634 }
2635
mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct * work)2636 static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work)
2637 {
2638 struct mlxsw_sp_neigh_entry *neigh_entry;
2639 struct mlxsw_sp_router *router;
2640
2641 router = container_of(work, struct mlxsw_sp_router,
2642 nexthop_probe_dw.work);
2643 /* Iterate over nexthop neighbours, find those who are unresolved and
2644 * send arp on them. This solves the chicken-egg problem when
2645 * the nexthop wouldn't get offloaded until the neighbor is resolved
2646 * but it wouldn't get resolved ever in case traffic is flowing in HW
2647 * using different nexthop.
2648 */
2649 mutex_lock(&router->lock);
2650 list_for_each_entry(neigh_entry, &router->nexthop_neighs_list,
2651 nexthop_neighs_list_node)
2652 if (!neigh_entry->connected)
2653 neigh_event_send(neigh_entry->key.n, NULL);
2654 mutex_unlock(&router->lock);
2655
2656 mlxsw_core_schedule_dw(&router->nexthop_probe_dw,
2657 MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL);
2658 }
2659
2660 static void
2661 mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
2662 struct mlxsw_sp_neigh_entry *neigh_entry,
2663 bool removing, bool dead);
2664
mlxsw_sp_rauht_op(bool adding)2665 static enum mlxsw_reg_rauht_op mlxsw_sp_rauht_op(bool adding)
2666 {
2667 return adding ? MLXSW_REG_RAUHT_OP_WRITE_ADD :
2668 MLXSW_REG_RAUHT_OP_WRITE_DELETE;
2669 }
2670
2671 static int
mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,enum mlxsw_reg_rauht_op op)2672 mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp *mlxsw_sp,
2673 struct mlxsw_sp_neigh_entry *neigh_entry,
2674 enum mlxsw_reg_rauht_op op)
2675 {
2676 struct neighbour *n = neigh_entry->key.n;
2677 u32 dip = ntohl(*((__be32 *) n->primary_key));
2678 char rauht_pl[MLXSW_REG_RAUHT_LEN];
2679
2680 mlxsw_reg_rauht_pack4(rauht_pl, op, neigh_entry->rif, neigh_entry->ha,
2681 dip);
2682 if (neigh_entry->counter_valid)
2683 mlxsw_reg_rauht_pack_counter(rauht_pl,
2684 neigh_entry->counter_index);
2685 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
2686 }
2687
2688 static int
mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,enum mlxsw_reg_rauht_op op)2689 mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp *mlxsw_sp,
2690 struct mlxsw_sp_neigh_entry *neigh_entry,
2691 enum mlxsw_reg_rauht_op op)
2692 {
2693 struct neighbour *n = neigh_entry->key.n;
2694 char rauht_pl[MLXSW_REG_RAUHT_LEN];
2695 const char *dip = n->primary_key;
2696
2697 mlxsw_reg_rauht_pack6(rauht_pl, op, neigh_entry->rif, neigh_entry->ha,
2698 dip);
2699 if (neigh_entry->counter_valid)
2700 mlxsw_reg_rauht_pack_counter(rauht_pl,
2701 neigh_entry->counter_index);
2702 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
2703 }
2704
mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry * neigh_entry)2705 bool mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry *neigh_entry)
2706 {
2707 struct neighbour *n = neigh_entry->key.n;
2708
2709 /* Packets with a link-local destination address are trapped
2710 * after LPM lookup and never reach the neighbour table, so
2711 * there is no need to program such neighbours to the device.
2712 */
2713 if (ipv6_addr_type((struct in6_addr *) &n->primary_key) &
2714 IPV6_ADDR_LINKLOCAL)
2715 return true;
2716 return false;
2717 }
2718
2719 static void
mlxsw_sp_neigh_entry_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,bool adding)2720 mlxsw_sp_neigh_entry_update(struct mlxsw_sp *mlxsw_sp,
2721 struct mlxsw_sp_neigh_entry *neigh_entry,
2722 bool adding)
2723 {
2724 enum mlxsw_reg_rauht_op op = mlxsw_sp_rauht_op(adding);
2725 int err;
2726
2727 if (!adding && !neigh_entry->connected)
2728 return;
2729 neigh_entry->connected = adding;
2730 if (neigh_entry->key.n->tbl->family == AF_INET) {
2731 err = mlxsw_sp_router_neigh_entry_op4(mlxsw_sp, neigh_entry,
2732 op);
2733 if (err)
2734 return;
2735 } else if (neigh_entry->key.n->tbl->family == AF_INET6) {
2736 if (mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
2737 return;
2738 err = mlxsw_sp_router_neigh_entry_op6(mlxsw_sp, neigh_entry,
2739 op);
2740 if (err)
2741 return;
2742 } else {
2743 WARN_ON_ONCE(1);
2744 return;
2745 }
2746
2747 if (adding)
2748 neigh_entry->key.n->flags |= NTF_OFFLOADED;
2749 else
2750 neigh_entry->key.n->flags &= ~NTF_OFFLOADED;
2751 }
2752
2753 void
mlxsw_sp_neigh_entry_counter_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,bool adding)2754 mlxsw_sp_neigh_entry_counter_update(struct mlxsw_sp *mlxsw_sp,
2755 struct mlxsw_sp_neigh_entry *neigh_entry,
2756 bool adding)
2757 {
2758 if (adding)
2759 mlxsw_sp_neigh_counter_alloc(mlxsw_sp, neigh_entry);
2760 else
2761 mlxsw_sp_neigh_counter_free(mlxsw_sp, neigh_entry);
2762 mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, true);
2763 }
2764
2765 struct mlxsw_sp_netevent_work {
2766 struct work_struct work;
2767 struct mlxsw_sp *mlxsw_sp;
2768 struct neighbour *n;
2769 };
2770
mlxsw_sp_router_neigh_event_work(struct work_struct * work)2771 static void mlxsw_sp_router_neigh_event_work(struct work_struct *work)
2772 {
2773 struct mlxsw_sp_netevent_work *net_work =
2774 container_of(work, struct mlxsw_sp_netevent_work, work);
2775 struct mlxsw_sp *mlxsw_sp = net_work->mlxsw_sp;
2776 struct mlxsw_sp_neigh_entry *neigh_entry;
2777 struct neighbour *n = net_work->n;
2778 unsigned char ha[ETH_ALEN];
2779 bool entry_connected;
2780 u8 nud_state, dead;
2781
2782 /* If these parameters are changed after we release the lock,
2783 * then we are guaranteed to receive another event letting us
2784 * know about it.
2785 */
2786 read_lock_bh(&n->lock);
2787 memcpy(ha, n->ha, ETH_ALEN);
2788 nud_state = n->nud_state;
2789 dead = n->dead;
2790 read_unlock_bh(&n->lock);
2791
2792 mutex_lock(&mlxsw_sp->router->lock);
2793 mlxsw_sp_span_respin(mlxsw_sp);
2794
2795 entry_connected = nud_state & NUD_VALID && !dead;
2796 neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
2797 if (!entry_connected && !neigh_entry)
2798 goto out;
2799 if (!neigh_entry) {
2800 neigh_entry = mlxsw_sp_neigh_entry_create(mlxsw_sp, n);
2801 if (IS_ERR(neigh_entry))
2802 goto out;
2803 }
2804
2805 if (neigh_entry->connected && entry_connected &&
2806 !memcmp(neigh_entry->ha, ha, ETH_ALEN))
2807 goto out;
2808
2809 memcpy(neigh_entry->ha, ha, ETH_ALEN);
2810 mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, entry_connected);
2811 mlxsw_sp_nexthop_neigh_update(mlxsw_sp, neigh_entry, !entry_connected,
2812 dead);
2813
2814 if (!neigh_entry->connected && list_empty(&neigh_entry->nexthop_list))
2815 mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
2816
2817 out:
2818 mutex_unlock(&mlxsw_sp->router->lock);
2819 neigh_release(n);
2820 kfree(net_work);
2821 }
2822
2823 static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp);
2824
mlxsw_sp_router_mp_hash_event_work(struct work_struct * work)2825 static void mlxsw_sp_router_mp_hash_event_work(struct work_struct *work)
2826 {
2827 struct mlxsw_sp_netevent_work *net_work =
2828 container_of(work, struct mlxsw_sp_netevent_work, work);
2829 struct mlxsw_sp *mlxsw_sp = net_work->mlxsw_sp;
2830
2831 mlxsw_sp_mp_hash_init(mlxsw_sp);
2832 kfree(net_work);
2833 }
2834
2835 static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp);
2836
mlxsw_sp_router_update_priority_work(struct work_struct * work)2837 static void mlxsw_sp_router_update_priority_work(struct work_struct *work)
2838 {
2839 struct mlxsw_sp_netevent_work *net_work =
2840 container_of(work, struct mlxsw_sp_netevent_work, work);
2841 struct mlxsw_sp *mlxsw_sp = net_work->mlxsw_sp;
2842
2843 __mlxsw_sp_router_init(mlxsw_sp);
2844 kfree(net_work);
2845 }
2846
mlxsw_sp_router_schedule_work(struct net * net,struct mlxsw_sp_router * router,struct neighbour * n,void (* cb)(struct work_struct *))2847 static int mlxsw_sp_router_schedule_work(struct net *net,
2848 struct mlxsw_sp_router *router,
2849 struct neighbour *n,
2850 void (*cb)(struct work_struct *))
2851 {
2852 struct mlxsw_sp_netevent_work *net_work;
2853
2854 if (!net_eq(net, mlxsw_sp_net(router->mlxsw_sp)))
2855 return NOTIFY_DONE;
2856
2857 net_work = kzalloc_obj(*net_work, GFP_ATOMIC);
2858 if (!net_work)
2859 return NOTIFY_BAD;
2860
2861 /* Take a reference to ensure the neighbour won't be destructed until
2862 * we drop the reference in the work item.
2863 */
2864 neigh_clone(n);
2865
2866 INIT_WORK(&net_work->work, cb);
2867 net_work->mlxsw_sp = router->mlxsw_sp;
2868 net_work->n = n;
2869 mlxsw_core_schedule_work(&net_work->work);
2870 return NOTIFY_DONE;
2871 }
2872
mlxsw_sp_dev_lower_is_port(struct net_device * dev)2873 static bool mlxsw_sp_dev_lower_is_port(struct net_device *dev)
2874 {
2875 struct mlxsw_sp_port *mlxsw_sp_port;
2876
2877 rcu_read_lock();
2878 mlxsw_sp_port = mlxsw_sp_port_dev_lower_find_rcu(dev);
2879 rcu_read_unlock();
2880 return !!mlxsw_sp_port;
2881 }
2882
mlxsw_sp_router_schedule_neigh_work(struct mlxsw_sp_router * router,struct neighbour * n)2883 static int mlxsw_sp_router_schedule_neigh_work(struct mlxsw_sp_router *router,
2884 struct neighbour *n)
2885 {
2886 struct net *net;
2887
2888 net = neigh_parms_net(n->parms);
2889 return mlxsw_sp_router_schedule_work(net, router, n,
2890 mlxsw_sp_router_neigh_event_work);
2891 }
2892
mlxsw_sp_router_netevent_event(struct notifier_block * nb,unsigned long event,void * ptr)2893 static int mlxsw_sp_router_netevent_event(struct notifier_block *nb,
2894 unsigned long event, void *ptr)
2895 {
2896 struct mlxsw_sp_router *router;
2897 unsigned long interval;
2898 struct neigh_parms *p;
2899 struct neighbour *n;
2900
2901 router = container_of(nb, struct mlxsw_sp_router, netevent_nb);
2902
2903 switch (event) {
2904 case NETEVENT_DELAY_PROBE_TIME_UPDATE:
2905 p = ptr;
2906
2907 /* We don't care about changes in the default table. */
2908 if (!p->dev || (p->tbl->family != AF_INET &&
2909 p->tbl->family != AF_INET6))
2910 return NOTIFY_DONE;
2911
2912 /* We are in atomic context and can't take RTNL mutex,
2913 * so use RCU variant to walk the device chain.
2914 */
2915 if (!mlxsw_sp_dev_lower_is_port(p->dev))
2916 return NOTIFY_DONE;
2917
2918 interval = jiffies_to_msecs(NEIGH_VAR(p, DELAY_PROBE_TIME));
2919 router->neighs_update.interval = interval;
2920 break;
2921 case NETEVENT_NEIGH_UPDATE:
2922 n = ptr;
2923
2924 if (n->tbl->family != AF_INET && n->tbl->family != AF_INET6)
2925 return NOTIFY_DONE;
2926
2927 if (!mlxsw_sp_dev_lower_is_port(n->dev))
2928 return NOTIFY_DONE;
2929
2930 return mlxsw_sp_router_schedule_neigh_work(router, n);
2931
2932 case NETEVENT_IPV4_MPATH_HASH_UPDATE:
2933 case NETEVENT_IPV6_MPATH_HASH_UPDATE:
2934 return mlxsw_sp_router_schedule_work(ptr, router, NULL,
2935 mlxsw_sp_router_mp_hash_event_work);
2936
2937 case NETEVENT_IPV4_FWD_UPDATE_PRIORITY_UPDATE:
2938 return mlxsw_sp_router_schedule_work(ptr, router, NULL,
2939 mlxsw_sp_router_update_priority_work);
2940 }
2941
2942 return NOTIFY_DONE;
2943 }
2944
mlxsw_sp_neigh_init(struct mlxsw_sp * mlxsw_sp)2945 static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
2946 {
2947 int err;
2948
2949 err = rhashtable_init(&mlxsw_sp->router->neigh_ht,
2950 &mlxsw_sp_neigh_ht_params);
2951 if (err)
2952 return err;
2953
2954 /* Initialize the polling interval according to the default
2955 * table.
2956 */
2957 mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp);
2958
2959 /* Create the delayed works for the activity_update */
2960 INIT_DELAYED_WORK(&mlxsw_sp->router->neighs_update.dw,
2961 mlxsw_sp_router_neighs_update_work);
2962 INIT_DELAYED_WORK(&mlxsw_sp->router->nexthop_probe_dw,
2963 mlxsw_sp_router_probe_unresolved_nexthops);
2964 atomic_set(&mlxsw_sp->router->neighs_update.neigh_count, 0);
2965 mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw, 0);
2966 mlxsw_core_schedule_dw(&mlxsw_sp->router->nexthop_probe_dw, 0);
2967 return 0;
2968 }
2969
mlxsw_sp_neigh_fini(struct mlxsw_sp * mlxsw_sp)2970 static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)
2971 {
2972 cancel_delayed_work_sync(&mlxsw_sp->router->neighs_update.dw);
2973 cancel_delayed_work_sync(&mlxsw_sp->router->nexthop_probe_dw);
2974 rhashtable_destroy(&mlxsw_sp->router->neigh_ht);
2975 }
2976
mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif)2977 static void mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
2978 struct mlxsw_sp_rif *rif)
2979 {
2980 struct mlxsw_sp_neigh_entry *neigh_entry, *tmp;
2981
2982 list_for_each_entry_safe(neigh_entry, tmp, &rif->neigh_list,
2983 rif_list_node) {
2984 mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, false);
2985 mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
2986 }
2987 }
2988
2989 struct mlxsw_sp_neigh_rif_made_sync {
2990 struct mlxsw_sp *mlxsw_sp;
2991 struct mlxsw_sp_rif *rif;
2992 int err;
2993 };
2994
mlxsw_sp_neigh_rif_made_sync_each(struct neighbour * n,void * data)2995 static void mlxsw_sp_neigh_rif_made_sync_each(struct neighbour *n, void *data)
2996 {
2997 struct mlxsw_sp_neigh_rif_made_sync *rms = data;
2998 int rc;
2999
3000 if (rms->err)
3001 return;
3002 if (n->dev != mlxsw_sp_rif_dev(rms->rif))
3003 return;
3004 rc = mlxsw_sp_router_schedule_neigh_work(rms->mlxsw_sp->router, n);
3005 if (rc != NOTIFY_DONE)
3006 rms->err = -ENOMEM;
3007 }
3008
mlxsw_sp_neigh_rif_made_sync(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif)3009 static int mlxsw_sp_neigh_rif_made_sync(struct mlxsw_sp *mlxsw_sp,
3010 struct mlxsw_sp_rif *rif)
3011 {
3012 struct mlxsw_sp_neigh_rif_made_sync rms = {
3013 .mlxsw_sp = mlxsw_sp,
3014 .rif = rif,
3015 };
3016
3017 if (!mlxsw_sp_dev_lower_is_port(mlxsw_sp_rif_dev(rif)))
3018 return 0;
3019
3020 neigh_for_each(&arp_tbl, mlxsw_sp_neigh_rif_made_sync_each, &rms);
3021 if (rms.err)
3022 goto err_arp;
3023
3024 #if IS_ENABLED(CONFIG_IPV6)
3025 neigh_for_each(&nd_tbl, mlxsw_sp_neigh_rif_made_sync_each, &rms);
3026 #endif
3027 if (rms.err)
3028 goto err_nd;
3029
3030 return 0;
3031
3032 err_nd:
3033 err_arp:
3034 mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif);
3035 return rms.err;
3036 }
3037
3038 enum mlxsw_sp_nexthop_type {
3039 MLXSW_SP_NEXTHOP_TYPE_ETH,
3040 MLXSW_SP_NEXTHOP_TYPE_IPIP,
3041 };
3042
3043 enum mlxsw_sp_nexthop_action {
3044 /* Nexthop forwards packets to an egress RIF */
3045 MLXSW_SP_NEXTHOP_ACTION_FORWARD,
3046 /* Nexthop discards packets */
3047 MLXSW_SP_NEXTHOP_ACTION_DISCARD,
3048 /* Nexthop traps packets */
3049 MLXSW_SP_NEXTHOP_ACTION_TRAP,
3050 };
3051
3052 struct mlxsw_sp_nexthop_key {
3053 struct fib_nh *fib_nh;
3054 };
3055
3056 struct mlxsw_sp_nexthop_counter;
3057
3058 struct mlxsw_sp_nexthop {
3059 struct list_head neigh_list_node; /* member of neigh entry list */
3060 struct list_head crif_list_node;
3061 struct list_head router_list_node;
3062 struct mlxsw_sp_nexthop_group_info *nhgi; /* pointer back to the group
3063 * this nexthop belongs to
3064 */
3065 struct rhash_head ht_node;
3066 struct neigh_table *neigh_tbl;
3067 struct mlxsw_sp_nexthop_key key;
3068 unsigned char gw_addr[sizeof(struct in6_addr)];
3069 int ifindex;
3070 int nh_weight;
3071 int norm_nh_weight;
3072 int num_adj_entries;
3073 struct mlxsw_sp_crif *crif;
3074 u8 should_offload:1, /* set indicates this nexthop should be written
3075 * to the adjacency table.
3076 */
3077 offloaded:1, /* set indicates this nexthop was written to the
3078 * adjacency table.
3079 */
3080 update:1; /* set indicates this nexthop should be updated in the
3081 * adjacency table (f.e., its MAC changed).
3082 */
3083 enum mlxsw_sp_nexthop_action action;
3084 enum mlxsw_sp_nexthop_type type;
3085 union {
3086 struct mlxsw_sp_neigh_entry *neigh_entry;
3087 struct mlxsw_sp_ipip_entry *ipip_entry;
3088 };
3089 struct mlxsw_sp_nexthop_counter *counter;
3090 u32 id; /* NH ID for members of a NH object group. */
3091 };
3092
3093 static struct net_device *
mlxsw_sp_nexthop_dev(const struct mlxsw_sp_nexthop * nh)3094 mlxsw_sp_nexthop_dev(const struct mlxsw_sp_nexthop *nh)
3095 {
3096 if (!nh->crif)
3097 return NULL;
3098 return nh->crif->key.dev;
3099 }
3100
3101 enum mlxsw_sp_nexthop_group_type {
3102 MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV4,
3103 MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV6,
3104 MLXSW_SP_NEXTHOP_GROUP_TYPE_OBJ,
3105 };
3106
3107 struct mlxsw_sp_nexthop_group_info {
3108 struct mlxsw_sp_nexthop_group *nh_grp;
3109 u32 adj_index;
3110 u16 ecmp_size;
3111 u16 count;
3112 int sum_norm_weight;
3113 u8 adj_index_valid:1,
3114 gateway:1, /* routes using the group use a gateway */
3115 is_resilient:1,
3116 hw_stats:1;
3117 struct list_head list; /* member in nh_res_grp_list */
3118 struct xarray nexthop_counters;
3119 struct mlxsw_sp_nexthop nexthops[] __counted_by(count);
3120 };
3121
3122 static struct mlxsw_sp_rif *
mlxsw_sp_nhgi_rif(const struct mlxsw_sp_nexthop_group_info * nhgi)3123 mlxsw_sp_nhgi_rif(const struct mlxsw_sp_nexthop_group_info *nhgi)
3124 {
3125 struct mlxsw_sp_crif *crif = nhgi->nexthops[0].crif;
3126
3127 if (!crif)
3128 return NULL;
3129 return crif->rif;
3130 }
3131
3132 struct mlxsw_sp_nexthop_group_vr_key {
3133 u16 vr_id;
3134 enum mlxsw_sp_l3proto proto;
3135 };
3136
3137 struct mlxsw_sp_nexthop_group_vr_entry {
3138 struct list_head list; /* member in vr_list */
3139 struct rhash_head ht_node; /* member in vr_ht */
3140 refcount_t ref_count;
3141 struct mlxsw_sp_nexthop_group_vr_key key;
3142 };
3143
3144 struct mlxsw_sp_nexthop_group {
3145 struct rhash_head ht_node;
3146 struct list_head fib_list; /* list of fib entries that use this group */
3147 union {
3148 struct {
3149 struct fib_info *fi;
3150 } ipv4;
3151 struct {
3152 u32 id;
3153 } obj;
3154 };
3155 struct mlxsw_sp_nexthop_group_info *nhgi;
3156 struct list_head vr_list;
3157 struct rhashtable vr_ht;
3158 enum mlxsw_sp_nexthop_group_type type;
3159 bool can_destroy;
3160 };
3161
3162 struct mlxsw_sp_nexthop_counter {
3163 unsigned int counter_index;
3164 refcount_t ref_count;
3165 };
3166
3167 static struct mlxsw_sp_nexthop_counter *
mlxsw_sp_nexthop_counter_alloc(struct mlxsw_sp * mlxsw_sp)3168 mlxsw_sp_nexthop_counter_alloc(struct mlxsw_sp *mlxsw_sp)
3169 {
3170 struct mlxsw_sp_nexthop_counter *nhct;
3171 int err;
3172
3173 nhct = kzalloc_obj(*nhct);
3174 if (!nhct)
3175 return ERR_PTR(-ENOMEM);
3176
3177 err = mlxsw_sp_flow_counter_alloc(mlxsw_sp, &nhct->counter_index);
3178 if (err)
3179 goto err_counter_alloc;
3180
3181 refcount_set(&nhct->ref_count, 1);
3182 return nhct;
3183
3184 err_counter_alloc:
3185 kfree(nhct);
3186 return ERR_PTR(err);
3187 }
3188
3189 static void
mlxsw_sp_nexthop_counter_free(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_counter * nhct)3190 mlxsw_sp_nexthop_counter_free(struct mlxsw_sp *mlxsw_sp,
3191 struct mlxsw_sp_nexthop_counter *nhct)
3192 {
3193 mlxsw_sp_flow_counter_free(mlxsw_sp, nhct->counter_index);
3194 kfree(nhct);
3195 }
3196
3197 static struct mlxsw_sp_nexthop_counter *
mlxsw_sp_nexthop_sh_counter_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3198 mlxsw_sp_nexthop_sh_counter_get(struct mlxsw_sp *mlxsw_sp,
3199 struct mlxsw_sp_nexthop *nh)
3200 {
3201 struct mlxsw_sp_nexthop_group *nh_grp = nh->nhgi->nh_grp;
3202 struct mlxsw_sp_nexthop_counter *nhct;
3203 int err;
3204
3205 nhct = xa_load(&nh_grp->nhgi->nexthop_counters, nh->id);
3206 if (nhct) {
3207 refcount_inc(&nhct->ref_count);
3208 return nhct;
3209 }
3210
3211 nhct = mlxsw_sp_nexthop_counter_alloc(mlxsw_sp);
3212 if (IS_ERR(nhct))
3213 return nhct;
3214
3215 err = xa_err(xa_store(&nh_grp->nhgi->nexthop_counters, nh->id, nhct,
3216 GFP_KERNEL));
3217 if (err)
3218 goto err_store;
3219
3220 return nhct;
3221
3222 err_store:
3223 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nhct);
3224 return ERR_PTR(err);
3225 }
3226
mlxsw_sp_nexthop_sh_counter_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3227 static void mlxsw_sp_nexthop_sh_counter_put(struct mlxsw_sp *mlxsw_sp,
3228 struct mlxsw_sp_nexthop *nh)
3229 {
3230 struct mlxsw_sp_nexthop_group *nh_grp = nh->nhgi->nh_grp;
3231 struct mlxsw_sp_nexthop_counter *nhct;
3232
3233 nhct = xa_load(&nh_grp->nhgi->nexthop_counters, nh->id);
3234 if (WARN_ON(!nhct))
3235 return;
3236
3237 if (!refcount_dec_and_test(&nhct->ref_count))
3238 return;
3239
3240 xa_erase(&nh_grp->nhgi->nexthop_counters, nh->id);
3241 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nhct);
3242 }
3243
mlxsw_sp_nexthop_counter_enable(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3244 int mlxsw_sp_nexthop_counter_enable(struct mlxsw_sp *mlxsw_sp,
3245 struct mlxsw_sp_nexthop *nh)
3246 {
3247 const char *table_adj = MLXSW_SP_DPIPE_TABLE_NAME_ADJ;
3248 struct mlxsw_sp_nexthop_counter *nhct;
3249 struct devlink *devlink;
3250 bool dpipe_stats;
3251
3252 if (nh->counter)
3253 return 0;
3254
3255 devlink = priv_to_devlink(mlxsw_sp->core);
3256 dpipe_stats = devlink_dpipe_table_counter_enabled(devlink, table_adj);
3257 if (!(nh->nhgi->hw_stats || dpipe_stats))
3258 return 0;
3259
3260 if (nh->id)
3261 nhct = mlxsw_sp_nexthop_sh_counter_get(mlxsw_sp, nh);
3262 else
3263 nhct = mlxsw_sp_nexthop_counter_alloc(mlxsw_sp);
3264 if (IS_ERR(nhct))
3265 return PTR_ERR(nhct);
3266
3267 nh->counter = nhct;
3268 return 0;
3269 }
3270
mlxsw_sp_nexthop_counter_disable(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3271 void mlxsw_sp_nexthop_counter_disable(struct mlxsw_sp *mlxsw_sp,
3272 struct mlxsw_sp_nexthop *nh)
3273 {
3274 if (!nh->counter)
3275 return;
3276
3277 if (nh->id)
3278 mlxsw_sp_nexthop_sh_counter_put(mlxsw_sp, nh);
3279 else
3280 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh->counter);
3281 nh->counter = NULL;
3282 }
3283
mlxsw_sp_nexthop_counter_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3284 static int mlxsw_sp_nexthop_counter_update(struct mlxsw_sp *mlxsw_sp,
3285 struct mlxsw_sp_nexthop *nh)
3286 {
3287 if (nh->nhgi->hw_stats)
3288 return mlxsw_sp_nexthop_counter_enable(mlxsw_sp, nh);
3289 mlxsw_sp_nexthop_counter_disable(mlxsw_sp, nh);
3290 return 0;
3291 }
3292
mlxsw_sp_nexthop_counter_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh,u64 * p_counter)3293 int mlxsw_sp_nexthop_counter_get(struct mlxsw_sp *mlxsw_sp,
3294 struct mlxsw_sp_nexthop *nh, u64 *p_counter)
3295 {
3296 if (!nh->counter)
3297 return -EINVAL;
3298
3299 return mlxsw_sp_flow_counter_get(mlxsw_sp, nh->counter->counter_index,
3300 true, p_counter, NULL);
3301 }
3302
mlxsw_sp_nexthop_next(struct mlxsw_sp_router * router,struct mlxsw_sp_nexthop * nh)3303 struct mlxsw_sp_nexthop *mlxsw_sp_nexthop_next(struct mlxsw_sp_router *router,
3304 struct mlxsw_sp_nexthop *nh)
3305 {
3306 if (!nh) {
3307 if (list_empty(&router->nexthop_list))
3308 return NULL;
3309 else
3310 return list_first_entry(&router->nexthop_list,
3311 typeof(*nh), router_list_node);
3312 }
3313 if (list_is_last(&nh->router_list_node, &router->nexthop_list))
3314 return NULL;
3315 return list_next_entry(nh, router_list_node);
3316 }
3317
mlxsw_sp_nexthop_is_forward(const struct mlxsw_sp_nexthop * nh)3318 bool mlxsw_sp_nexthop_is_forward(const struct mlxsw_sp_nexthop *nh)
3319 {
3320 return nh->offloaded && nh->action == MLXSW_SP_NEXTHOP_ACTION_FORWARD;
3321 }
3322
mlxsw_sp_nexthop_ha(struct mlxsw_sp_nexthop * nh)3323 unsigned char *mlxsw_sp_nexthop_ha(struct mlxsw_sp_nexthop *nh)
3324 {
3325 if (nh->type != MLXSW_SP_NEXTHOP_TYPE_ETH ||
3326 !mlxsw_sp_nexthop_is_forward(nh))
3327 return NULL;
3328 return nh->neigh_entry->ha;
3329 }
3330
mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop * nh,u32 * p_adj_index,u32 * p_adj_size,u32 * p_adj_hash_index)3331 int mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop *nh, u32 *p_adj_index,
3332 u32 *p_adj_size, u32 *p_adj_hash_index)
3333 {
3334 struct mlxsw_sp_nexthop_group_info *nhgi = nh->nhgi;
3335 u32 adj_hash_index = 0;
3336 int i;
3337
3338 if (!nh->offloaded || !nhgi->adj_index_valid)
3339 return -EINVAL;
3340
3341 *p_adj_index = nhgi->adj_index;
3342 *p_adj_size = nhgi->ecmp_size;
3343
3344 for (i = 0; i < nhgi->count; i++) {
3345 struct mlxsw_sp_nexthop *nh_iter = &nhgi->nexthops[i];
3346
3347 if (nh_iter == nh)
3348 break;
3349 if (nh_iter->offloaded)
3350 adj_hash_index += nh_iter->num_adj_entries;
3351 }
3352
3353 *p_adj_hash_index = adj_hash_index;
3354 return 0;
3355 }
3356
mlxsw_sp_nexthop_rif(struct mlxsw_sp_nexthop * nh)3357 struct mlxsw_sp_rif *mlxsw_sp_nexthop_rif(struct mlxsw_sp_nexthop *nh)
3358 {
3359 if (WARN_ON(!nh->crif))
3360 return NULL;
3361 return nh->crif->rif;
3362 }
3363
mlxsw_sp_nexthop_group_has_ipip(struct mlxsw_sp_nexthop * nh)3364 bool mlxsw_sp_nexthop_group_has_ipip(struct mlxsw_sp_nexthop *nh)
3365 {
3366 struct mlxsw_sp_nexthop_group_info *nhgi = nh->nhgi;
3367 int i;
3368
3369 for (i = 0; i < nhgi->count; i++) {
3370 struct mlxsw_sp_nexthop *nh_iter = &nhgi->nexthops[i];
3371
3372 if (nh_iter->type == MLXSW_SP_NEXTHOP_TYPE_IPIP)
3373 return true;
3374 }
3375 return false;
3376 }
3377
3378 static const struct rhashtable_params mlxsw_sp_nexthop_group_vr_ht_params = {
3379 .key_offset = offsetof(struct mlxsw_sp_nexthop_group_vr_entry, key),
3380 .head_offset = offsetof(struct mlxsw_sp_nexthop_group_vr_entry, ht_node),
3381 .key_len = sizeof(struct mlxsw_sp_nexthop_group_vr_key),
3382 .automatic_shrinking = true,
3383 };
3384
3385 static struct mlxsw_sp_nexthop_group_vr_entry *
mlxsw_sp_nexthop_group_vr_entry_lookup(struct mlxsw_sp_nexthop_group * nh_grp,const struct mlxsw_sp_fib * fib)3386 mlxsw_sp_nexthop_group_vr_entry_lookup(struct mlxsw_sp_nexthop_group *nh_grp,
3387 const struct mlxsw_sp_fib *fib)
3388 {
3389 struct mlxsw_sp_nexthop_group_vr_key key;
3390
3391 memset(&key, 0, sizeof(key));
3392 key.vr_id = fib->vr->id;
3393 key.proto = fib->proto;
3394 return rhashtable_lookup_fast(&nh_grp->vr_ht, &key,
3395 mlxsw_sp_nexthop_group_vr_ht_params);
3396 }
3397
3398 static int
mlxsw_sp_nexthop_group_vr_entry_create(struct mlxsw_sp_nexthop_group * nh_grp,const struct mlxsw_sp_fib * fib)3399 mlxsw_sp_nexthop_group_vr_entry_create(struct mlxsw_sp_nexthop_group *nh_grp,
3400 const struct mlxsw_sp_fib *fib)
3401 {
3402 struct mlxsw_sp_nexthop_group_vr_entry *vr_entry;
3403 int err;
3404
3405 vr_entry = kzalloc_obj(*vr_entry);
3406 if (!vr_entry)
3407 return -ENOMEM;
3408
3409 vr_entry->key.vr_id = fib->vr->id;
3410 vr_entry->key.proto = fib->proto;
3411 refcount_set(&vr_entry->ref_count, 1);
3412
3413 err = rhashtable_insert_fast(&nh_grp->vr_ht, &vr_entry->ht_node,
3414 mlxsw_sp_nexthop_group_vr_ht_params);
3415 if (err)
3416 goto err_hashtable_insert;
3417
3418 list_add(&vr_entry->list, &nh_grp->vr_list);
3419
3420 return 0;
3421
3422 err_hashtable_insert:
3423 kfree(vr_entry);
3424 return err;
3425 }
3426
3427 static void
mlxsw_sp_nexthop_group_vr_entry_destroy(struct mlxsw_sp_nexthop_group * nh_grp,struct mlxsw_sp_nexthop_group_vr_entry * vr_entry)3428 mlxsw_sp_nexthop_group_vr_entry_destroy(struct mlxsw_sp_nexthop_group *nh_grp,
3429 struct mlxsw_sp_nexthop_group_vr_entry *vr_entry)
3430 {
3431 list_del(&vr_entry->list);
3432 rhashtable_remove_fast(&nh_grp->vr_ht, &vr_entry->ht_node,
3433 mlxsw_sp_nexthop_group_vr_ht_params);
3434 kfree(vr_entry);
3435 }
3436
3437 static int
mlxsw_sp_nexthop_group_vr_link(struct mlxsw_sp_nexthop_group * nh_grp,const struct mlxsw_sp_fib * fib)3438 mlxsw_sp_nexthop_group_vr_link(struct mlxsw_sp_nexthop_group *nh_grp,
3439 const struct mlxsw_sp_fib *fib)
3440 {
3441 struct mlxsw_sp_nexthop_group_vr_entry *vr_entry;
3442
3443 vr_entry = mlxsw_sp_nexthop_group_vr_entry_lookup(nh_grp, fib);
3444 if (vr_entry) {
3445 refcount_inc(&vr_entry->ref_count);
3446 return 0;
3447 }
3448
3449 return mlxsw_sp_nexthop_group_vr_entry_create(nh_grp, fib);
3450 }
3451
3452 static void
mlxsw_sp_nexthop_group_vr_unlink(struct mlxsw_sp_nexthop_group * nh_grp,const struct mlxsw_sp_fib * fib)3453 mlxsw_sp_nexthop_group_vr_unlink(struct mlxsw_sp_nexthop_group *nh_grp,
3454 const struct mlxsw_sp_fib *fib)
3455 {
3456 struct mlxsw_sp_nexthop_group_vr_entry *vr_entry;
3457
3458 vr_entry = mlxsw_sp_nexthop_group_vr_entry_lookup(nh_grp, fib);
3459 if (WARN_ON_ONCE(!vr_entry))
3460 return;
3461
3462 if (!refcount_dec_and_test(&vr_entry->ref_count))
3463 return;
3464
3465 mlxsw_sp_nexthop_group_vr_entry_destroy(nh_grp, vr_entry);
3466 }
3467
3468 struct mlxsw_sp_nexthop_group_cmp_arg {
3469 enum mlxsw_sp_nexthop_group_type type;
3470 union {
3471 struct fib_info *fi;
3472 struct mlxsw_sp_fib6_entry *fib6_entry;
3473 u32 id;
3474 };
3475 };
3476
3477 static bool
mlxsw_sp_nexthop6_group_has_nexthop(const struct mlxsw_sp_nexthop_group * nh_grp,const struct in6_addr * gw,int ifindex,int weight)3478 mlxsw_sp_nexthop6_group_has_nexthop(const struct mlxsw_sp_nexthop_group *nh_grp,
3479 const struct in6_addr *gw, int ifindex,
3480 int weight)
3481 {
3482 int i;
3483
3484 for (i = 0; i < nh_grp->nhgi->count; i++) {
3485 const struct mlxsw_sp_nexthop *nh;
3486
3487 nh = &nh_grp->nhgi->nexthops[i];
3488 if (nh->ifindex == ifindex && nh->nh_weight == weight &&
3489 ipv6_addr_equal(gw, (struct in6_addr *) nh->gw_addr))
3490 return true;
3491 }
3492
3493 return false;
3494 }
3495
3496 static bool
mlxsw_sp_nexthop6_group_cmp(const struct mlxsw_sp_nexthop_group * nh_grp,const struct mlxsw_sp_fib6_entry * fib6_entry)3497 mlxsw_sp_nexthop6_group_cmp(const struct mlxsw_sp_nexthop_group *nh_grp,
3498 const struct mlxsw_sp_fib6_entry *fib6_entry)
3499 {
3500 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
3501
3502 if (nh_grp->nhgi->count != fib6_entry->nrt6)
3503 return false;
3504
3505 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
3506 struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
3507 struct in6_addr *gw;
3508 int ifindex, weight;
3509
3510 ifindex = fib6_nh->fib_nh_dev->ifindex;
3511 weight = fib6_nh->fib_nh_weight;
3512 gw = &fib6_nh->fib_nh_gw6;
3513 if (!mlxsw_sp_nexthop6_group_has_nexthop(nh_grp, gw, ifindex,
3514 weight))
3515 return false;
3516 }
3517
3518 return true;
3519 }
3520
3521 static int
mlxsw_sp_nexthop_group_cmp(struct rhashtable_compare_arg * arg,const void * ptr)3522 mlxsw_sp_nexthop_group_cmp(struct rhashtable_compare_arg *arg, const void *ptr)
3523 {
3524 const struct mlxsw_sp_nexthop_group_cmp_arg *cmp_arg = arg->key;
3525 const struct mlxsw_sp_nexthop_group *nh_grp = ptr;
3526
3527 if (nh_grp->type != cmp_arg->type)
3528 return 1;
3529
3530 switch (cmp_arg->type) {
3531 case MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV4:
3532 return cmp_arg->fi != nh_grp->ipv4.fi;
3533 case MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV6:
3534 return !mlxsw_sp_nexthop6_group_cmp(nh_grp,
3535 cmp_arg->fib6_entry);
3536 case MLXSW_SP_NEXTHOP_GROUP_TYPE_OBJ:
3537 return cmp_arg->id != nh_grp->obj.id;
3538 default:
3539 WARN_ON(1);
3540 return 1;
3541 }
3542 }
3543
mlxsw_sp_nexthop_group_hash_obj(const void * data,u32 len,u32 seed)3544 static u32 mlxsw_sp_nexthop_group_hash_obj(const void *data, u32 len, u32 seed)
3545 {
3546 const struct mlxsw_sp_nexthop_group *nh_grp = data;
3547 const struct mlxsw_sp_nexthop *nh;
3548 struct fib_info *fi;
3549 unsigned int val;
3550 int i;
3551
3552 switch (nh_grp->type) {
3553 case MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV4:
3554 fi = nh_grp->ipv4.fi;
3555 return jhash(&fi, sizeof(fi), seed);
3556 case MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV6:
3557 val = nh_grp->nhgi->count;
3558 for (i = 0; i < nh_grp->nhgi->count; i++) {
3559 nh = &nh_grp->nhgi->nexthops[i];
3560 val ^= jhash(&nh->ifindex, sizeof(nh->ifindex), seed);
3561 val ^= jhash(&nh->gw_addr, sizeof(nh->gw_addr), seed);
3562 }
3563 return jhash(&val, sizeof(val), seed);
3564 case MLXSW_SP_NEXTHOP_GROUP_TYPE_OBJ:
3565 return jhash(&nh_grp->obj.id, sizeof(nh_grp->obj.id), seed);
3566 default:
3567 WARN_ON(1);
3568 return 0;
3569 }
3570 }
3571
3572 static u32
mlxsw_sp_nexthop6_group_hash(struct mlxsw_sp_fib6_entry * fib6_entry,u32 seed)3573 mlxsw_sp_nexthop6_group_hash(struct mlxsw_sp_fib6_entry *fib6_entry, u32 seed)
3574 {
3575 unsigned int val = fib6_entry->nrt6;
3576 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
3577
3578 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
3579 struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
3580 struct net_device *dev = fib6_nh->fib_nh_dev;
3581 struct in6_addr *gw = &fib6_nh->fib_nh_gw6;
3582
3583 val ^= jhash(&dev->ifindex, sizeof(dev->ifindex), seed);
3584 val ^= jhash(gw, sizeof(*gw), seed);
3585 }
3586
3587 return jhash(&val, sizeof(val), seed);
3588 }
3589
3590 static u32
mlxsw_sp_nexthop_group_hash(const void * data,u32 len,u32 seed)3591 mlxsw_sp_nexthop_group_hash(const void *data, u32 len, u32 seed)
3592 {
3593 const struct mlxsw_sp_nexthop_group_cmp_arg *cmp_arg = data;
3594
3595 switch (cmp_arg->type) {
3596 case MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV4:
3597 return jhash(&cmp_arg->fi, sizeof(cmp_arg->fi), seed);
3598 case MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV6:
3599 return mlxsw_sp_nexthop6_group_hash(cmp_arg->fib6_entry, seed);
3600 case MLXSW_SP_NEXTHOP_GROUP_TYPE_OBJ:
3601 return jhash(&cmp_arg->id, sizeof(cmp_arg->id), seed);
3602 default:
3603 WARN_ON(1);
3604 return 0;
3605 }
3606 }
3607
3608 static const struct rhashtable_params mlxsw_sp_nexthop_group_ht_params = {
3609 .head_offset = offsetof(struct mlxsw_sp_nexthop_group, ht_node),
3610 .hashfn = mlxsw_sp_nexthop_group_hash,
3611 .obj_hashfn = mlxsw_sp_nexthop_group_hash_obj,
3612 .obj_cmpfn = mlxsw_sp_nexthop_group_cmp,
3613 };
3614
mlxsw_sp_nexthop_group_insert(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)3615 static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp,
3616 struct mlxsw_sp_nexthop_group *nh_grp)
3617 {
3618 if (nh_grp->type == MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV6 &&
3619 !nh_grp->nhgi->gateway)
3620 return 0;
3621
3622 return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_group_ht,
3623 &nh_grp->ht_node,
3624 mlxsw_sp_nexthop_group_ht_params);
3625 }
3626
mlxsw_sp_nexthop_group_remove(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)3627 static void mlxsw_sp_nexthop_group_remove(struct mlxsw_sp *mlxsw_sp,
3628 struct mlxsw_sp_nexthop_group *nh_grp)
3629 {
3630 if (nh_grp->type == MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV6 &&
3631 !nh_grp->nhgi->gateway)
3632 return;
3633
3634 rhashtable_remove_fast(&mlxsw_sp->router->nexthop_group_ht,
3635 &nh_grp->ht_node,
3636 mlxsw_sp_nexthop_group_ht_params);
3637 }
3638
3639 static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop4_group_lookup(struct mlxsw_sp * mlxsw_sp,struct fib_info * fi)3640 mlxsw_sp_nexthop4_group_lookup(struct mlxsw_sp *mlxsw_sp,
3641 struct fib_info *fi)
3642 {
3643 struct mlxsw_sp_nexthop_group_cmp_arg cmp_arg;
3644
3645 cmp_arg.type = MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV4;
3646 cmp_arg.fi = fi;
3647 return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht,
3648 &cmp_arg,
3649 mlxsw_sp_nexthop_group_ht_params);
3650 }
3651
3652 static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop6_group_lookup(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)3653 mlxsw_sp_nexthop6_group_lookup(struct mlxsw_sp *mlxsw_sp,
3654 struct mlxsw_sp_fib6_entry *fib6_entry)
3655 {
3656 struct mlxsw_sp_nexthop_group_cmp_arg cmp_arg;
3657
3658 cmp_arg.type = MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV6;
3659 cmp_arg.fib6_entry = fib6_entry;
3660 return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht,
3661 &cmp_arg,
3662 mlxsw_sp_nexthop_group_ht_params);
3663 }
3664
3665 static const struct rhashtable_params mlxsw_sp_nexthop_ht_params = {
3666 .key_offset = offsetof(struct mlxsw_sp_nexthop, key),
3667 .head_offset = offsetof(struct mlxsw_sp_nexthop, ht_node),
3668 .key_len = sizeof(struct mlxsw_sp_nexthop_key),
3669 };
3670
mlxsw_sp_nexthop_insert(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3671 static int mlxsw_sp_nexthop_insert(struct mlxsw_sp *mlxsw_sp,
3672 struct mlxsw_sp_nexthop *nh)
3673 {
3674 return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_ht,
3675 &nh->ht_node, mlxsw_sp_nexthop_ht_params);
3676 }
3677
mlxsw_sp_nexthop_remove(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)3678 static void mlxsw_sp_nexthop_remove(struct mlxsw_sp *mlxsw_sp,
3679 struct mlxsw_sp_nexthop *nh)
3680 {
3681 rhashtable_remove_fast(&mlxsw_sp->router->nexthop_ht, &nh->ht_node,
3682 mlxsw_sp_nexthop_ht_params);
3683 }
3684
3685 static struct mlxsw_sp_nexthop *
mlxsw_sp_nexthop_lookup(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_key key)3686 mlxsw_sp_nexthop_lookup(struct mlxsw_sp *mlxsw_sp,
3687 struct mlxsw_sp_nexthop_key key)
3688 {
3689 return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_ht, &key,
3690 mlxsw_sp_nexthop_ht_params);
3691 }
3692
mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_l3proto proto,u16 vr_id,u32 adj_index,u16 ecmp_size,u32 new_adj_index,u16 new_ecmp_size)3693 static int mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp *mlxsw_sp,
3694 enum mlxsw_sp_l3proto proto,
3695 u16 vr_id,
3696 u32 adj_index, u16 ecmp_size,
3697 u32 new_adj_index,
3698 u16 new_ecmp_size)
3699 {
3700 char raleu_pl[MLXSW_REG_RALEU_LEN];
3701
3702 mlxsw_reg_raleu_pack(raleu_pl,
3703 (enum mlxsw_reg_ralxx_protocol) proto, vr_id,
3704 adj_index, ecmp_size, new_adj_index,
3705 new_ecmp_size);
3706 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raleu), raleu_pl);
3707 }
3708
mlxsw_sp_adj_index_mass_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,u32 old_adj_index,u16 old_ecmp_size)3709 static int mlxsw_sp_adj_index_mass_update(struct mlxsw_sp *mlxsw_sp,
3710 struct mlxsw_sp_nexthop_group *nh_grp,
3711 u32 old_adj_index, u16 old_ecmp_size)
3712 {
3713 struct mlxsw_sp_nexthop_group_info *nhgi = nh_grp->nhgi;
3714 struct mlxsw_sp_nexthop_group_vr_entry *vr_entry;
3715 int err;
3716
3717 list_for_each_entry(vr_entry, &nh_grp->vr_list, list) {
3718 err = mlxsw_sp_adj_index_mass_update_vr(mlxsw_sp,
3719 vr_entry->key.proto,
3720 vr_entry->key.vr_id,
3721 old_adj_index,
3722 old_ecmp_size,
3723 nhgi->adj_index,
3724 nhgi->ecmp_size);
3725 if (err)
3726 goto err_mass_update_vr;
3727 }
3728 return 0;
3729
3730 err_mass_update_vr:
3731 list_for_each_entry_continue_reverse(vr_entry, &nh_grp->vr_list, list)
3732 mlxsw_sp_adj_index_mass_update_vr(mlxsw_sp, vr_entry->key.proto,
3733 vr_entry->key.vr_id,
3734 nhgi->adj_index,
3735 nhgi->ecmp_size,
3736 old_adj_index, old_ecmp_size);
3737 return err;
3738 }
3739
__mlxsw_sp_nexthop_eth_update(struct mlxsw_sp * mlxsw_sp,u32 adj_index,struct mlxsw_sp_nexthop * nh,bool force,char * ratr_pl)3740 static int __mlxsw_sp_nexthop_eth_update(struct mlxsw_sp *mlxsw_sp,
3741 u32 adj_index,
3742 struct mlxsw_sp_nexthop *nh,
3743 bool force, char *ratr_pl)
3744 {
3745 struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry;
3746 struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh);
3747 enum mlxsw_reg_ratr_op op;
3748 u16 rif_index;
3749
3750 rif_index = rif ? rif->rif_index :
3751 mlxsw_sp->router->lb_crif->rif->rif_index;
3752 op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY :
3753 MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY;
3754 mlxsw_reg_ratr_pack(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_ETHERNET,
3755 adj_index, rif_index);
3756 switch (nh->action) {
3757 case MLXSW_SP_NEXTHOP_ACTION_FORWARD:
3758 mlxsw_reg_ratr_eth_entry_pack(ratr_pl, neigh_entry->ha);
3759 break;
3760 case MLXSW_SP_NEXTHOP_ACTION_DISCARD:
3761 mlxsw_reg_ratr_trap_action_set(ratr_pl,
3762 MLXSW_REG_RATR_TRAP_ACTION_DISCARD_ERRORS);
3763 break;
3764 case MLXSW_SP_NEXTHOP_ACTION_TRAP:
3765 mlxsw_reg_ratr_trap_action_set(ratr_pl,
3766 MLXSW_REG_RATR_TRAP_ACTION_TRAP);
3767 mlxsw_reg_ratr_trap_id_set(ratr_pl, MLXSW_TRAP_ID_RTR_EGRESS0);
3768 break;
3769 default:
3770 WARN_ON_ONCE(1);
3771 return -EINVAL;
3772 }
3773 if (nh->counter)
3774 mlxsw_reg_ratr_counter_pack(ratr_pl, nh->counter->counter_index,
3775 true);
3776 else
3777 mlxsw_reg_ratr_counter_pack(ratr_pl, 0, false);
3778
3779 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
3780 }
3781
mlxsw_sp_nexthop_eth_update(struct mlxsw_sp * mlxsw_sp,u32 adj_index,struct mlxsw_sp_nexthop * nh,bool force,char * ratr_pl)3782 int mlxsw_sp_nexthop_eth_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
3783 struct mlxsw_sp_nexthop *nh, bool force,
3784 char *ratr_pl)
3785 {
3786 int i;
3787
3788 for (i = 0; i < nh->num_adj_entries; i++) {
3789 int err;
3790
3791 err = __mlxsw_sp_nexthop_eth_update(mlxsw_sp, adj_index + i,
3792 nh, force, ratr_pl);
3793 if (err)
3794 return err;
3795 }
3796
3797 return 0;
3798 }
3799
__mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp * mlxsw_sp,u32 adj_index,struct mlxsw_sp_nexthop * nh,bool force,char * ratr_pl)3800 static int __mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp *mlxsw_sp,
3801 u32 adj_index,
3802 struct mlxsw_sp_nexthop *nh,
3803 bool force, char *ratr_pl)
3804 {
3805 const struct mlxsw_sp_ipip_ops *ipip_ops;
3806
3807 ipip_ops = mlxsw_sp->router->ipip_ops_arr[nh->ipip_entry->ipipt];
3808 return ipip_ops->nexthop_update(mlxsw_sp, adj_index, nh->ipip_entry,
3809 force, ratr_pl);
3810 }
3811
mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp * mlxsw_sp,u32 adj_index,struct mlxsw_sp_nexthop * nh,bool force,char * ratr_pl)3812 static int mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp *mlxsw_sp,
3813 u32 adj_index,
3814 struct mlxsw_sp_nexthop *nh, bool force,
3815 char *ratr_pl)
3816 {
3817 int i;
3818
3819 for (i = 0; i < nh->num_adj_entries; i++) {
3820 int err;
3821
3822 err = __mlxsw_sp_nexthop_ipip_update(mlxsw_sp, adj_index + i,
3823 nh, force, ratr_pl);
3824 if (err)
3825 return err;
3826 }
3827
3828 return 0;
3829 }
3830
mlxsw_sp_nexthop_update(struct mlxsw_sp * mlxsw_sp,u32 adj_index,struct mlxsw_sp_nexthop * nh,bool force,char * ratr_pl)3831 static int mlxsw_sp_nexthop_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
3832 struct mlxsw_sp_nexthop *nh, bool force,
3833 char *ratr_pl)
3834 {
3835 /* When action is discard or trap, the nexthop must be
3836 * programmed as an Ethernet nexthop.
3837 */
3838 if (nh->type == MLXSW_SP_NEXTHOP_TYPE_ETH ||
3839 nh->action == MLXSW_SP_NEXTHOP_ACTION_DISCARD ||
3840 nh->action == MLXSW_SP_NEXTHOP_ACTION_TRAP)
3841 return mlxsw_sp_nexthop_eth_update(mlxsw_sp, adj_index, nh,
3842 force, ratr_pl);
3843 else
3844 return mlxsw_sp_nexthop_ipip_update(mlxsw_sp, adj_index, nh,
3845 force, ratr_pl);
3846 }
3847
3848 static int
mlxsw_sp_nexthop_group_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group_info * nhgi,bool reallocate)3849 mlxsw_sp_nexthop_group_update(struct mlxsw_sp *mlxsw_sp,
3850 struct mlxsw_sp_nexthop_group_info *nhgi,
3851 bool reallocate)
3852 {
3853 char ratr_pl[MLXSW_REG_RATR_LEN];
3854 u32 adj_index = nhgi->adj_index; /* base */
3855 struct mlxsw_sp_nexthop *nh;
3856 int i;
3857
3858 for (i = 0; i < nhgi->count; i++) {
3859 nh = &nhgi->nexthops[i];
3860
3861 if (!nh->should_offload) {
3862 mlxsw_sp_nexthop_counter_disable(mlxsw_sp, nh);
3863 nh->offloaded = 0;
3864 continue;
3865 }
3866
3867 if (nh->update || reallocate) {
3868 int err = 0;
3869
3870 err = mlxsw_sp_nexthop_counter_update(mlxsw_sp, nh);
3871 if (err)
3872 return err;
3873
3874 err = mlxsw_sp_nexthop_update(mlxsw_sp, adj_index, nh,
3875 true, ratr_pl);
3876 if (err)
3877 return err;
3878 nh->update = 0;
3879 nh->offloaded = 1;
3880 }
3881 adj_index += nh->num_adj_entries;
3882 }
3883 return 0;
3884 }
3885
3886 static int
mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)3887 mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp *mlxsw_sp,
3888 struct mlxsw_sp_nexthop_group *nh_grp)
3889 {
3890 struct mlxsw_sp_fib_entry *fib_entry;
3891 int err;
3892
3893 list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) {
3894 err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
3895 if (err)
3896 return err;
3897 }
3898 return 0;
3899 }
3900
3901 struct mlxsw_sp_adj_grp_size_range {
3902 u16 start; /* Inclusive */
3903 u16 end; /* Inclusive */
3904 };
3905
3906 /* Ordered by range start value */
3907 static const struct mlxsw_sp_adj_grp_size_range
3908 mlxsw_sp1_adj_grp_size_ranges[] = {
3909 { .start = 1, .end = 64 },
3910 { .start = 512, .end = 512 },
3911 { .start = 1024, .end = 1024 },
3912 { .start = 2048, .end = 2048 },
3913 { .start = 4096, .end = 4096 },
3914 };
3915
3916 /* Ordered by range start value */
3917 static const struct mlxsw_sp_adj_grp_size_range
3918 mlxsw_sp2_adj_grp_size_ranges[] = {
3919 { .start = 1, .end = 128 },
3920 { .start = 256, .end = 256 },
3921 { .start = 512, .end = 512 },
3922 { .start = 1024, .end = 1024 },
3923 { .start = 2048, .end = 2048 },
3924 { .start = 4096, .end = 4096 },
3925 };
3926
mlxsw_sp_adj_grp_size_round_up(const struct mlxsw_sp * mlxsw_sp,u16 * p_adj_grp_size)3927 static void mlxsw_sp_adj_grp_size_round_up(const struct mlxsw_sp *mlxsw_sp,
3928 u16 *p_adj_grp_size)
3929 {
3930 int i;
3931
3932 for (i = 0; i < mlxsw_sp->router->adj_grp_size_ranges_count; i++) {
3933 const struct mlxsw_sp_adj_grp_size_range *size_range;
3934
3935 size_range = &mlxsw_sp->router->adj_grp_size_ranges[i];
3936
3937 if (*p_adj_grp_size >= size_range->start &&
3938 *p_adj_grp_size <= size_range->end)
3939 return;
3940
3941 if (*p_adj_grp_size <= size_range->end) {
3942 *p_adj_grp_size = size_range->end;
3943 return;
3944 }
3945 }
3946 }
3947
mlxsw_sp_adj_grp_size_round_down(const struct mlxsw_sp * mlxsw_sp,u16 * p_adj_grp_size,unsigned int alloc_size)3948 static void mlxsw_sp_adj_grp_size_round_down(const struct mlxsw_sp *mlxsw_sp,
3949 u16 *p_adj_grp_size,
3950 unsigned int alloc_size)
3951 {
3952 int i;
3953
3954 for (i = mlxsw_sp->router->adj_grp_size_ranges_count - 1; i >= 0; i--) {
3955 const struct mlxsw_sp_adj_grp_size_range *size_range;
3956
3957 size_range = &mlxsw_sp->router->adj_grp_size_ranges[i];
3958
3959 if (alloc_size >= size_range->end) {
3960 *p_adj_grp_size = size_range->end;
3961 return;
3962 }
3963 }
3964 }
3965
mlxsw_sp_fix_adj_grp_size(struct mlxsw_sp * mlxsw_sp,u16 * p_adj_grp_size)3966 static int mlxsw_sp_fix_adj_grp_size(struct mlxsw_sp *mlxsw_sp,
3967 u16 *p_adj_grp_size)
3968 {
3969 unsigned int alloc_size;
3970 int err;
3971
3972 /* Round up the requested group size to the next size supported
3973 * by the device and make sure the request can be satisfied.
3974 */
3975 mlxsw_sp_adj_grp_size_round_up(mlxsw_sp, p_adj_grp_size);
3976 err = mlxsw_sp_kvdl_alloc_count_query(mlxsw_sp,
3977 MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
3978 *p_adj_grp_size, &alloc_size);
3979 if (err)
3980 return err;
3981 /* It is possible the allocation results in more allocated
3982 * entries than requested. Try to use as much of them as
3983 * possible.
3984 */
3985 mlxsw_sp_adj_grp_size_round_down(mlxsw_sp, p_adj_grp_size, alloc_size);
3986
3987 return 0;
3988 }
3989
3990 static void
mlxsw_sp_nexthop_group_normalize(struct mlxsw_sp_nexthop_group_info * nhgi)3991 mlxsw_sp_nexthop_group_normalize(struct mlxsw_sp_nexthop_group_info *nhgi)
3992 {
3993 int i, g = 0, sum_norm_weight = 0;
3994 struct mlxsw_sp_nexthop *nh;
3995
3996 for (i = 0; i < nhgi->count; i++) {
3997 nh = &nhgi->nexthops[i];
3998
3999 if (!nh->should_offload)
4000 continue;
4001 if (g > 0)
4002 g = gcd(nh->nh_weight, g);
4003 else
4004 g = nh->nh_weight;
4005 }
4006
4007 for (i = 0; i < nhgi->count; i++) {
4008 nh = &nhgi->nexthops[i];
4009
4010 if (!nh->should_offload)
4011 continue;
4012 nh->norm_nh_weight = nh->nh_weight / g;
4013 sum_norm_weight += nh->norm_nh_weight;
4014 }
4015
4016 nhgi->sum_norm_weight = sum_norm_weight;
4017 }
4018
4019 static void
mlxsw_sp_nexthop_group_rebalance(struct mlxsw_sp_nexthop_group_info * nhgi)4020 mlxsw_sp_nexthop_group_rebalance(struct mlxsw_sp_nexthop_group_info *nhgi)
4021 {
4022 int i, weight = 0, lower_bound = 0;
4023 int total = nhgi->sum_norm_weight;
4024 u16 ecmp_size = nhgi->ecmp_size;
4025
4026 for (i = 0; i < nhgi->count; i++) {
4027 struct mlxsw_sp_nexthop *nh = &nhgi->nexthops[i];
4028 int upper_bound;
4029
4030 if (!nh->should_offload)
4031 continue;
4032 weight += nh->norm_nh_weight;
4033 upper_bound = DIV_ROUND_CLOSEST(ecmp_size * weight, total);
4034 nh->num_adj_entries = upper_bound - lower_bound;
4035 lower_bound = upper_bound;
4036 }
4037 }
4038
4039 static struct mlxsw_sp_nexthop *
4040 mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp,
4041 const struct mlxsw_sp_rt6 *mlxsw_sp_rt6);
4042
4043 static void
mlxsw_sp_nexthop4_group_offload_refresh(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)4044 mlxsw_sp_nexthop4_group_offload_refresh(struct mlxsw_sp *mlxsw_sp,
4045 struct mlxsw_sp_nexthop_group *nh_grp)
4046 {
4047 int i;
4048
4049 for (i = 0; i < nh_grp->nhgi->count; i++) {
4050 struct mlxsw_sp_nexthop *nh = &nh_grp->nhgi->nexthops[i];
4051
4052 if (nh->offloaded)
4053 nh->key.fib_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
4054 else
4055 nh->key.fib_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
4056 }
4057 }
4058
4059 static void
__mlxsw_sp_nexthop6_group_offload_refresh(struct mlxsw_sp_nexthop_group * nh_grp,struct mlxsw_sp_fib6_entry * fib6_entry)4060 __mlxsw_sp_nexthop6_group_offload_refresh(struct mlxsw_sp_nexthop_group *nh_grp,
4061 struct mlxsw_sp_fib6_entry *fib6_entry)
4062 {
4063 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
4064
4065 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
4066 struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
4067 struct mlxsw_sp_nexthop *nh;
4068
4069 nh = mlxsw_sp_rt6_nexthop(nh_grp, mlxsw_sp_rt6);
4070 if (nh && nh->offloaded)
4071 fib6_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
4072 else
4073 fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
4074 }
4075 }
4076
4077 static void
mlxsw_sp_nexthop6_group_offload_refresh(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)4078 mlxsw_sp_nexthop6_group_offload_refresh(struct mlxsw_sp *mlxsw_sp,
4079 struct mlxsw_sp_nexthop_group *nh_grp)
4080 {
4081 struct mlxsw_sp_fib6_entry *fib6_entry;
4082
4083 /* Unfortunately, in IPv6 the route and the nexthop are described by
4084 * the same struct, so we need to iterate over all the routes using the
4085 * nexthop group and set / clear the offload indication for them.
4086 */
4087 list_for_each_entry(fib6_entry, &nh_grp->fib_list,
4088 common.nexthop_group_node)
4089 __mlxsw_sp_nexthop6_group_offload_refresh(nh_grp, fib6_entry);
4090 }
4091
4092 static void
mlxsw_sp_nexthop_bucket_offload_refresh(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_nexthop * nh,u16 bucket_index)4093 mlxsw_sp_nexthop_bucket_offload_refresh(struct mlxsw_sp *mlxsw_sp,
4094 const struct mlxsw_sp_nexthop *nh,
4095 u16 bucket_index)
4096 {
4097 struct mlxsw_sp_nexthop_group *nh_grp = nh->nhgi->nh_grp;
4098 bool offload = false, trap = false;
4099
4100 if (nh->offloaded) {
4101 if (nh->action == MLXSW_SP_NEXTHOP_ACTION_TRAP)
4102 trap = true;
4103 else
4104 offload = true;
4105 }
4106 nexthop_bucket_set_hw_flags(mlxsw_sp_net(mlxsw_sp), nh_grp->obj.id,
4107 bucket_index, offload, trap);
4108 }
4109
4110 static void
mlxsw_sp_nexthop_obj_group_offload_refresh(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)4111 mlxsw_sp_nexthop_obj_group_offload_refresh(struct mlxsw_sp *mlxsw_sp,
4112 struct mlxsw_sp_nexthop_group *nh_grp)
4113 {
4114 int i;
4115
4116 /* Do not update the flags if the nexthop group is being destroyed
4117 * since:
4118 * 1. The nexthop objects is being deleted, in which case the flags are
4119 * irrelevant.
4120 * 2. The nexthop group was replaced by a newer group, in which case
4121 * the flags of the nexthop object were already updated based on the
4122 * new group.
4123 */
4124 if (nh_grp->can_destroy)
4125 return;
4126
4127 nexthop_set_hw_flags(mlxsw_sp_net(mlxsw_sp), nh_grp->obj.id,
4128 nh_grp->nhgi->adj_index_valid, false);
4129
4130 /* Update flags of individual nexthop buckets in case of a resilient
4131 * nexthop group.
4132 */
4133 if (!nh_grp->nhgi->is_resilient)
4134 return;
4135
4136 for (i = 0; i < nh_grp->nhgi->count; i++) {
4137 struct mlxsw_sp_nexthop *nh = &nh_grp->nhgi->nexthops[i];
4138
4139 mlxsw_sp_nexthop_bucket_offload_refresh(mlxsw_sp, nh, i);
4140 }
4141 }
4142
4143 static void
mlxsw_sp_nexthop_group_offload_refresh(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)4144 mlxsw_sp_nexthop_group_offload_refresh(struct mlxsw_sp *mlxsw_sp,
4145 struct mlxsw_sp_nexthop_group *nh_grp)
4146 {
4147 switch (nh_grp->type) {
4148 case MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV4:
4149 mlxsw_sp_nexthop4_group_offload_refresh(mlxsw_sp, nh_grp);
4150 break;
4151 case MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV6:
4152 mlxsw_sp_nexthop6_group_offload_refresh(mlxsw_sp, nh_grp);
4153 break;
4154 case MLXSW_SP_NEXTHOP_GROUP_TYPE_OBJ:
4155 mlxsw_sp_nexthop_obj_group_offload_refresh(mlxsw_sp, nh_grp);
4156 break;
4157 }
4158 }
4159
4160 static int
mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)4161 mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
4162 struct mlxsw_sp_nexthop_group *nh_grp)
4163 {
4164 struct mlxsw_sp_nexthop_group_info *nhgi = nh_grp->nhgi;
4165 u16 ecmp_size, old_ecmp_size;
4166 struct mlxsw_sp_nexthop *nh;
4167 bool offload_change = false;
4168 u32 adj_index;
4169 bool old_adj_index_valid;
4170 u32 old_adj_index;
4171 int i, err2, err;
4172
4173 if (!nhgi->gateway)
4174 return mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
4175
4176 for (i = 0; i < nhgi->count; i++) {
4177 nh = &nhgi->nexthops[i];
4178
4179 if (nh->should_offload != nh->offloaded) {
4180 offload_change = true;
4181 if (nh->should_offload)
4182 nh->update = 1;
4183 }
4184 }
4185 if (!offload_change) {
4186 /* Nothing was added or removed, so no need to reallocate. Just
4187 * update MAC on existing adjacency indexes.
4188 */
4189 err = mlxsw_sp_nexthop_group_update(mlxsw_sp, nhgi, false);
4190 if (err) {
4191 dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
4192 goto set_trap;
4193 }
4194 /* Flags of individual nexthop buckets might need to be
4195 * updated.
4196 */
4197 mlxsw_sp_nexthop_group_offload_refresh(mlxsw_sp, nh_grp);
4198 return 0;
4199 }
4200 mlxsw_sp_nexthop_group_normalize(nhgi);
4201 if (!nhgi->sum_norm_weight) {
4202 /* No neigh of this group is connected so we just set
4203 * the trap and let everthing flow through kernel.
4204 */
4205 err = 0;
4206 goto set_trap;
4207 }
4208
4209 ecmp_size = nhgi->sum_norm_weight;
4210 err = mlxsw_sp_fix_adj_grp_size(mlxsw_sp, &ecmp_size);
4211 if (err)
4212 /* No valid allocation size available. */
4213 goto set_trap;
4214
4215 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
4216 ecmp_size, &adj_index);
4217 if (err) {
4218 /* We ran out of KVD linear space, just set the
4219 * trap and let everything flow through kernel.
4220 */
4221 dev_warn(mlxsw_sp->bus_info->dev, "Failed to allocate KVD linear area for nexthop group.\n");
4222 goto set_trap;
4223 }
4224 old_adj_index_valid = nhgi->adj_index_valid;
4225 old_adj_index = nhgi->adj_index;
4226 old_ecmp_size = nhgi->ecmp_size;
4227 nhgi->adj_index_valid = 1;
4228 nhgi->adj_index = adj_index;
4229 nhgi->ecmp_size = ecmp_size;
4230 mlxsw_sp_nexthop_group_rebalance(nhgi);
4231 err = mlxsw_sp_nexthop_group_update(mlxsw_sp, nhgi, true);
4232 if (err) {
4233 dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
4234 goto set_trap;
4235 }
4236
4237 mlxsw_sp_nexthop_group_offload_refresh(mlxsw_sp, nh_grp);
4238
4239 if (!old_adj_index_valid) {
4240 /* The trap was set for fib entries, so we have to call
4241 * fib entry update to unset it and use adjacency index.
4242 */
4243 err = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
4244 if (err) {
4245 dev_warn(mlxsw_sp->bus_info->dev, "Failed to add adjacency index to fib entries.\n");
4246 goto set_trap;
4247 }
4248 return 0;
4249 }
4250
4251 err = mlxsw_sp_adj_index_mass_update(mlxsw_sp, nh_grp,
4252 old_adj_index, old_ecmp_size);
4253 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
4254 old_ecmp_size, old_adj_index);
4255 if (err) {
4256 dev_warn(mlxsw_sp->bus_info->dev, "Failed to mass-update adjacency index for nexthop group.\n");
4257 goto set_trap;
4258 }
4259
4260 return 0;
4261
4262 set_trap:
4263 old_adj_index_valid = nhgi->adj_index_valid;
4264 nhgi->adj_index_valid = 0;
4265 for (i = 0; i < nhgi->count; i++) {
4266 nh = &nhgi->nexthops[i];
4267 nh->offloaded = 0;
4268 }
4269 err2 = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
4270 if (err2)
4271 dev_warn(mlxsw_sp->bus_info->dev, "Failed to set traps for fib entries.\n");
4272 mlxsw_sp_nexthop_group_offload_refresh(mlxsw_sp, nh_grp);
4273 if (old_adj_index_valid)
4274 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
4275 nhgi->ecmp_size, nhgi->adj_index);
4276 return err;
4277 }
4278
__mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop * nh,bool removing)4279 static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop *nh,
4280 bool removing)
4281 {
4282 if (!removing) {
4283 nh->action = MLXSW_SP_NEXTHOP_ACTION_FORWARD;
4284 nh->should_offload = 1;
4285 } else if (nh->nhgi->is_resilient) {
4286 nh->action = MLXSW_SP_NEXTHOP_ACTION_TRAP;
4287 nh->should_offload = 1;
4288 } else {
4289 nh->should_offload = 0;
4290 }
4291 nh->update = 1;
4292 }
4293
4294 static int
mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry)4295 mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp *mlxsw_sp,
4296 struct mlxsw_sp_neigh_entry *neigh_entry)
4297 {
4298 struct neighbour *n, *old_n = neigh_entry->key.n;
4299 struct mlxsw_sp_nexthop *nh;
4300 struct net_device *dev;
4301 bool entry_connected;
4302 u8 nud_state, dead;
4303 int err;
4304
4305 nh = list_first_entry(&neigh_entry->nexthop_list,
4306 struct mlxsw_sp_nexthop, neigh_list_node);
4307 dev = mlxsw_sp_nexthop_dev(nh);
4308
4309 n = neigh_lookup(nh->neigh_tbl, &nh->gw_addr, dev);
4310 if (!n) {
4311 n = neigh_create(nh->neigh_tbl, &nh->gw_addr, dev);
4312 if (IS_ERR(n))
4313 return PTR_ERR(n);
4314 neigh_event_send(n, NULL);
4315 }
4316
4317 mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
4318 neigh_entry->key.n = n;
4319 err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
4320 if (err)
4321 goto err_neigh_entry_insert;
4322
4323 neigh_release(old_n);
4324
4325 read_lock_bh(&n->lock);
4326 nud_state = n->nud_state;
4327 dead = n->dead;
4328 read_unlock_bh(&n->lock);
4329 entry_connected = nud_state & NUD_VALID && !dead;
4330
4331 list_for_each_entry(nh, &neigh_entry->nexthop_list,
4332 neigh_list_node) {
4333 __mlxsw_sp_nexthop_neigh_update(nh, !entry_connected);
4334 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp);
4335 }
4336
4337 return 0;
4338
4339 err_neigh_entry_insert:
4340 neigh_entry->key.n = old_n;
4341 mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
4342 neigh_release(n);
4343 return err;
4344 }
4345
4346 static void
mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_neigh_entry * neigh_entry,bool removing,bool dead)4347 mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
4348 struct mlxsw_sp_neigh_entry *neigh_entry,
4349 bool removing, bool dead)
4350 {
4351 struct mlxsw_sp_nexthop *nh;
4352
4353 if (list_empty(&neigh_entry->nexthop_list))
4354 return;
4355
4356 if (dead) {
4357 int err;
4358
4359 err = mlxsw_sp_nexthop_dead_neigh_replace(mlxsw_sp,
4360 neigh_entry);
4361 if (err)
4362 dev_err(mlxsw_sp->bus_info->dev, "Failed to replace dead neigh\n");
4363 return;
4364 }
4365
4366 list_for_each_entry(nh, &neigh_entry->nexthop_list,
4367 neigh_list_node) {
4368 __mlxsw_sp_nexthop_neigh_update(nh, removing);
4369 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp);
4370 }
4371 }
4372
mlxsw_sp_nexthop_crif_init(struct mlxsw_sp_nexthop * nh,struct mlxsw_sp_crif * crif)4373 static void mlxsw_sp_nexthop_crif_init(struct mlxsw_sp_nexthop *nh,
4374 struct mlxsw_sp_crif *crif)
4375 {
4376 if (nh->crif)
4377 return;
4378
4379 nh->crif = crif;
4380 list_add(&nh->crif_list_node, &crif->nexthop_list);
4381 }
4382
mlxsw_sp_nexthop_crif_fini(struct mlxsw_sp_nexthop * nh)4383 static void mlxsw_sp_nexthop_crif_fini(struct mlxsw_sp_nexthop *nh)
4384 {
4385 if (!nh->crif)
4386 return;
4387
4388 list_del(&nh->crif_list_node);
4389 nh->crif = NULL;
4390 }
4391
mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)4392 static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp,
4393 struct mlxsw_sp_nexthop *nh)
4394 {
4395 struct mlxsw_sp_neigh_entry *neigh_entry;
4396 struct net_device *dev;
4397 struct neighbour *n;
4398 u8 nud_state, dead;
4399 int err;
4400
4401 if (WARN_ON(!nh->crif->rif))
4402 return 0;
4403
4404 if (!nh->nhgi->gateway || nh->neigh_entry)
4405 return 0;
4406 dev = mlxsw_sp_nexthop_dev(nh);
4407
4408 /* Take a reference of neigh here ensuring that neigh would
4409 * not be destructed before the nexthop entry is finished.
4410 * The reference is taken either in neigh_lookup() or
4411 * in neigh_create() in case n is not found.
4412 */
4413 n = neigh_lookup(nh->neigh_tbl, &nh->gw_addr, dev);
4414 if (!n) {
4415 n = neigh_create(nh->neigh_tbl, &nh->gw_addr, dev);
4416 if (IS_ERR(n))
4417 return PTR_ERR(n);
4418 neigh_event_send(n, NULL);
4419 }
4420 neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
4421 if (!neigh_entry) {
4422 neigh_entry = mlxsw_sp_neigh_entry_create(mlxsw_sp, n);
4423 if (IS_ERR(neigh_entry)) {
4424 err = -EINVAL;
4425 goto err_neigh_entry_create;
4426 }
4427 }
4428
4429 /* Release the reference taken by neigh_lookup() / neigh_create() since
4430 * neigh_entry already holds one.
4431 */
4432 neigh_release(n);
4433
4434 /* If that is the first nexthop connected to that neigh, add to
4435 * nexthop_neighs_list
4436 */
4437 if (list_empty(&neigh_entry->nexthop_list))
4438 list_add_tail(&neigh_entry->nexthop_neighs_list_node,
4439 &mlxsw_sp->router->nexthop_neighs_list);
4440
4441 nh->neigh_entry = neigh_entry;
4442 list_add_tail(&nh->neigh_list_node, &neigh_entry->nexthop_list);
4443 read_lock_bh(&n->lock);
4444 nud_state = n->nud_state;
4445 dead = n->dead;
4446 read_unlock_bh(&n->lock);
4447 __mlxsw_sp_nexthop_neigh_update(nh, !(nud_state & NUD_VALID && !dead));
4448
4449 return 0;
4450
4451 err_neigh_entry_create:
4452 neigh_release(n);
4453 return err;
4454 }
4455
mlxsw_sp_nexthop_neigh_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)4456 static void mlxsw_sp_nexthop_neigh_fini(struct mlxsw_sp *mlxsw_sp,
4457 struct mlxsw_sp_nexthop *nh)
4458 {
4459 struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry;
4460
4461 if (!neigh_entry)
4462 return;
4463
4464 __mlxsw_sp_nexthop_neigh_update(nh, true);
4465 list_del(&nh->neigh_list_node);
4466 nh->neigh_entry = NULL;
4467
4468 /* If that is the last nexthop connected to that neigh, remove from
4469 * nexthop_neighs_list
4470 */
4471 if (list_empty(&neigh_entry->nexthop_list))
4472 list_del(&neigh_entry->nexthop_neighs_list_node);
4473
4474 if (!neigh_entry->connected && list_empty(&neigh_entry->nexthop_list))
4475 mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
4476 }
4477
mlxsw_sp_ipip_netdev_ul_up(struct net_device * ol_dev)4478 static bool mlxsw_sp_ipip_netdev_ul_up(struct net_device *ol_dev)
4479 {
4480 struct net_device *ul_dev;
4481 bool is_up;
4482
4483 rcu_read_lock();
4484 ul_dev = mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
4485 is_up = ul_dev ? (ul_dev->flags & IFF_UP) : true;
4486 rcu_read_unlock();
4487
4488 return is_up;
4489 }
4490
mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh,struct mlxsw_sp_ipip_entry * ipip_entry)4491 static void mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp *mlxsw_sp,
4492 struct mlxsw_sp_nexthop *nh,
4493 struct mlxsw_sp_ipip_entry *ipip_entry)
4494 {
4495 struct mlxsw_sp_crif *crif;
4496 bool removing;
4497
4498 if (!nh->nhgi->gateway || nh->ipip_entry)
4499 return;
4500
4501 crif = mlxsw_sp_crif_lookup(mlxsw_sp->router, ipip_entry->ol_dev);
4502 if (WARN_ON(!crif))
4503 return;
4504
4505 nh->ipip_entry = ipip_entry;
4506 removing = !mlxsw_sp_ipip_netdev_ul_up(ipip_entry->ol_dev);
4507 __mlxsw_sp_nexthop_neigh_update(nh, removing);
4508 mlxsw_sp_nexthop_crif_init(nh, crif);
4509 }
4510
mlxsw_sp_nexthop_ipip_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)4511 static void mlxsw_sp_nexthop_ipip_fini(struct mlxsw_sp *mlxsw_sp,
4512 struct mlxsw_sp_nexthop *nh)
4513 {
4514 struct mlxsw_sp_ipip_entry *ipip_entry = nh->ipip_entry;
4515
4516 if (!ipip_entry)
4517 return;
4518
4519 __mlxsw_sp_nexthop_neigh_update(nh, true);
4520 nh->ipip_entry = NULL;
4521 }
4522
mlxsw_sp_nexthop4_ipip_type(const struct mlxsw_sp * mlxsw_sp,const struct fib_nh * fib_nh,enum mlxsw_sp_ipip_type * p_ipipt)4523 static bool mlxsw_sp_nexthop4_ipip_type(const struct mlxsw_sp *mlxsw_sp,
4524 const struct fib_nh *fib_nh,
4525 enum mlxsw_sp_ipip_type *p_ipipt)
4526 {
4527 struct net_device *dev = fib_nh->fib_nh_dev;
4528
4529 return dev &&
4530 fib_nh->nh_parent->fib_type == RTN_UNICAST &&
4531 mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, p_ipipt);
4532 }
4533
mlxsw_sp_nexthop_type_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh,const struct net_device * dev)4534 static int mlxsw_sp_nexthop_type_init(struct mlxsw_sp *mlxsw_sp,
4535 struct mlxsw_sp_nexthop *nh,
4536 const struct net_device *dev)
4537 {
4538 const struct mlxsw_sp_ipip_ops *ipip_ops;
4539 struct mlxsw_sp_ipip_entry *ipip_entry;
4540 struct mlxsw_sp_crif *crif;
4541 int err;
4542
4543 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, dev);
4544 if (ipip_entry) {
4545 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
4546 if (ipip_ops->can_offload(mlxsw_sp, dev)) {
4547 nh->type = MLXSW_SP_NEXTHOP_TYPE_IPIP;
4548 mlxsw_sp_nexthop_ipip_init(mlxsw_sp, nh, ipip_entry);
4549 return 0;
4550 }
4551 }
4552
4553 nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH;
4554 crif = mlxsw_sp_crif_lookup(mlxsw_sp->router, dev);
4555 if (!crif)
4556 return 0;
4557
4558 mlxsw_sp_nexthop_crif_init(nh, crif);
4559
4560 if (!crif->rif)
4561 return 0;
4562
4563 err = mlxsw_sp_nexthop_neigh_init(mlxsw_sp, nh);
4564 if (err)
4565 goto err_neigh_init;
4566
4567 return 0;
4568
4569 err_neigh_init:
4570 mlxsw_sp_nexthop_crif_fini(nh);
4571 return err;
4572 }
4573
mlxsw_sp_nexthop_type_rif_made(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)4574 static int mlxsw_sp_nexthop_type_rif_made(struct mlxsw_sp *mlxsw_sp,
4575 struct mlxsw_sp_nexthop *nh)
4576 {
4577 switch (nh->type) {
4578 case MLXSW_SP_NEXTHOP_TYPE_ETH:
4579 return mlxsw_sp_nexthop_neigh_init(mlxsw_sp, nh);
4580 case MLXSW_SP_NEXTHOP_TYPE_IPIP:
4581 break;
4582 }
4583
4584 return 0;
4585 }
4586
mlxsw_sp_nexthop_type_rif_gone(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)4587 static void mlxsw_sp_nexthop_type_rif_gone(struct mlxsw_sp *mlxsw_sp,
4588 struct mlxsw_sp_nexthop *nh)
4589 {
4590 switch (nh->type) {
4591 case MLXSW_SP_NEXTHOP_TYPE_ETH:
4592 mlxsw_sp_nexthop_neigh_fini(mlxsw_sp, nh);
4593 break;
4594 case MLXSW_SP_NEXTHOP_TYPE_IPIP:
4595 mlxsw_sp_nexthop_ipip_fini(mlxsw_sp, nh);
4596 break;
4597 }
4598 }
4599
mlxsw_sp_nexthop_type_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)4600 static void mlxsw_sp_nexthop_type_fini(struct mlxsw_sp *mlxsw_sp,
4601 struct mlxsw_sp_nexthop *nh)
4602 {
4603 mlxsw_sp_nexthop_type_rif_gone(mlxsw_sp, nh);
4604 mlxsw_sp_nexthop_crif_fini(nh);
4605 }
4606
mlxsw_sp_nexthop4_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,struct mlxsw_sp_nexthop * nh,struct fib_nh * fib_nh)4607 static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp,
4608 struct mlxsw_sp_nexthop_group *nh_grp,
4609 struct mlxsw_sp_nexthop *nh,
4610 struct fib_nh *fib_nh)
4611 {
4612 struct net_device *dev = fib_nh->fib_nh_dev;
4613 struct in_device *in_dev;
4614 int err;
4615
4616 nh->nhgi = nh_grp->nhgi;
4617 nh->key.fib_nh = fib_nh;
4618 #ifdef CONFIG_IP_ROUTE_MULTIPATH
4619 nh->nh_weight = fib_nh->fib_nh_weight;
4620 #else
4621 nh->nh_weight = 1;
4622 #endif
4623 memcpy(&nh->gw_addr, &fib_nh->fib_nh_gw4, sizeof(fib_nh->fib_nh_gw4));
4624 nh->neigh_tbl = &arp_tbl;
4625 err = mlxsw_sp_nexthop_insert(mlxsw_sp, nh);
4626 if (err)
4627 return err;
4628
4629 err = mlxsw_sp_nexthop_counter_enable(mlxsw_sp, nh);
4630 if (err)
4631 goto err_counter_enable;
4632
4633 list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
4634
4635 if (!dev)
4636 return 0;
4637 nh->ifindex = dev->ifindex;
4638
4639 rcu_read_lock();
4640 in_dev = __in_dev_get_rcu(dev);
4641 if (in_dev && IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
4642 fib_nh->fib_nh_flags & RTNH_F_LINKDOWN) {
4643 rcu_read_unlock();
4644 return 0;
4645 }
4646 rcu_read_unlock();
4647
4648 err = mlxsw_sp_nexthop_type_init(mlxsw_sp, nh, dev);
4649 if (err)
4650 goto err_nexthop_neigh_init;
4651
4652 return 0;
4653
4654 err_nexthop_neigh_init:
4655 list_del(&nh->router_list_node);
4656 mlxsw_sp_nexthop_counter_disable(mlxsw_sp, nh);
4657 err_counter_enable:
4658 mlxsw_sp_nexthop_remove(mlxsw_sp, nh);
4659 return err;
4660 }
4661
mlxsw_sp_nexthop4_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)4662 static void mlxsw_sp_nexthop4_fini(struct mlxsw_sp *mlxsw_sp,
4663 struct mlxsw_sp_nexthop *nh)
4664 {
4665 mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh);
4666 list_del(&nh->router_list_node);
4667 mlxsw_sp_nexthop_counter_disable(mlxsw_sp, nh);
4668 mlxsw_sp_nexthop_remove(mlxsw_sp, nh);
4669 }
4670
mlxsw_sp_nexthop4_event(struct mlxsw_sp * mlxsw_sp,unsigned long event,struct fib_nh * fib_nh)4671 static void mlxsw_sp_nexthop4_event(struct mlxsw_sp *mlxsw_sp,
4672 unsigned long event, struct fib_nh *fib_nh)
4673 {
4674 struct mlxsw_sp_nexthop_key key;
4675 struct mlxsw_sp_nexthop *nh;
4676
4677 key.fib_nh = fib_nh;
4678 nh = mlxsw_sp_nexthop_lookup(mlxsw_sp, key);
4679 if (!nh)
4680 return;
4681
4682 switch (event) {
4683 case FIB_EVENT_NH_ADD:
4684 mlxsw_sp_nexthop_type_init(mlxsw_sp, nh, fib_nh->fib_nh_dev);
4685 break;
4686 case FIB_EVENT_NH_DEL:
4687 mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh);
4688 break;
4689 }
4690
4691 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp);
4692 }
4693
mlxsw_sp_nexthop_rif_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif)4694 static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp,
4695 struct mlxsw_sp_rif *rif)
4696 {
4697 struct net_device *dev = mlxsw_sp_rif_dev(rif);
4698 struct mlxsw_sp_nexthop *nh;
4699 bool removing;
4700
4701 list_for_each_entry(nh, &rif->crif->nexthop_list, crif_list_node) {
4702 switch (nh->type) {
4703 case MLXSW_SP_NEXTHOP_TYPE_ETH:
4704 removing = false;
4705 break;
4706 case MLXSW_SP_NEXTHOP_TYPE_IPIP:
4707 removing = !mlxsw_sp_ipip_netdev_ul_up(dev);
4708 break;
4709 default:
4710 WARN_ON(1);
4711 continue;
4712 }
4713
4714 __mlxsw_sp_nexthop_neigh_update(nh, removing);
4715 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp);
4716 }
4717 }
4718
mlxsw_sp_nexthop_rif_made_sync(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif)4719 static int mlxsw_sp_nexthop_rif_made_sync(struct mlxsw_sp *mlxsw_sp,
4720 struct mlxsw_sp_rif *rif)
4721 {
4722 struct mlxsw_sp_nexthop *nh, *tmp;
4723 unsigned int n = 0;
4724 int err;
4725
4726 list_for_each_entry_safe(nh, tmp, &rif->crif->nexthop_list,
4727 crif_list_node) {
4728 err = mlxsw_sp_nexthop_type_rif_made(mlxsw_sp, nh);
4729 if (err)
4730 goto err_nexthop_type_rif;
4731 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp);
4732 n++;
4733 }
4734
4735 return 0;
4736
4737 err_nexthop_type_rif:
4738 list_for_each_entry_safe(nh, tmp, &rif->crif->nexthop_list,
4739 crif_list_node) {
4740 if (!n--)
4741 break;
4742 mlxsw_sp_nexthop_type_rif_gone(mlxsw_sp, nh);
4743 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp);
4744 }
4745 return err;
4746 }
4747
mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif)4748 static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
4749 struct mlxsw_sp_rif *rif)
4750 {
4751 struct mlxsw_sp_nexthop *nh, *tmp;
4752
4753 list_for_each_entry_safe(nh, tmp, &rif->crif->nexthop_list,
4754 crif_list_node) {
4755 mlxsw_sp_nexthop_type_rif_gone(mlxsw_sp, nh);
4756 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp);
4757 }
4758 }
4759
mlxsw_sp_adj_trap_entry_init(struct mlxsw_sp * mlxsw_sp)4760 static int mlxsw_sp_adj_trap_entry_init(struct mlxsw_sp *mlxsw_sp)
4761 {
4762 enum mlxsw_reg_ratr_trap_action trap_action;
4763 char ratr_pl[MLXSW_REG_RATR_LEN];
4764 int err;
4765
4766 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
4767 &mlxsw_sp->router->adj_trap_index);
4768 if (err)
4769 return err;
4770
4771 trap_action = MLXSW_REG_RATR_TRAP_ACTION_TRAP;
4772 mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, true,
4773 MLXSW_REG_RATR_TYPE_ETHERNET,
4774 mlxsw_sp->router->adj_trap_index,
4775 mlxsw_sp->router->lb_crif->rif->rif_index);
4776 mlxsw_reg_ratr_trap_action_set(ratr_pl, trap_action);
4777 mlxsw_reg_ratr_trap_id_set(ratr_pl, MLXSW_TRAP_ID_RTR_EGRESS0);
4778 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
4779 if (err)
4780 goto err_ratr_write;
4781
4782 return 0;
4783
4784 err_ratr_write:
4785 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
4786 mlxsw_sp->router->adj_trap_index);
4787 return err;
4788 }
4789
mlxsw_sp_adj_trap_entry_fini(struct mlxsw_sp * mlxsw_sp)4790 static void mlxsw_sp_adj_trap_entry_fini(struct mlxsw_sp *mlxsw_sp)
4791 {
4792 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
4793 mlxsw_sp->router->adj_trap_index);
4794 }
4795
mlxsw_sp_nexthop_group_inc(struct mlxsw_sp * mlxsw_sp)4796 static int mlxsw_sp_nexthop_group_inc(struct mlxsw_sp *mlxsw_sp)
4797 {
4798 int err;
4799
4800 if (refcount_inc_not_zero(&mlxsw_sp->router->num_groups))
4801 return 0;
4802
4803 err = mlxsw_sp_adj_trap_entry_init(mlxsw_sp);
4804 if (err)
4805 return err;
4806
4807 refcount_set(&mlxsw_sp->router->num_groups, 1);
4808
4809 return 0;
4810 }
4811
mlxsw_sp_nexthop_group_dec(struct mlxsw_sp * mlxsw_sp)4812 static void mlxsw_sp_nexthop_group_dec(struct mlxsw_sp *mlxsw_sp)
4813 {
4814 if (!refcount_dec_and_test(&mlxsw_sp->router->num_groups))
4815 return;
4816
4817 mlxsw_sp_adj_trap_entry_fini(mlxsw_sp);
4818 }
4819
4820 static void
mlxsw_sp_nh_grp_activity_get(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_nexthop_group * nh_grp,unsigned long * activity)4821 mlxsw_sp_nh_grp_activity_get(struct mlxsw_sp *mlxsw_sp,
4822 const struct mlxsw_sp_nexthop_group *nh_grp,
4823 unsigned long *activity)
4824 {
4825 char *ratrad_pl;
4826 int i, err;
4827
4828 ratrad_pl = kmalloc(MLXSW_REG_RATRAD_LEN, GFP_KERNEL);
4829 if (!ratrad_pl)
4830 return;
4831
4832 mlxsw_reg_ratrad_pack(ratrad_pl, nh_grp->nhgi->adj_index,
4833 nh_grp->nhgi->count);
4834 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ratrad), ratrad_pl);
4835 if (err)
4836 goto out;
4837
4838 for (i = 0; i < nh_grp->nhgi->count; i++) {
4839 if (!mlxsw_reg_ratrad_activity_vector_get(ratrad_pl, i))
4840 continue;
4841 bitmap_set(activity, i, 1);
4842 }
4843
4844 out:
4845 kfree(ratrad_pl);
4846 }
4847
4848 #define MLXSW_SP_NH_GRP_ACTIVITY_UPDATE_INTERVAL 1000 /* ms */
4849
4850 static void
mlxsw_sp_nh_grp_activity_update(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_nexthop_group * nh_grp)4851 mlxsw_sp_nh_grp_activity_update(struct mlxsw_sp *mlxsw_sp,
4852 const struct mlxsw_sp_nexthop_group *nh_grp)
4853 {
4854 unsigned long *activity;
4855
4856 activity = bitmap_zalloc(nh_grp->nhgi->count, GFP_KERNEL);
4857 if (!activity)
4858 return;
4859
4860 mlxsw_sp_nh_grp_activity_get(mlxsw_sp, nh_grp, activity);
4861 nexthop_res_grp_activity_update(mlxsw_sp_net(mlxsw_sp), nh_grp->obj.id,
4862 nh_grp->nhgi->count, activity);
4863
4864 bitmap_free(activity);
4865 }
4866
4867 static void
mlxsw_sp_nh_grp_activity_work_schedule(struct mlxsw_sp * mlxsw_sp)4868 mlxsw_sp_nh_grp_activity_work_schedule(struct mlxsw_sp *mlxsw_sp)
4869 {
4870 unsigned int interval = MLXSW_SP_NH_GRP_ACTIVITY_UPDATE_INTERVAL;
4871
4872 mlxsw_core_schedule_dw(&mlxsw_sp->router->nh_grp_activity_dw,
4873 msecs_to_jiffies(interval));
4874 }
4875
mlxsw_sp_nh_grp_activity_work(struct work_struct * work)4876 static void mlxsw_sp_nh_grp_activity_work(struct work_struct *work)
4877 {
4878 struct mlxsw_sp_nexthop_group_info *nhgi;
4879 struct mlxsw_sp_router *router;
4880 bool reschedule = false;
4881
4882 router = container_of(work, struct mlxsw_sp_router,
4883 nh_grp_activity_dw.work);
4884
4885 mutex_lock(&router->lock);
4886
4887 list_for_each_entry(nhgi, &router->nh_res_grp_list, list) {
4888 mlxsw_sp_nh_grp_activity_update(router->mlxsw_sp, nhgi->nh_grp);
4889 reschedule = true;
4890 }
4891
4892 mutex_unlock(&router->lock);
4893
4894 if (!reschedule)
4895 return;
4896 mlxsw_sp_nh_grp_activity_work_schedule(router->mlxsw_sp);
4897 }
4898
4899 static int
mlxsw_sp_nexthop_obj_single_validate(struct mlxsw_sp * mlxsw_sp,const struct nh_notifier_single_info * nh,struct netlink_ext_ack * extack)4900 mlxsw_sp_nexthop_obj_single_validate(struct mlxsw_sp *mlxsw_sp,
4901 const struct nh_notifier_single_info *nh,
4902 struct netlink_ext_ack *extack)
4903 {
4904 int err = -EINVAL;
4905
4906 if (nh->is_fdb)
4907 NL_SET_ERR_MSG_MOD(extack, "FDB nexthops are not supported");
4908 else if (nh->has_encap)
4909 NL_SET_ERR_MSG_MOD(extack, "Encapsulating nexthops are not supported");
4910 else
4911 err = 0;
4912
4913 return err;
4914 }
4915
4916 static int
mlxsw_sp_nexthop_obj_group_entry_validate(struct mlxsw_sp * mlxsw_sp,const struct nh_notifier_single_info * nh,struct netlink_ext_ack * extack)4917 mlxsw_sp_nexthop_obj_group_entry_validate(struct mlxsw_sp *mlxsw_sp,
4918 const struct nh_notifier_single_info *nh,
4919 struct netlink_ext_ack *extack)
4920 {
4921 int err;
4922
4923 err = mlxsw_sp_nexthop_obj_single_validate(mlxsw_sp, nh, extack);
4924 if (err)
4925 return err;
4926
4927 /* Device only nexthops with an IPIP device are programmed as
4928 * encapsulating adjacency entries.
4929 */
4930 if (!nh->gw_family && !nh->is_reject &&
4931 !mlxsw_sp_netdev_ipip_type(mlxsw_sp, nh->dev, NULL)) {
4932 NL_SET_ERR_MSG_MOD(extack, "Nexthop group entry does not have a gateway");
4933 return -EINVAL;
4934 }
4935
4936 return 0;
4937 }
4938
4939 static int
mlxsw_sp_nexthop_obj_group_validate(struct mlxsw_sp * mlxsw_sp,const struct nh_notifier_grp_info * nh_grp,struct netlink_ext_ack * extack)4940 mlxsw_sp_nexthop_obj_group_validate(struct mlxsw_sp *mlxsw_sp,
4941 const struct nh_notifier_grp_info *nh_grp,
4942 struct netlink_ext_ack *extack)
4943 {
4944 int i;
4945
4946 if (nh_grp->is_fdb) {
4947 NL_SET_ERR_MSG_MOD(extack, "FDB nexthop groups are not supported");
4948 return -EINVAL;
4949 }
4950
4951 for (i = 0; i < nh_grp->num_nh; i++) {
4952 const struct nh_notifier_single_info *nh;
4953 int err;
4954
4955 nh = &nh_grp->nh_entries[i].nh;
4956 err = mlxsw_sp_nexthop_obj_group_entry_validate(mlxsw_sp, nh,
4957 extack);
4958 if (err)
4959 return err;
4960 }
4961
4962 return 0;
4963 }
4964
4965 static int
mlxsw_sp_nexthop_obj_res_group_size_validate(struct mlxsw_sp * mlxsw_sp,const struct nh_notifier_res_table_info * nh_res_table,struct netlink_ext_ack * extack)4966 mlxsw_sp_nexthop_obj_res_group_size_validate(struct mlxsw_sp *mlxsw_sp,
4967 const struct nh_notifier_res_table_info *nh_res_table,
4968 struct netlink_ext_ack *extack)
4969 {
4970 unsigned int alloc_size;
4971 bool valid_size = false;
4972 int err, i;
4973
4974 if (nh_res_table->num_nh_buckets < 32) {
4975 NL_SET_ERR_MSG_MOD(extack, "Minimum number of buckets is 32");
4976 return -EINVAL;
4977 }
4978
4979 for (i = 0; i < mlxsw_sp->router->adj_grp_size_ranges_count; i++) {
4980 const struct mlxsw_sp_adj_grp_size_range *size_range;
4981
4982 size_range = &mlxsw_sp->router->adj_grp_size_ranges[i];
4983
4984 if (nh_res_table->num_nh_buckets >= size_range->start &&
4985 nh_res_table->num_nh_buckets <= size_range->end) {
4986 valid_size = true;
4987 break;
4988 }
4989 }
4990
4991 if (!valid_size) {
4992 NL_SET_ERR_MSG_MOD(extack, "Invalid number of buckets");
4993 return -EINVAL;
4994 }
4995
4996 err = mlxsw_sp_kvdl_alloc_count_query(mlxsw_sp,
4997 MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
4998 nh_res_table->num_nh_buckets,
4999 &alloc_size);
5000 if (err || nh_res_table->num_nh_buckets != alloc_size) {
5001 NL_SET_ERR_MSG_MOD(extack, "Number of buckets does not fit allocation size of any KVDL partition");
5002 return -EINVAL;
5003 }
5004
5005 return 0;
5006 }
5007
5008 static int
mlxsw_sp_nexthop_obj_res_group_validate(struct mlxsw_sp * mlxsw_sp,const struct nh_notifier_res_table_info * nh_res_table,struct netlink_ext_ack * extack)5009 mlxsw_sp_nexthop_obj_res_group_validate(struct mlxsw_sp *mlxsw_sp,
5010 const struct nh_notifier_res_table_info *nh_res_table,
5011 struct netlink_ext_ack *extack)
5012 {
5013 int err;
5014 u16 i;
5015
5016 err = mlxsw_sp_nexthop_obj_res_group_size_validate(mlxsw_sp,
5017 nh_res_table,
5018 extack);
5019 if (err)
5020 return err;
5021
5022 for (i = 0; i < nh_res_table->num_nh_buckets; i++) {
5023 const struct nh_notifier_single_info *nh;
5024 int err;
5025
5026 nh = &nh_res_table->nhs[i];
5027 err = mlxsw_sp_nexthop_obj_group_entry_validate(mlxsw_sp, nh,
5028 extack);
5029 if (err)
5030 return err;
5031 }
5032
5033 return 0;
5034 }
5035
mlxsw_sp_nexthop_obj_validate(struct mlxsw_sp * mlxsw_sp,unsigned long event,struct nh_notifier_info * info)5036 static int mlxsw_sp_nexthop_obj_validate(struct mlxsw_sp *mlxsw_sp,
5037 unsigned long event,
5038 struct nh_notifier_info *info)
5039 {
5040 struct nh_notifier_single_info *nh;
5041
5042 if (event != NEXTHOP_EVENT_REPLACE &&
5043 event != NEXTHOP_EVENT_RES_TABLE_PRE_REPLACE &&
5044 event != NEXTHOP_EVENT_BUCKET_REPLACE)
5045 return 0;
5046
5047 switch (info->type) {
5048 case NH_NOTIFIER_INFO_TYPE_SINGLE:
5049 return mlxsw_sp_nexthop_obj_single_validate(mlxsw_sp, info->nh,
5050 info->extack);
5051 case NH_NOTIFIER_INFO_TYPE_GRP:
5052 return mlxsw_sp_nexthop_obj_group_validate(mlxsw_sp,
5053 info->nh_grp,
5054 info->extack);
5055 case NH_NOTIFIER_INFO_TYPE_RES_TABLE:
5056 return mlxsw_sp_nexthop_obj_res_group_validate(mlxsw_sp,
5057 info->nh_res_table,
5058 info->extack);
5059 case NH_NOTIFIER_INFO_TYPE_RES_BUCKET:
5060 nh = &info->nh_res_bucket->new_nh;
5061 return mlxsw_sp_nexthop_obj_group_entry_validate(mlxsw_sp, nh,
5062 info->extack);
5063 default:
5064 NL_SET_ERR_MSG_MOD(info->extack, "Unsupported nexthop type");
5065 return -EOPNOTSUPP;
5066 }
5067 }
5068
mlxsw_sp_nexthop_obj_is_gateway(struct mlxsw_sp * mlxsw_sp,const struct nh_notifier_info * info)5069 static bool mlxsw_sp_nexthop_obj_is_gateway(struct mlxsw_sp *mlxsw_sp,
5070 const struct nh_notifier_info *info)
5071 {
5072 const struct net_device *dev;
5073
5074 switch (info->type) {
5075 case NH_NOTIFIER_INFO_TYPE_SINGLE:
5076 dev = info->nh->dev;
5077 return info->nh->gw_family || info->nh->is_reject ||
5078 mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, NULL);
5079 case NH_NOTIFIER_INFO_TYPE_GRP:
5080 case NH_NOTIFIER_INFO_TYPE_RES_TABLE:
5081 /* Already validated earlier. */
5082 return true;
5083 default:
5084 return false;
5085 }
5086 }
5087
mlxsw_sp_nexthop_obj_blackhole_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)5088 static void mlxsw_sp_nexthop_obj_blackhole_init(struct mlxsw_sp *mlxsw_sp,
5089 struct mlxsw_sp_nexthop *nh)
5090 {
5091 nh->action = MLXSW_SP_NEXTHOP_ACTION_DISCARD;
5092 nh->should_offload = 1;
5093 /* While nexthops that discard packets do not forward packets
5094 * via an egress RIF, they still need to be programmed using a
5095 * valid RIF, so use the loopback RIF created during init.
5096 */
5097 nh->crif = mlxsw_sp->router->lb_crif;
5098 }
5099
mlxsw_sp_nexthop_obj_blackhole_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)5100 static void mlxsw_sp_nexthop_obj_blackhole_fini(struct mlxsw_sp *mlxsw_sp,
5101 struct mlxsw_sp_nexthop *nh)
5102 {
5103 nh->crif = NULL;
5104 nh->should_offload = 0;
5105 }
5106
5107 static int
mlxsw_sp_nexthop_obj_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,struct mlxsw_sp_nexthop * nh,struct nh_notifier_single_info * nh_obj,int weight)5108 mlxsw_sp_nexthop_obj_init(struct mlxsw_sp *mlxsw_sp,
5109 struct mlxsw_sp_nexthop_group *nh_grp,
5110 struct mlxsw_sp_nexthop *nh,
5111 struct nh_notifier_single_info *nh_obj, int weight)
5112 {
5113 struct net_device *dev = nh_obj->dev;
5114 int err;
5115
5116 nh->nhgi = nh_grp->nhgi;
5117 nh->nh_weight = weight;
5118
5119 switch (nh_obj->gw_family) {
5120 case AF_INET:
5121 memcpy(&nh->gw_addr, &nh_obj->ipv4, sizeof(nh_obj->ipv4));
5122 nh->neigh_tbl = &arp_tbl;
5123 break;
5124 case AF_INET6:
5125 memcpy(&nh->gw_addr, &nh_obj->ipv6, sizeof(nh_obj->ipv6));
5126 #if IS_ENABLED(CONFIG_IPV6)
5127 nh->neigh_tbl = &nd_tbl;
5128 #endif
5129 break;
5130 }
5131
5132 list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
5133 nh->ifindex = dev->ifindex;
5134 nh->id = nh_obj->id;
5135
5136 err = mlxsw_sp_nexthop_type_init(mlxsw_sp, nh, dev);
5137 if (err)
5138 goto err_type_init;
5139
5140 if (nh_obj->is_reject)
5141 mlxsw_sp_nexthop_obj_blackhole_init(mlxsw_sp, nh);
5142
5143 /* In a resilient nexthop group, all the nexthops must be written to
5144 * the adjacency table. Even if they do not have a valid neighbour or
5145 * RIF.
5146 */
5147 if (nh_grp->nhgi->is_resilient && !nh->should_offload) {
5148 nh->action = MLXSW_SP_NEXTHOP_ACTION_TRAP;
5149 nh->should_offload = 1;
5150 }
5151
5152 return 0;
5153
5154 err_type_init:
5155 list_del(&nh->router_list_node);
5156 return err;
5157 }
5158
mlxsw_sp_nexthop_obj_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)5159 static void mlxsw_sp_nexthop_obj_fini(struct mlxsw_sp *mlxsw_sp,
5160 struct mlxsw_sp_nexthop *nh)
5161 {
5162 if (nh->action == MLXSW_SP_NEXTHOP_ACTION_DISCARD)
5163 mlxsw_sp_nexthop_obj_blackhole_fini(mlxsw_sp, nh);
5164 mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh);
5165 list_del(&nh->router_list_node);
5166 mlxsw_sp_nexthop_counter_disable(mlxsw_sp, nh);
5167 nh->should_offload = 0;
5168 }
5169
5170 static int
mlxsw_sp_nexthop_obj_group_info_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,struct nh_notifier_info * info)5171 mlxsw_sp_nexthop_obj_group_info_init(struct mlxsw_sp *mlxsw_sp,
5172 struct mlxsw_sp_nexthop_group *nh_grp,
5173 struct nh_notifier_info *info)
5174 {
5175 struct mlxsw_sp_nexthop_group_info *nhgi;
5176 struct mlxsw_sp_nexthop *nh;
5177 bool is_resilient = false;
5178 bool hw_stats = false;
5179 unsigned int nhs;
5180 int err, i;
5181
5182 switch (info->type) {
5183 case NH_NOTIFIER_INFO_TYPE_SINGLE:
5184 nhs = 1;
5185 break;
5186 case NH_NOTIFIER_INFO_TYPE_GRP:
5187 nhs = info->nh_grp->num_nh;
5188 hw_stats = info->nh_grp->hw_stats;
5189 break;
5190 case NH_NOTIFIER_INFO_TYPE_RES_TABLE:
5191 nhs = info->nh_res_table->num_nh_buckets;
5192 hw_stats = info->nh_res_table->hw_stats;
5193 is_resilient = true;
5194 break;
5195 default:
5196 return -EINVAL;
5197 }
5198
5199 nhgi = kzalloc_flex(*nhgi, nexthops, nhs);
5200 if (!nhgi)
5201 return -ENOMEM;
5202 nh_grp->nhgi = nhgi;
5203 nhgi->nh_grp = nh_grp;
5204 nhgi->gateway = mlxsw_sp_nexthop_obj_is_gateway(mlxsw_sp, info);
5205 nhgi->is_resilient = is_resilient;
5206 nhgi->count = nhs;
5207 nhgi->hw_stats = hw_stats;
5208
5209 xa_init_flags(&nhgi->nexthop_counters, XA_FLAGS_ALLOC1);
5210
5211 for (i = 0; i < nhgi->count; i++) {
5212 struct nh_notifier_single_info *nh_obj;
5213 int weight;
5214
5215 nh = &nhgi->nexthops[i];
5216 switch (info->type) {
5217 case NH_NOTIFIER_INFO_TYPE_SINGLE:
5218 nh_obj = info->nh;
5219 weight = 1;
5220 break;
5221 case NH_NOTIFIER_INFO_TYPE_GRP:
5222 nh_obj = &info->nh_grp->nh_entries[i].nh;
5223 weight = info->nh_grp->nh_entries[i].weight;
5224 break;
5225 case NH_NOTIFIER_INFO_TYPE_RES_TABLE:
5226 nh_obj = &info->nh_res_table->nhs[i];
5227 weight = 1;
5228 break;
5229 default:
5230 err = -EINVAL;
5231 goto err_nexthop_obj_init;
5232 }
5233 err = mlxsw_sp_nexthop_obj_init(mlxsw_sp, nh_grp, nh, nh_obj,
5234 weight);
5235 if (err)
5236 goto err_nexthop_obj_init;
5237 }
5238 err = mlxsw_sp_nexthop_group_inc(mlxsw_sp);
5239 if (err)
5240 goto err_group_inc;
5241 err = mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
5242 if (err) {
5243 NL_SET_ERR_MSG_MOD(info->extack, "Failed to write adjacency entries to the device");
5244 goto err_group_refresh;
5245 }
5246
5247 /* Add resilient nexthop groups to a list so that the activity of their
5248 * nexthop buckets will be periodically queried and cleared.
5249 */
5250 if (nhgi->is_resilient) {
5251 if (list_empty(&mlxsw_sp->router->nh_res_grp_list))
5252 mlxsw_sp_nh_grp_activity_work_schedule(mlxsw_sp);
5253 list_add(&nhgi->list, &mlxsw_sp->router->nh_res_grp_list);
5254 }
5255
5256 return 0;
5257
5258 err_group_refresh:
5259 mlxsw_sp_nexthop_group_dec(mlxsw_sp);
5260 err_group_inc:
5261 i = nhgi->count;
5262 err_nexthop_obj_init:
5263 for (i--; i >= 0; i--) {
5264 nh = &nhgi->nexthops[i];
5265 mlxsw_sp_nexthop_obj_fini(mlxsw_sp, nh);
5266 }
5267 kfree(nhgi);
5268 return err;
5269 }
5270
5271 static void
mlxsw_sp_nexthop_obj_group_info_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)5272 mlxsw_sp_nexthop_obj_group_info_fini(struct mlxsw_sp *mlxsw_sp,
5273 struct mlxsw_sp_nexthop_group *nh_grp)
5274 {
5275 struct mlxsw_sp_nexthop_group_info *nhgi = nh_grp->nhgi;
5276 struct mlxsw_sp_router *router = mlxsw_sp->router;
5277 int i;
5278
5279 if (nhgi->is_resilient) {
5280 list_del(&nhgi->list);
5281 if (list_empty(&mlxsw_sp->router->nh_res_grp_list))
5282 cancel_delayed_work(&router->nh_grp_activity_dw);
5283 }
5284
5285 mlxsw_sp_nexthop_group_dec(mlxsw_sp);
5286 for (i = nhgi->count - 1; i >= 0; i--) {
5287 struct mlxsw_sp_nexthop *nh = &nhgi->nexthops[i];
5288
5289 mlxsw_sp_nexthop_obj_fini(mlxsw_sp, nh);
5290 }
5291 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
5292 WARN_ON_ONCE(nhgi->adj_index_valid);
5293 WARN_ON(!xa_empty(&nhgi->nexthop_counters));
5294 xa_destroy(&nhgi->nexthop_counters);
5295 kfree(nhgi);
5296 }
5297
5298 static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop_obj_group_create(struct mlxsw_sp * mlxsw_sp,struct nh_notifier_info * info)5299 mlxsw_sp_nexthop_obj_group_create(struct mlxsw_sp *mlxsw_sp,
5300 struct nh_notifier_info *info)
5301 {
5302 struct mlxsw_sp_nexthop_group *nh_grp;
5303 int err;
5304
5305 nh_grp = kzalloc_obj(*nh_grp);
5306 if (!nh_grp)
5307 return ERR_PTR(-ENOMEM);
5308 INIT_LIST_HEAD(&nh_grp->vr_list);
5309 err = rhashtable_init(&nh_grp->vr_ht,
5310 &mlxsw_sp_nexthop_group_vr_ht_params);
5311 if (err)
5312 goto err_nexthop_group_vr_ht_init;
5313 INIT_LIST_HEAD(&nh_grp->fib_list);
5314 nh_grp->type = MLXSW_SP_NEXTHOP_GROUP_TYPE_OBJ;
5315 nh_grp->obj.id = info->id;
5316
5317 err = mlxsw_sp_nexthop_obj_group_info_init(mlxsw_sp, nh_grp, info);
5318 if (err)
5319 goto err_nexthop_group_info_init;
5320
5321 nh_grp->can_destroy = false;
5322
5323 return nh_grp;
5324
5325 err_nexthop_group_info_init:
5326 rhashtable_destroy(&nh_grp->vr_ht);
5327 err_nexthop_group_vr_ht_init:
5328 kfree(nh_grp);
5329 return ERR_PTR(err);
5330 }
5331
5332 static void
mlxsw_sp_nexthop_obj_group_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)5333 mlxsw_sp_nexthop_obj_group_destroy(struct mlxsw_sp *mlxsw_sp,
5334 struct mlxsw_sp_nexthop_group *nh_grp)
5335 {
5336 if (!nh_grp->can_destroy)
5337 return;
5338 mlxsw_sp_nexthop_obj_group_info_fini(mlxsw_sp, nh_grp);
5339 WARN_ON_ONCE(!list_empty(&nh_grp->fib_list));
5340 WARN_ON_ONCE(!list_empty(&nh_grp->vr_list));
5341 rhashtable_destroy(&nh_grp->vr_ht);
5342 kfree(nh_grp);
5343 }
5344
5345 static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop_obj_group_lookup(struct mlxsw_sp * mlxsw_sp,u32 id)5346 mlxsw_sp_nexthop_obj_group_lookup(struct mlxsw_sp *mlxsw_sp, u32 id)
5347 {
5348 struct mlxsw_sp_nexthop_group_cmp_arg cmp_arg;
5349
5350 cmp_arg.type = MLXSW_SP_NEXTHOP_GROUP_TYPE_OBJ;
5351 cmp_arg.id = id;
5352 return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht,
5353 &cmp_arg,
5354 mlxsw_sp_nexthop_group_ht_params);
5355 }
5356
mlxsw_sp_nexthop_obj_group_add(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)5357 static int mlxsw_sp_nexthop_obj_group_add(struct mlxsw_sp *mlxsw_sp,
5358 struct mlxsw_sp_nexthop_group *nh_grp)
5359 {
5360 return mlxsw_sp_nexthop_group_insert(mlxsw_sp, nh_grp);
5361 }
5362
5363 static int
mlxsw_sp_nexthop_obj_group_replace(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,struct mlxsw_sp_nexthop_group * old_nh_grp,struct netlink_ext_ack * extack)5364 mlxsw_sp_nexthop_obj_group_replace(struct mlxsw_sp *mlxsw_sp,
5365 struct mlxsw_sp_nexthop_group *nh_grp,
5366 struct mlxsw_sp_nexthop_group *old_nh_grp,
5367 struct netlink_ext_ack *extack)
5368 {
5369 struct mlxsw_sp_nexthop_group_info *old_nhgi = old_nh_grp->nhgi;
5370 struct mlxsw_sp_nexthop_group_info *new_nhgi = nh_grp->nhgi;
5371 int err;
5372
5373 old_nh_grp->nhgi = new_nhgi;
5374 new_nhgi->nh_grp = old_nh_grp;
5375 nh_grp->nhgi = old_nhgi;
5376 old_nhgi->nh_grp = nh_grp;
5377
5378 if (old_nhgi->adj_index_valid && new_nhgi->adj_index_valid) {
5379 /* Both the old adjacency index and the new one are valid.
5380 * Routes are currently using the old one. Tell the device to
5381 * replace the old adjacency index with the new one.
5382 */
5383 err = mlxsw_sp_adj_index_mass_update(mlxsw_sp, old_nh_grp,
5384 old_nhgi->adj_index,
5385 old_nhgi->ecmp_size);
5386 if (err) {
5387 NL_SET_ERR_MSG_MOD(extack, "Failed to replace old adjacency index with new one");
5388 goto err_out;
5389 }
5390 } else if (old_nhgi->adj_index_valid && !new_nhgi->adj_index_valid) {
5391 /* The old adjacency index is valid, while the new one is not.
5392 * Iterate over all the routes using the group and change them
5393 * to trap packets to the CPU.
5394 */
5395 err = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, old_nh_grp);
5396 if (err) {
5397 NL_SET_ERR_MSG_MOD(extack, "Failed to update routes to trap packets");
5398 goto err_out;
5399 }
5400 } else if (!old_nhgi->adj_index_valid && new_nhgi->adj_index_valid) {
5401 /* The old adjacency index is invalid, while the new one is.
5402 * Iterate over all the routes using the group and change them
5403 * to forward packets using the new valid index.
5404 */
5405 err = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, old_nh_grp);
5406 if (err) {
5407 NL_SET_ERR_MSG_MOD(extack, "Failed to update routes to forward packets");
5408 goto err_out;
5409 }
5410 }
5411
5412 /* Make sure the flags are set / cleared based on the new nexthop group
5413 * information.
5414 */
5415 mlxsw_sp_nexthop_obj_group_offload_refresh(mlxsw_sp, old_nh_grp);
5416
5417 /* At this point 'nh_grp' is just a shell that is not used by anyone
5418 * and its nexthop group info is the old info that was just replaced
5419 * with the new one. Remove it.
5420 */
5421 nh_grp->can_destroy = true;
5422 mlxsw_sp_nexthop_obj_group_destroy(mlxsw_sp, nh_grp);
5423
5424 return 0;
5425
5426 err_out:
5427 old_nhgi->nh_grp = old_nh_grp;
5428 nh_grp->nhgi = new_nhgi;
5429 new_nhgi->nh_grp = nh_grp;
5430 old_nh_grp->nhgi = old_nhgi;
5431 return err;
5432 }
5433
mlxsw_sp_nexthop_obj_res_group_pre(struct mlxsw_sp * mlxsw_sp,struct nh_notifier_info * info)5434 static int mlxsw_sp_nexthop_obj_res_group_pre(struct mlxsw_sp *mlxsw_sp,
5435 struct nh_notifier_info *info)
5436 {
5437 struct nh_notifier_grp_info *grp_info = info->nh_grp;
5438 struct mlxsw_sp_nexthop_group_info *nhgi;
5439 struct mlxsw_sp_nexthop_group *nh_grp;
5440 int err;
5441 int i;
5442
5443 nh_grp = mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp, info->id);
5444 if (!nh_grp)
5445 return 0;
5446 nhgi = nh_grp->nhgi;
5447
5448 if (nhgi->hw_stats == grp_info->hw_stats)
5449 return 0;
5450
5451 nhgi->hw_stats = grp_info->hw_stats;
5452
5453 for (i = 0; i < nhgi->count; i++) {
5454 struct mlxsw_sp_nexthop *nh = &nhgi->nexthops[i];
5455
5456 if (nh->offloaded)
5457 nh->update = 1;
5458 }
5459
5460 err = mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
5461 if (err)
5462 goto err_group_refresh;
5463
5464 return 0;
5465
5466 err_group_refresh:
5467 nhgi->hw_stats = !grp_info->hw_stats;
5468 return err;
5469 }
5470
mlxsw_sp_nexthop_obj_new(struct mlxsw_sp * mlxsw_sp,struct nh_notifier_info * info)5471 static int mlxsw_sp_nexthop_obj_new(struct mlxsw_sp *mlxsw_sp,
5472 struct nh_notifier_info *info)
5473 {
5474 struct mlxsw_sp_nexthop_group *nh_grp, *old_nh_grp;
5475 struct netlink_ext_ack *extack = info->extack;
5476 int err;
5477
5478 nh_grp = mlxsw_sp_nexthop_obj_group_create(mlxsw_sp, info);
5479 if (IS_ERR(nh_grp))
5480 return PTR_ERR(nh_grp);
5481
5482 old_nh_grp = mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp, info->id);
5483 if (!old_nh_grp)
5484 err = mlxsw_sp_nexthop_obj_group_add(mlxsw_sp, nh_grp);
5485 else
5486 err = mlxsw_sp_nexthop_obj_group_replace(mlxsw_sp, nh_grp,
5487 old_nh_grp, extack);
5488
5489 if (err) {
5490 nh_grp->can_destroy = true;
5491 mlxsw_sp_nexthop_obj_group_destroy(mlxsw_sp, nh_grp);
5492 }
5493
5494 return err;
5495 }
5496
mlxsw_sp_nexthop_obj_del(struct mlxsw_sp * mlxsw_sp,struct nh_notifier_info * info)5497 static void mlxsw_sp_nexthop_obj_del(struct mlxsw_sp *mlxsw_sp,
5498 struct nh_notifier_info *info)
5499 {
5500 struct mlxsw_sp_nexthop_group *nh_grp;
5501
5502 nh_grp = mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp, info->id);
5503 if (!nh_grp)
5504 return;
5505
5506 nh_grp->can_destroy = true;
5507 mlxsw_sp_nexthop_group_remove(mlxsw_sp, nh_grp);
5508
5509 /* If the group still has routes using it, then defer the delete
5510 * operation until the last route using it is deleted.
5511 */
5512 if (!list_empty(&nh_grp->fib_list))
5513 return;
5514 mlxsw_sp_nexthop_obj_group_destroy(mlxsw_sp, nh_grp);
5515 }
5516
mlxsw_sp_nexthop_obj_bucket_query(struct mlxsw_sp * mlxsw_sp,u32 adj_index,char * ratr_pl)5517 static int mlxsw_sp_nexthop_obj_bucket_query(struct mlxsw_sp *mlxsw_sp,
5518 u32 adj_index, char *ratr_pl)
5519 {
5520 MLXSW_REG_ZERO(ratr, ratr_pl);
5521 mlxsw_reg_ratr_op_set(ratr_pl, MLXSW_REG_RATR_OP_QUERY_READ);
5522 mlxsw_reg_ratr_adjacency_index_low_set(ratr_pl, adj_index);
5523 mlxsw_reg_ratr_adjacency_index_high_set(ratr_pl, adj_index >> 16);
5524
5525 return mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
5526 }
5527
mlxsw_sp_nexthop_obj_bucket_compare(char * ratr_pl,char * ratr_pl_new)5528 static int mlxsw_sp_nexthop_obj_bucket_compare(char *ratr_pl, char *ratr_pl_new)
5529 {
5530 /* Clear the opcode and activity on both the old and new payload as
5531 * they are irrelevant for the comparison.
5532 */
5533 mlxsw_reg_ratr_op_set(ratr_pl, MLXSW_REG_RATR_OP_QUERY_READ);
5534 mlxsw_reg_ratr_a_set(ratr_pl, 0);
5535 mlxsw_reg_ratr_op_set(ratr_pl_new, MLXSW_REG_RATR_OP_QUERY_READ);
5536 mlxsw_reg_ratr_a_set(ratr_pl_new, 0);
5537
5538 /* If the contents of the adjacency entry are consistent with the
5539 * replacement request, then replacement was successful.
5540 */
5541 if (!memcmp(ratr_pl, ratr_pl_new, MLXSW_REG_RATR_LEN))
5542 return 0;
5543
5544 return -EINVAL;
5545 }
5546
5547 static int
mlxsw_sp_nexthop_obj_bucket_adj_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh,struct nh_notifier_info * info)5548 mlxsw_sp_nexthop_obj_bucket_adj_update(struct mlxsw_sp *mlxsw_sp,
5549 struct mlxsw_sp_nexthop *nh,
5550 struct nh_notifier_info *info)
5551 {
5552 u16 bucket_index = info->nh_res_bucket->bucket_index;
5553 struct netlink_ext_ack *extack = info->extack;
5554 bool force = info->nh_res_bucket->force;
5555 char ratr_pl_new[MLXSW_REG_RATR_LEN];
5556 char ratr_pl[MLXSW_REG_RATR_LEN];
5557 u32 adj_index;
5558 int err;
5559
5560 /* No point in trying an atomic replacement if the idle timer interval
5561 * is smaller than the interval in which we query and clear activity.
5562 */
5563 if (!force && info->nh_res_bucket->idle_timer_ms <
5564 MLXSW_SP_NH_GRP_ACTIVITY_UPDATE_INTERVAL)
5565 force = true;
5566
5567 adj_index = nh->nhgi->adj_index + bucket_index;
5568 err = mlxsw_sp_nexthop_update(mlxsw_sp, adj_index, nh, force, ratr_pl);
5569 if (err) {
5570 NL_SET_ERR_MSG_MOD(extack, "Failed to overwrite nexthop bucket");
5571 return err;
5572 }
5573
5574 if (!force) {
5575 err = mlxsw_sp_nexthop_obj_bucket_query(mlxsw_sp, adj_index,
5576 ratr_pl_new);
5577 if (err) {
5578 NL_SET_ERR_MSG_MOD(extack, "Failed to query nexthop bucket state after replacement. State might be inconsistent");
5579 return err;
5580 }
5581
5582 err = mlxsw_sp_nexthop_obj_bucket_compare(ratr_pl, ratr_pl_new);
5583 if (err) {
5584 NL_SET_ERR_MSG_MOD(extack, "Nexthop bucket was not replaced because it was active during replacement");
5585 return err;
5586 }
5587 }
5588
5589 nh->update = 0;
5590 nh->offloaded = 1;
5591 mlxsw_sp_nexthop_bucket_offload_refresh(mlxsw_sp, nh, bucket_index);
5592
5593 return 0;
5594 }
5595
mlxsw_sp_nexthop_obj_bucket_replace(struct mlxsw_sp * mlxsw_sp,struct nh_notifier_info * info)5596 static int mlxsw_sp_nexthop_obj_bucket_replace(struct mlxsw_sp *mlxsw_sp,
5597 struct nh_notifier_info *info)
5598 {
5599 u16 bucket_index = info->nh_res_bucket->bucket_index;
5600 struct netlink_ext_ack *extack = info->extack;
5601 struct mlxsw_sp_nexthop_group_info *nhgi;
5602 struct nh_notifier_single_info *nh_obj;
5603 struct mlxsw_sp_nexthop_group *nh_grp;
5604 struct mlxsw_sp_nexthop *nh;
5605 int err;
5606
5607 nh_grp = mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp, info->id);
5608 if (!nh_grp) {
5609 NL_SET_ERR_MSG_MOD(extack, "Nexthop group was not found");
5610 return -EINVAL;
5611 }
5612
5613 nhgi = nh_grp->nhgi;
5614
5615 if (bucket_index >= nhgi->count) {
5616 NL_SET_ERR_MSG_MOD(extack, "Nexthop bucket index out of range");
5617 return -EINVAL;
5618 }
5619
5620 nh = &nhgi->nexthops[bucket_index];
5621 mlxsw_sp_nexthop_obj_fini(mlxsw_sp, nh);
5622
5623 nh_obj = &info->nh_res_bucket->new_nh;
5624 err = mlxsw_sp_nexthop_obj_init(mlxsw_sp, nh_grp, nh, nh_obj, 1);
5625 if (err) {
5626 NL_SET_ERR_MSG_MOD(extack, "Failed to initialize nexthop object for nexthop bucket replacement");
5627 goto err_nexthop_obj_init;
5628 }
5629
5630 err = mlxsw_sp_nexthop_obj_bucket_adj_update(mlxsw_sp, nh, info);
5631 if (err)
5632 goto err_nexthop_obj_bucket_adj_update;
5633
5634 return 0;
5635
5636 err_nexthop_obj_bucket_adj_update:
5637 mlxsw_sp_nexthop_obj_fini(mlxsw_sp, nh);
5638 err_nexthop_obj_init:
5639 nh_obj = &info->nh_res_bucket->old_nh;
5640 mlxsw_sp_nexthop_obj_init(mlxsw_sp, nh_grp, nh, nh_obj, 1);
5641 /* The old adjacency entry was not overwritten */
5642 nh->update = 0;
5643 nh->offloaded = 1;
5644 return err;
5645 }
5646
5647 static void
mlxsw_sp_nexthop_obj_mp_hw_stats_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group_info * nhgi,struct nh_notifier_grp_hw_stats_info * info)5648 mlxsw_sp_nexthop_obj_mp_hw_stats_get(struct mlxsw_sp *mlxsw_sp,
5649 struct mlxsw_sp_nexthop_group_info *nhgi,
5650 struct nh_notifier_grp_hw_stats_info *info)
5651 {
5652 int nhi;
5653
5654 for (nhi = 0; nhi < info->num_nh; nhi++) {
5655 struct mlxsw_sp_nexthop *nh = &nhgi->nexthops[nhi];
5656 u64 packets;
5657 int err;
5658
5659 err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &packets);
5660 if (err)
5661 continue;
5662
5663 nh_grp_hw_stats_report_delta(info, nhi, packets);
5664 }
5665 }
5666
5667 static void
mlxsw_sp_nexthop_obj_res_hw_stats_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group_info * nhgi,struct nh_notifier_grp_hw_stats_info * info)5668 mlxsw_sp_nexthop_obj_res_hw_stats_get(struct mlxsw_sp *mlxsw_sp,
5669 struct mlxsw_sp_nexthop_group_info *nhgi,
5670 struct nh_notifier_grp_hw_stats_info *info)
5671 {
5672 int nhi = -1;
5673 int bucket;
5674
5675 for (bucket = 0; bucket < nhgi->count; bucket++) {
5676 struct mlxsw_sp_nexthop *nh = &nhgi->nexthops[bucket];
5677 u64 packets;
5678 int err;
5679
5680 if (nhi == -1 || info->stats[nhi].id != nh->id) {
5681 for (nhi = 0; nhi < info->num_nh; nhi++)
5682 if (info->stats[nhi].id == nh->id)
5683 break;
5684 if (WARN_ON_ONCE(nhi == info->num_nh)) {
5685 nhi = -1;
5686 continue;
5687 }
5688 }
5689
5690 err = mlxsw_sp_nexthop_counter_get(mlxsw_sp, nh, &packets);
5691 if (err)
5692 continue;
5693
5694 nh_grp_hw_stats_report_delta(info, nhi, packets);
5695 }
5696 }
5697
mlxsw_sp_nexthop_obj_hw_stats_get(struct mlxsw_sp * mlxsw_sp,struct nh_notifier_info * info)5698 static void mlxsw_sp_nexthop_obj_hw_stats_get(struct mlxsw_sp *mlxsw_sp,
5699 struct nh_notifier_info *info)
5700 {
5701 struct mlxsw_sp_nexthop_group_info *nhgi;
5702 struct mlxsw_sp_nexthop_group *nh_grp;
5703
5704 if (info->type != NH_NOTIFIER_INFO_TYPE_GRP_HW_STATS)
5705 return;
5706
5707 nh_grp = mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp, info->id);
5708 if (!nh_grp)
5709 return;
5710 nhgi = nh_grp->nhgi;
5711
5712 if (nhgi->is_resilient)
5713 mlxsw_sp_nexthop_obj_res_hw_stats_get(mlxsw_sp, nhgi,
5714 info->nh_grp_hw_stats);
5715 else
5716 mlxsw_sp_nexthop_obj_mp_hw_stats_get(mlxsw_sp, nhgi,
5717 info->nh_grp_hw_stats);
5718 }
5719
mlxsw_sp_nexthop_obj_event(struct notifier_block * nb,unsigned long event,void * ptr)5720 static int mlxsw_sp_nexthop_obj_event(struct notifier_block *nb,
5721 unsigned long event, void *ptr)
5722 {
5723 struct nh_notifier_info *info = ptr;
5724 struct mlxsw_sp_router *router;
5725 int err = 0;
5726
5727 router = container_of(nb, struct mlxsw_sp_router, nexthop_nb);
5728 err = mlxsw_sp_nexthop_obj_validate(router->mlxsw_sp, event, info);
5729 if (err)
5730 goto out;
5731
5732 mutex_lock(&router->lock);
5733
5734 switch (event) {
5735 case NEXTHOP_EVENT_RES_TABLE_PRE_REPLACE:
5736 err = mlxsw_sp_nexthop_obj_res_group_pre(router->mlxsw_sp,
5737 info);
5738 break;
5739 case NEXTHOP_EVENT_REPLACE:
5740 err = mlxsw_sp_nexthop_obj_new(router->mlxsw_sp, info);
5741 break;
5742 case NEXTHOP_EVENT_DEL:
5743 mlxsw_sp_nexthop_obj_del(router->mlxsw_sp, info);
5744 break;
5745 case NEXTHOP_EVENT_BUCKET_REPLACE:
5746 err = mlxsw_sp_nexthop_obj_bucket_replace(router->mlxsw_sp,
5747 info);
5748 break;
5749 case NEXTHOP_EVENT_HW_STATS_REPORT_DELTA:
5750 mlxsw_sp_nexthop_obj_hw_stats_get(router->mlxsw_sp, info);
5751 break;
5752 default:
5753 break;
5754 }
5755
5756 mutex_unlock(&router->lock);
5757
5758 out:
5759 return notifier_from_errno(err);
5760 }
5761
mlxsw_sp_fi_is_gateway(const struct mlxsw_sp * mlxsw_sp,struct fib_info * fi)5762 static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp *mlxsw_sp,
5763 struct fib_info *fi)
5764 {
5765 const struct fib_nh *nh = fib_info_nh(fi, 0);
5766
5767 return nh->fib_nh_gw_family ||
5768 mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, nh, NULL);
5769 }
5770
5771 static int
mlxsw_sp_nexthop4_group_info_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)5772 mlxsw_sp_nexthop4_group_info_init(struct mlxsw_sp *mlxsw_sp,
5773 struct mlxsw_sp_nexthop_group *nh_grp)
5774 {
5775 unsigned int nhs = fib_info_num_path(nh_grp->ipv4.fi);
5776 struct mlxsw_sp_nexthop_group_info *nhgi;
5777 struct mlxsw_sp_nexthop *nh;
5778 int err, i;
5779
5780 nhgi = kzalloc_flex(*nhgi, nexthops, nhs);
5781 if (!nhgi)
5782 return -ENOMEM;
5783 nh_grp->nhgi = nhgi;
5784 nhgi->nh_grp = nh_grp;
5785 nhgi->gateway = mlxsw_sp_fi_is_gateway(mlxsw_sp, nh_grp->ipv4.fi);
5786 nhgi->count = nhs;
5787 for (i = 0; i < nhgi->count; i++) {
5788 struct fib_nh *fib_nh;
5789
5790 nh = &nhgi->nexthops[i];
5791 fib_nh = fib_info_nh(nh_grp->ipv4.fi, i);
5792 err = mlxsw_sp_nexthop4_init(mlxsw_sp, nh_grp, nh, fib_nh);
5793 if (err)
5794 goto err_nexthop4_init;
5795 }
5796 err = mlxsw_sp_nexthop_group_inc(mlxsw_sp);
5797 if (err)
5798 goto err_group_inc;
5799 err = mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
5800 if (err)
5801 goto err_group_refresh;
5802
5803 return 0;
5804
5805 err_group_refresh:
5806 mlxsw_sp_nexthop_group_dec(mlxsw_sp);
5807 err_group_inc:
5808 i = nhgi->count;
5809 err_nexthop4_init:
5810 for (i--; i >= 0; i--) {
5811 nh = &nhgi->nexthops[i];
5812 mlxsw_sp_nexthop4_fini(mlxsw_sp, nh);
5813 }
5814 kfree(nhgi);
5815 return err;
5816 }
5817
5818 static void
mlxsw_sp_nexthop4_group_info_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)5819 mlxsw_sp_nexthop4_group_info_fini(struct mlxsw_sp *mlxsw_sp,
5820 struct mlxsw_sp_nexthop_group *nh_grp)
5821 {
5822 struct mlxsw_sp_nexthop_group_info *nhgi = nh_grp->nhgi;
5823 int i;
5824
5825 mlxsw_sp_nexthop_group_dec(mlxsw_sp);
5826 for (i = nhgi->count - 1; i >= 0; i--) {
5827 struct mlxsw_sp_nexthop *nh = &nhgi->nexthops[i];
5828
5829 mlxsw_sp_nexthop4_fini(mlxsw_sp, nh);
5830 }
5831 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
5832 WARN_ON_ONCE(nhgi->adj_index_valid);
5833 kfree(nhgi);
5834 }
5835
5836 static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop4_group_create(struct mlxsw_sp * mlxsw_sp,struct fib_info * fi)5837 mlxsw_sp_nexthop4_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi)
5838 {
5839 struct mlxsw_sp_nexthop_group *nh_grp;
5840 int err;
5841
5842 nh_grp = kzalloc_obj(*nh_grp);
5843 if (!nh_grp)
5844 return ERR_PTR(-ENOMEM);
5845 INIT_LIST_HEAD(&nh_grp->vr_list);
5846 err = rhashtable_init(&nh_grp->vr_ht,
5847 &mlxsw_sp_nexthop_group_vr_ht_params);
5848 if (err)
5849 goto err_nexthop_group_vr_ht_init;
5850 INIT_LIST_HEAD(&nh_grp->fib_list);
5851 nh_grp->type = MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV4;
5852 nh_grp->ipv4.fi = fi;
5853 fib_info_hold(fi);
5854
5855 err = mlxsw_sp_nexthop4_group_info_init(mlxsw_sp, nh_grp);
5856 if (err)
5857 goto err_nexthop_group_info_init;
5858
5859 err = mlxsw_sp_nexthop_group_insert(mlxsw_sp, nh_grp);
5860 if (err)
5861 goto err_nexthop_group_insert;
5862
5863 nh_grp->can_destroy = true;
5864
5865 return nh_grp;
5866
5867 err_nexthop_group_insert:
5868 mlxsw_sp_nexthop4_group_info_fini(mlxsw_sp, nh_grp);
5869 err_nexthop_group_info_init:
5870 fib_info_put(fi);
5871 rhashtable_destroy(&nh_grp->vr_ht);
5872 err_nexthop_group_vr_ht_init:
5873 kfree(nh_grp);
5874 return ERR_PTR(err);
5875 }
5876
5877 static void
mlxsw_sp_nexthop4_group_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)5878 mlxsw_sp_nexthop4_group_destroy(struct mlxsw_sp *mlxsw_sp,
5879 struct mlxsw_sp_nexthop_group *nh_grp)
5880 {
5881 if (!nh_grp->can_destroy)
5882 return;
5883 mlxsw_sp_nexthop_group_remove(mlxsw_sp, nh_grp);
5884 mlxsw_sp_nexthop4_group_info_fini(mlxsw_sp, nh_grp);
5885 fib_info_put(nh_grp->ipv4.fi);
5886 WARN_ON_ONCE(!list_empty(&nh_grp->vr_list));
5887 rhashtable_destroy(&nh_grp->vr_ht);
5888 kfree(nh_grp);
5889 }
5890
mlxsw_sp_nexthop4_group_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,struct fib_info * fi)5891 static int mlxsw_sp_nexthop4_group_get(struct mlxsw_sp *mlxsw_sp,
5892 struct mlxsw_sp_fib_entry *fib_entry,
5893 struct fib_info *fi)
5894 {
5895 struct mlxsw_sp_nexthop_group *nh_grp;
5896
5897 if (fi->nh) {
5898 nh_grp = mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp,
5899 fi->nh->id);
5900 if (WARN_ON_ONCE(!nh_grp))
5901 return -EINVAL;
5902 goto out;
5903 }
5904
5905 nh_grp = mlxsw_sp_nexthop4_group_lookup(mlxsw_sp, fi);
5906 if (!nh_grp) {
5907 nh_grp = mlxsw_sp_nexthop4_group_create(mlxsw_sp, fi);
5908 if (IS_ERR(nh_grp))
5909 return PTR_ERR(nh_grp);
5910 }
5911 out:
5912 list_add_tail(&fib_entry->nexthop_group_node, &nh_grp->fib_list);
5913 fib_entry->nh_group = nh_grp;
5914 return 0;
5915 }
5916
mlxsw_sp_nexthop4_group_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)5917 static void mlxsw_sp_nexthop4_group_put(struct mlxsw_sp *mlxsw_sp,
5918 struct mlxsw_sp_fib_entry *fib_entry)
5919 {
5920 struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
5921
5922 list_del(&fib_entry->nexthop_group_node);
5923 if (!list_empty(&nh_grp->fib_list))
5924 return;
5925
5926 if (nh_grp->type == MLXSW_SP_NEXTHOP_GROUP_TYPE_OBJ) {
5927 mlxsw_sp_nexthop_obj_group_destroy(mlxsw_sp, nh_grp);
5928 return;
5929 }
5930
5931 mlxsw_sp_nexthop4_group_destroy(mlxsw_sp, nh_grp);
5932 }
5933
5934 static bool
mlxsw_sp_fib4_entry_should_offload(const struct mlxsw_sp_fib_entry * fib_entry)5935 mlxsw_sp_fib4_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry)
5936 {
5937 struct mlxsw_sp_fib4_entry *fib4_entry;
5938
5939 fib4_entry = container_of(fib_entry, struct mlxsw_sp_fib4_entry,
5940 common);
5941 return !fib4_entry->dscp;
5942 }
5943
5944 static bool
mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry * fib_entry)5945 mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry)
5946 {
5947 struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group;
5948
5949 switch (fib_entry->fib_node->fib->proto) {
5950 case MLXSW_SP_L3_PROTO_IPV4:
5951 if (!mlxsw_sp_fib4_entry_should_offload(fib_entry))
5952 return false;
5953 break;
5954 case MLXSW_SP_L3_PROTO_IPV6:
5955 break;
5956 }
5957
5958 switch (fib_entry->type) {
5959 case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE:
5960 return !!nh_group->nhgi->adj_index_valid;
5961 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
5962 return !!mlxsw_sp_nhgi_rif(nh_group->nhgi);
5963 case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE:
5964 case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
5965 case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP:
5966 return true;
5967 default:
5968 return false;
5969 }
5970 }
5971
5972 static struct mlxsw_sp_nexthop *
mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group * nh_grp,const struct mlxsw_sp_rt6 * mlxsw_sp_rt6)5973 mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp,
5974 const struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
5975 {
5976 int i;
5977
5978 for (i = 0; i < nh_grp->nhgi->count; i++) {
5979 struct mlxsw_sp_nexthop *nh = &nh_grp->nhgi->nexthops[i];
5980 struct net_device *dev = mlxsw_sp_nexthop_dev(nh);
5981 struct fib6_info *rt = mlxsw_sp_rt6->rt;
5982
5983 if (dev && dev == rt->fib6_nh->fib_nh_dev &&
5984 ipv6_addr_equal((const struct in6_addr *) &nh->gw_addr,
5985 &rt->fib6_nh->fib_nh_gw6))
5986 return nh;
5987 }
5988
5989 return NULL;
5990 }
5991
5992 static void
mlxsw_sp_fib4_offload_failed_flag_set(struct mlxsw_sp * mlxsw_sp,struct fib_entry_notifier_info * fen_info)5993 mlxsw_sp_fib4_offload_failed_flag_set(struct mlxsw_sp *mlxsw_sp,
5994 struct fib_entry_notifier_info *fen_info)
5995 {
5996 u32 *p_dst = (u32 *) &fen_info->dst;
5997 struct fib_rt_info fri;
5998
5999 fri.fi = fen_info->fi;
6000 fri.tb_id = fen_info->tb_id;
6001 fri.dst = cpu_to_be32(*p_dst);
6002 fri.dst_len = fen_info->dst_len;
6003 fri.dscp = fen_info->dscp;
6004 fri.type = fen_info->type;
6005 fri.offload = false;
6006 fri.trap = false;
6007 fri.offload_failed = true;
6008 fib_alias_hw_flags_set(mlxsw_sp_net(mlxsw_sp), &fri);
6009 }
6010
6011 static void
mlxsw_sp_fib4_entry_hw_flags_set(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6012 mlxsw_sp_fib4_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
6013 struct mlxsw_sp_fib_entry *fib_entry)
6014 {
6015 u32 *p_dst = (u32 *) fib_entry->fib_node->key.addr;
6016 int dst_len = fib_entry->fib_node->key.prefix_len;
6017 struct mlxsw_sp_fib4_entry *fib4_entry;
6018 struct fib_rt_info fri;
6019 bool should_offload;
6020
6021 should_offload = mlxsw_sp_fib_entry_should_offload(fib_entry);
6022 fib4_entry = container_of(fib_entry, struct mlxsw_sp_fib4_entry,
6023 common);
6024 fri.fi = fib4_entry->fi;
6025 fri.tb_id = fib4_entry->tb_id;
6026 fri.dst = cpu_to_be32(*p_dst);
6027 fri.dst_len = dst_len;
6028 fri.dscp = fib4_entry->dscp;
6029 fri.type = fib4_entry->type;
6030 fri.offload = should_offload;
6031 fri.trap = !should_offload;
6032 fri.offload_failed = false;
6033 fib_alias_hw_flags_set(mlxsw_sp_net(mlxsw_sp), &fri);
6034 }
6035
6036 static void
mlxsw_sp_fib4_entry_hw_flags_clear(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6037 mlxsw_sp_fib4_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
6038 struct mlxsw_sp_fib_entry *fib_entry)
6039 {
6040 u32 *p_dst = (u32 *) fib_entry->fib_node->key.addr;
6041 int dst_len = fib_entry->fib_node->key.prefix_len;
6042 struct mlxsw_sp_fib4_entry *fib4_entry;
6043 struct fib_rt_info fri;
6044
6045 fib4_entry = container_of(fib_entry, struct mlxsw_sp_fib4_entry,
6046 common);
6047 fri.fi = fib4_entry->fi;
6048 fri.tb_id = fib4_entry->tb_id;
6049 fri.dst = cpu_to_be32(*p_dst);
6050 fri.dst_len = dst_len;
6051 fri.dscp = fib4_entry->dscp;
6052 fri.type = fib4_entry->type;
6053 fri.offload = false;
6054 fri.trap = false;
6055 fri.offload_failed = false;
6056 fib_alias_hw_flags_set(mlxsw_sp_net(mlxsw_sp), &fri);
6057 }
6058
6059 #if IS_ENABLED(CONFIG_IPV6)
6060 static void
mlxsw_sp_fib6_offload_failed_flag_set(struct mlxsw_sp * mlxsw_sp,struct fib6_info ** rt_arr,unsigned int nrt6)6061 mlxsw_sp_fib6_offload_failed_flag_set(struct mlxsw_sp *mlxsw_sp,
6062 struct fib6_info **rt_arr,
6063 unsigned int nrt6)
6064 {
6065 int i;
6066
6067 /* In IPv6 a multipath route is represented using multiple routes, so
6068 * we need to set the flags on all of them.
6069 */
6070 for (i = 0; i < nrt6; i++)
6071 fib6_info_hw_flags_set(mlxsw_sp_net(mlxsw_sp), rt_arr[i],
6072 false, false, true);
6073 }
6074 #else
6075 static void
mlxsw_sp_fib6_offload_failed_flag_set(struct mlxsw_sp * mlxsw_sp,struct fib6_info ** rt_arr,unsigned int nrt6)6076 mlxsw_sp_fib6_offload_failed_flag_set(struct mlxsw_sp *mlxsw_sp,
6077 struct fib6_info **rt_arr,
6078 unsigned int nrt6)
6079 {
6080 }
6081 #endif
6082
6083 #if IS_ENABLED(CONFIG_IPV6)
6084 static void
mlxsw_sp_fib6_entry_hw_flags_set(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6085 mlxsw_sp_fib6_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
6086 struct mlxsw_sp_fib_entry *fib_entry)
6087 {
6088 struct mlxsw_sp_fib6_entry *fib6_entry;
6089 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
6090 bool should_offload;
6091
6092 should_offload = mlxsw_sp_fib_entry_should_offload(fib_entry);
6093
6094 /* In IPv6 a multipath route is represented using multiple routes, so
6095 * we need to set the flags on all of them.
6096 */
6097 fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry,
6098 common);
6099 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list)
6100 fib6_info_hw_flags_set(mlxsw_sp_net(mlxsw_sp), mlxsw_sp_rt6->rt,
6101 should_offload, !should_offload, false);
6102 }
6103 #else
6104 static void
mlxsw_sp_fib6_entry_hw_flags_set(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6105 mlxsw_sp_fib6_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
6106 struct mlxsw_sp_fib_entry *fib_entry)
6107 {
6108 }
6109 #endif
6110
6111 #if IS_ENABLED(CONFIG_IPV6)
6112 static void
mlxsw_sp_fib6_entry_hw_flags_clear(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6113 mlxsw_sp_fib6_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
6114 struct mlxsw_sp_fib_entry *fib_entry)
6115 {
6116 struct mlxsw_sp_fib6_entry *fib6_entry;
6117 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
6118
6119 fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry,
6120 common);
6121 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list)
6122 fib6_info_hw_flags_set(mlxsw_sp_net(mlxsw_sp), mlxsw_sp_rt6->rt,
6123 false, false, false);
6124 }
6125 #else
6126 static void
mlxsw_sp_fib6_entry_hw_flags_clear(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6127 mlxsw_sp_fib6_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
6128 struct mlxsw_sp_fib_entry *fib_entry)
6129 {
6130 }
6131 #endif
6132
6133 static void
mlxsw_sp_fib_entry_hw_flags_set(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6134 mlxsw_sp_fib_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
6135 struct mlxsw_sp_fib_entry *fib_entry)
6136 {
6137 switch (fib_entry->fib_node->fib->proto) {
6138 case MLXSW_SP_L3_PROTO_IPV4:
6139 mlxsw_sp_fib4_entry_hw_flags_set(mlxsw_sp, fib_entry);
6140 break;
6141 case MLXSW_SP_L3_PROTO_IPV6:
6142 mlxsw_sp_fib6_entry_hw_flags_set(mlxsw_sp, fib_entry);
6143 break;
6144 }
6145 }
6146
6147 static void
mlxsw_sp_fib_entry_hw_flags_clear(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6148 mlxsw_sp_fib_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
6149 struct mlxsw_sp_fib_entry *fib_entry)
6150 {
6151 switch (fib_entry->fib_node->fib->proto) {
6152 case MLXSW_SP_L3_PROTO_IPV4:
6153 mlxsw_sp_fib4_entry_hw_flags_clear(mlxsw_sp, fib_entry);
6154 break;
6155 case MLXSW_SP_L3_PROTO_IPV6:
6156 mlxsw_sp_fib6_entry_hw_flags_clear(mlxsw_sp, fib_entry);
6157 break;
6158 }
6159 }
6160
6161 static void
mlxsw_sp_fib_entry_hw_flags_refresh(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)6162 mlxsw_sp_fib_entry_hw_flags_refresh(struct mlxsw_sp *mlxsw_sp,
6163 struct mlxsw_sp_fib_entry *fib_entry,
6164 enum mlxsw_reg_ralue_op op)
6165 {
6166 switch (op) {
6167 case MLXSW_REG_RALUE_OP_WRITE_WRITE:
6168 mlxsw_sp_fib_entry_hw_flags_set(mlxsw_sp, fib_entry);
6169 break;
6170 case MLXSW_REG_RALUE_OP_WRITE_DELETE:
6171 mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, fib_entry);
6172 break;
6173 default:
6174 break;
6175 }
6176 }
6177
6178 static void
mlxsw_sp_fib_entry_ralue_pack(char * ralue_pl,const struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)6179 mlxsw_sp_fib_entry_ralue_pack(char *ralue_pl,
6180 const struct mlxsw_sp_fib_entry *fib_entry,
6181 enum mlxsw_reg_ralue_op op)
6182 {
6183 struct mlxsw_sp_fib *fib = fib_entry->fib_node->fib;
6184 enum mlxsw_reg_ralxx_protocol proto;
6185 u32 *p_dip;
6186
6187 proto = (enum mlxsw_reg_ralxx_protocol) fib->proto;
6188
6189 switch (fib->proto) {
6190 case MLXSW_SP_L3_PROTO_IPV4:
6191 p_dip = (u32 *) fib_entry->fib_node->key.addr;
6192 mlxsw_reg_ralue_pack4(ralue_pl, proto, op, fib->vr->id,
6193 fib_entry->fib_node->key.prefix_len,
6194 *p_dip);
6195 break;
6196 case MLXSW_SP_L3_PROTO_IPV6:
6197 mlxsw_reg_ralue_pack6(ralue_pl, proto, op, fib->vr->id,
6198 fib_entry->fib_node->key.prefix_len,
6199 fib_entry->fib_node->key.addr);
6200 break;
6201 }
6202 }
6203
mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)6204 static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp,
6205 struct mlxsw_sp_fib_entry *fib_entry,
6206 enum mlxsw_reg_ralue_op op)
6207 {
6208 struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group;
6209 struct mlxsw_sp_nexthop_group_info *nhgi = nh_group->nhgi;
6210 char ralue_pl[MLXSW_REG_RALUE_LEN];
6211 enum mlxsw_reg_ralue_trap_action trap_action;
6212 u16 trap_id = 0;
6213 u32 adjacency_index = 0;
6214 u16 ecmp_size = 0;
6215
6216 /* In case the nexthop group adjacency index is valid, use it
6217 * with provided ECMP size. Otherwise, setup trap and pass
6218 * traffic to kernel.
6219 */
6220 if (mlxsw_sp_fib_entry_should_offload(fib_entry)) {
6221 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
6222 adjacency_index = nhgi->adj_index;
6223 ecmp_size = nhgi->ecmp_size;
6224 } else if (!nhgi->adj_index_valid && nhgi->count &&
6225 mlxsw_sp_nhgi_rif(nhgi)) {
6226 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
6227 adjacency_index = mlxsw_sp->router->adj_trap_index;
6228 ecmp_size = 1;
6229 } else {
6230 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
6231 trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
6232 }
6233
6234 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
6235 mlxsw_reg_ralue_act_remote_pack(ralue_pl, trap_action, trap_id,
6236 adjacency_index, ecmp_size);
6237 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
6238 }
6239
mlxsw_sp_fib_entry_op_local(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)6240 static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp *mlxsw_sp,
6241 struct mlxsw_sp_fib_entry *fib_entry,
6242 enum mlxsw_reg_ralue_op op)
6243 {
6244 struct mlxsw_sp_rif *rif = mlxsw_sp_nhgi_rif(fib_entry->nh_group->nhgi);
6245 enum mlxsw_reg_ralue_trap_action trap_action;
6246 char ralue_pl[MLXSW_REG_RALUE_LEN];
6247 u16 trap_id = 0;
6248 u16 rif_index = 0;
6249
6250 if (mlxsw_sp_fib_entry_should_offload(fib_entry)) {
6251 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
6252 rif_index = rif->rif_index;
6253 } else {
6254 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
6255 trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
6256 }
6257
6258 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
6259 mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id,
6260 rif_index);
6261 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
6262 }
6263
mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)6264 static int mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp *mlxsw_sp,
6265 struct mlxsw_sp_fib_entry *fib_entry,
6266 enum mlxsw_reg_ralue_op op)
6267 {
6268 char ralue_pl[MLXSW_REG_RALUE_LEN];
6269
6270 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
6271 mlxsw_reg_ralue_act_ip2me_pack(ralue_pl);
6272 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
6273 }
6274
mlxsw_sp_fib_entry_op_blackhole(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)6275 static int mlxsw_sp_fib_entry_op_blackhole(struct mlxsw_sp *mlxsw_sp,
6276 struct mlxsw_sp_fib_entry *fib_entry,
6277 enum mlxsw_reg_ralue_op op)
6278 {
6279 enum mlxsw_reg_ralue_trap_action trap_action;
6280 char ralue_pl[MLXSW_REG_RALUE_LEN];
6281
6282 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_DISCARD_ERROR;
6283 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
6284 mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, 0, 0);
6285 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
6286 }
6287
6288 static int
mlxsw_sp_fib_entry_op_unreachable(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)6289 mlxsw_sp_fib_entry_op_unreachable(struct mlxsw_sp *mlxsw_sp,
6290 struct mlxsw_sp_fib_entry *fib_entry,
6291 enum mlxsw_reg_ralue_op op)
6292 {
6293 enum mlxsw_reg_ralue_trap_action trap_action;
6294 char ralue_pl[MLXSW_REG_RALUE_LEN];
6295 u16 trap_id;
6296
6297 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
6298 trap_id = MLXSW_TRAP_ID_RTR_INGRESS1;
6299
6300 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
6301 mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id, 0);
6302 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
6303 }
6304
6305 static int
mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)6306 mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp,
6307 struct mlxsw_sp_fib_entry *fib_entry,
6308 enum mlxsw_reg_ralue_op op)
6309 {
6310 struct mlxsw_sp_ipip_entry *ipip_entry = fib_entry->decap.ipip_entry;
6311 const struct mlxsw_sp_ipip_ops *ipip_ops;
6312 char ralue_pl[MLXSW_REG_RALUE_LEN];
6313 int err;
6314
6315 if (WARN_ON(!ipip_entry))
6316 return -EINVAL;
6317
6318 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
6319 err = ipip_ops->decap_config(mlxsw_sp, ipip_entry,
6320 fib_entry->decap.tunnel_index);
6321 if (err)
6322 return err;
6323
6324 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
6325 mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl,
6326 fib_entry->decap.tunnel_index);
6327 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
6328 }
6329
mlxsw_sp_fib_entry_op_nve_decap(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)6330 static int mlxsw_sp_fib_entry_op_nve_decap(struct mlxsw_sp *mlxsw_sp,
6331 struct mlxsw_sp_fib_entry *fib_entry,
6332 enum mlxsw_reg_ralue_op op)
6333 {
6334 char ralue_pl[MLXSW_REG_RALUE_LEN];
6335
6336 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
6337 mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl,
6338 fib_entry->decap.tunnel_index);
6339 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
6340 }
6341
__mlxsw_sp_fib_entry_op(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)6342 static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
6343 struct mlxsw_sp_fib_entry *fib_entry,
6344 enum mlxsw_reg_ralue_op op)
6345 {
6346 switch (fib_entry->type) {
6347 case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE:
6348 return mlxsw_sp_fib_entry_op_remote(mlxsw_sp, fib_entry, op);
6349 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
6350 return mlxsw_sp_fib_entry_op_local(mlxsw_sp, fib_entry, op);
6351 case MLXSW_SP_FIB_ENTRY_TYPE_TRAP:
6352 return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, fib_entry, op);
6353 case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE:
6354 return mlxsw_sp_fib_entry_op_blackhole(mlxsw_sp, fib_entry, op);
6355 case MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE:
6356 return mlxsw_sp_fib_entry_op_unreachable(mlxsw_sp, fib_entry,
6357 op);
6358 case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
6359 return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp,
6360 fib_entry, op);
6361 case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP:
6362 return mlxsw_sp_fib_entry_op_nve_decap(mlxsw_sp, fib_entry, op);
6363 }
6364 return -EINVAL;
6365 }
6366
mlxsw_sp_fib_entry_op(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,enum mlxsw_reg_ralue_op op)6367 static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
6368 struct mlxsw_sp_fib_entry *fib_entry,
6369 enum mlxsw_reg_ralue_op op)
6370 {
6371 int err = __mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, op);
6372
6373 if (err)
6374 return err;
6375
6376 mlxsw_sp_fib_entry_hw_flags_refresh(mlxsw_sp, fib_entry, op);
6377
6378 return err;
6379 }
6380
mlxsw_sp_fib_entry_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6381 static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
6382 struct mlxsw_sp_fib_entry *fib_entry)
6383 {
6384 return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
6385 MLXSW_REG_RALUE_OP_WRITE_WRITE);
6386 }
6387
mlxsw_sp_fib_entry_del(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6388 static int mlxsw_sp_fib_entry_del(struct mlxsw_sp *mlxsw_sp,
6389 struct mlxsw_sp_fib_entry *fib_entry)
6390 {
6391 return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
6392 MLXSW_REG_RALUE_OP_WRITE_DELETE);
6393 }
6394
6395 static int
mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp * mlxsw_sp,const struct fib_entry_notifier_info * fen_info,struct mlxsw_sp_fib_entry * fib_entry)6396 mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
6397 const struct fib_entry_notifier_info *fen_info,
6398 struct mlxsw_sp_fib_entry *fib_entry)
6399 {
6400 struct mlxsw_sp_nexthop_group_info *nhgi = fib_entry->nh_group->nhgi;
6401 union mlxsw_sp_l3addr dip = { .addr4 = htonl(fen_info->dst) };
6402 struct mlxsw_sp_router *router = mlxsw_sp->router;
6403 u32 tb_id = mlxsw_sp_fix_tb_id(fen_info->tb_id);
6404 int ifindex = nhgi->nexthops[0].ifindex;
6405 struct mlxsw_sp_ipip_entry *ipip_entry;
6406
6407 switch (fen_info->type) {
6408 case RTN_LOCAL:
6409 ipip_entry = mlxsw_sp_ipip_entry_find_by_decap(mlxsw_sp, ifindex,
6410 MLXSW_SP_L3_PROTO_IPV4, dip);
6411 if (ipip_entry && ipip_entry->ol_dev->flags & IFF_UP) {
6412 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
6413 return mlxsw_sp_fib_entry_decap_init(mlxsw_sp,
6414 fib_entry,
6415 ipip_entry);
6416 }
6417 if (mlxsw_sp_router_nve_is_decap(mlxsw_sp, tb_id,
6418 MLXSW_SP_L3_PROTO_IPV4,
6419 &dip)) {
6420 u32 tunnel_index;
6421
6422 tunnel_index = router->nve_decap_config.tunnel_index;
6423 fib_entry->decap.tunnel_index = tunnel_index;
6424 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP;
6425 return 0;
6426 }
6427 fallthrough;
6428 case RTN_BROADCAST:
6429 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
6430 return 0;
6431 case RTN_BLACKHOLE:
6432 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE;
6433 return 0;
6434 case RTN_UNREACHABLE:
6435 case RTN_PROHIBIT:
6436 /* Packets hitting these routes need to be trapped, but
6437 * can do so with a lower priority than packets directed
6438 * at the host, so use action type local instead of trap.
6439 */
6440 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE;
6441 return 0;
6442 case RTN_UNICAST:
6443 if (nhgi->gateway)
6444 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
6445 else
6446 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
6447 return 0;
6448 default:
6449 return -EINVAL;
6450 }
6451 }
6452
6453 static void
mlxsw_sp_fib_entry_type_unset(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6454 mlxsw_sp_fib_entry_type_unset(struct mlxsw_sp *mlxsw_sp,
6455 struct mlxsw_sp_fib_entry *fib_entry)
6456 {
6457 switch (fib_entry->type) {
6458 case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
6459 mlxsw_sp_fib_entry_decap_fini(mlxsw_sp, fib_entry);
6460 break;
6461 default:
6462 break;
6463 }
6464 }
6465
6466 static void
mlxsw_sp_fib4_entry_type_unset(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib4_entry * fib4_entry)6467 mlxsw_sp_fib4_entry_type_unset(struct mlxsw_sp *mlxsw_sp,
6468 struct mlxsw_sp_fib4_entry *fib4_entry)
6469 {
6470 mlxsw_sp_fib_entry_type_unset(mlxsw_sp, &fib4_entry->common);
6471 }
6472
6473 static struct mlxsw_sp_fib4_entry *
mlxsw_sp_fib4_entry_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node,const struct fib_entry_notifier_info * fen_info)6474 mlxsw_sp_fib4_entry_create(struct mlxsw_sp *mlxsw_sp,
6475 struct mlxsw_sp_fib_node *fib_node,
6476 const struct fib_entry_notifier_info *fen_info)
6477 {
6478 struct mlxsw_sp_fib4_entry *fib4_entry;
6479 struct mlxsw_sp_fib_entry *fib_entry;
6480 int err;
6481
6482 fib4_entry = kzalloc_obj(*fib4_entry);
6483 if (!fib4_entry)
6484 return ERR_PTR(-ENOMEM);
6485 fib_entry = &fib4_entry->common;
6486
6487 err = mlxsw_sp_nexthop4_group_get(mlxsw_sp, fib_entry, fen_info->fi);
6488 if (err)
6489 goto err_nexthop4_group_get;
6490
6491 err = mlxsw_sp_nexthop_group_vr_link(fib_entry->nh_group,
6492 fib_node->fib);
6493 if (err)
6494 goto err_nexthop_group_vr_link;
6495
6496 err = mlxsw_sp_fib4_entry_type_set(mlxsw_sp, fen_info, fib_entry);
6497 if (err)
6498 goto err_fib4_entry_type_set;
6499
6500 fib4_entry->fi = fen_info->fi;
6501 fib_info_hold(fib4_entry->fi);
6502 fib4_entry->tb_id = fen_info->tb_id;
6503 fib4_entry->type = fen_info->type;
6504 fib4_entry->dscp = fen_info->dscp;
6505
6506 fib_entry->fib_node = fib_node;
6507
6508 return fib4_entry;
6509
6510 err_fib4_entry_type_set:
6511 mlxsw_sp_nexthop_group_vr_unlink(fib_entry->nh_group, fib_node->fib);
6512 err_nexthop_group_vr_link:
6513 mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
6514 err_nexthop4_group_get:
6515 kfree(fib4_entry);
6516 return ERR_PTR(err);
6517 }
6518
mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib4_entry * fib4_entry)6519 static void mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp *mlxsw_sp,
6520 struct mlxsw_sp_fib4_entry *fib4_entry)
6521 {
6522 struct mlxsw_sp_fib_node *fib_node = fib4_entry->common.fib_node;
6523
6524 fib_info_put(fib4_entry->fi);
6525 mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, fib4_entry);
6526 mlxsw_sp_nexthop_group_vr_unlink(fib4_entry->common.nh_group,
6527 fib_node->fib);
6528 mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
6529 kfree(fib4_entry);
6530 }
6531
6532 static struct mlxsw_sp_fib4_entry *
mlxsw_sp_fib4_entry_lookup(struct mlxsw_sp * mlxsw_sp,const struct fib_entry_notifier_info * fen_info)6533 mlxsw_sp_fib4_entry_lookup(struct mlxsw_sp *mlxsw_sp,
6534 const struct fib_entry_notifier_info *fen_info)
6535 {
6536 struct mlxsw_sp_fib4_entry *fib4_entry;
6537 struct mlxsw_sp_fib_node *fib_node;
6538 struct mlxsw_sp_fib *fib;
6539 struct mlxsw_sp_vr *vr;
6540
6541 vr = mlxsw_sp_vr_find(mlxsw_sp, fen_info->tb_id);
6542 if (!vr)
6543 return NULL;
6544 fib = mlxsw_sp_vr_fib(vr, MLXSW_SP_L3_PROTO_IPV4);
6545
6546 fib_node = mlxsw_sp_fib_node_lookup(fib, &fen_info->dst,
6547 sizeof(fen_info->dst),
6548 fen_info->dst_len);
6549 if (!fib_node)
6550 return NULL;
6551
6552 fib4_entry = container_of(fib_node->fib_entry,
6553 struct mlxsw_sp_fib4_entry, common);
6554 if (fib4_entry->tb_id == fen_info->tb_id &&
6555 fib4_entry->dscp == fen_info->dscp &&
6556 fib4_entry->type == fen_info->type &&
6557 fib4_entry->fi == fen_info->fi)
6558 return fib4_entry;
6559
6560 return NULL;
6561 }
6562
6563 static const struct rhashtable_params mlxsw_sp_fib_ht_params = {
6564 .key_offset = offsetof(struct mlxsw_sp_fib_node, key),
6565 .head_offset = offsetof(struct mlxsw_sp_fib_node, ht_node),
6566 .key_len = sizeof(struct mlxsw_sp_fib_key),
6567 .automatic_shrinking = true,
6568 };
6569
mlxsw_sp_fib_node_insert(struct mlxsw_sp_fib * fib,struct mlxsw_sp_fib_node * fib_node)6570 static int mlxsw_sp_fib_node_insert(struct mlxsw_sp_fib *fib,
6571 struct mlxsw_sp_fib_node *fib_node)
6572 {
6573 return rhashtable_insert_fast(&fib->ht, &fib_node->ht_node,
6574 mlxsw_sp_fib_ht_params);
6575 }
6576
mlxsw_sp_fib_node_remove(struct mlxsw_sp_fib * fib,struct mlxsw_sp_fib_node * fib_node)6577 static void mlxsw_sp_fib_node_remove(struct mlxsw_sp_fib *fib,
6578 struct mlxsw_sp_fib_node *fib_node)
6579 {
6580 rhashtable_remove_fast(&fib->ht, &fib_node->ht_node,
6581 mlxsw_sp_fib_ht_params);
6582 }
6583
6584 static struct mlxsw_sp_fib_node *
mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib * fib,const void * addr,size_t addr_len,unsigned char prefix_len)6585 mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib *fib, const void *addr,
6586 size_t addr_len, unsigned char prefix_len)
6587 {
6588 struct mlxsw_sp_fib_key key;
6589
6590 memset(&key, 0, sizeof(key));
6591 memcpy(key.addr, addr, addr_len);
6592 key.prefix_len = prefix_len;
6593 return rhashtable_lookup_fast(&fib->ht, &key, mlxsw_sp_fib_ht_params);
6594 }
6595
6596 static struct mlxsw_sp_fib_node *
mlxsw_sp_fib_node_create(struct mlxsw_sp_fib * fib,const void * addr,size_t addr_len,unsigned char prefix_len)6597 mlxsw_sp_fib_node_create(struct mlxsw_sp_fib *fib, const void *addr,
6598 size_t addr_len, unsigned char prefix_len)
6599 {
6600 struct mlxsw_sp_fib_node *fib_node;
6601
6602 fib_node = kzalloc_obj(*fib_node);
6603 if (!fib_node)
6604 return NULL;
6605
6606 list_add(&fib_node->list, &fib->node_list);
6607 memcpy(fib_node->key.addr, addr, addr_len);
6608 fib_node->key.prefix_len = prefix_len;
6609
6610 return fib_node;
6611 }
6612
mlxsw_sp_fib_node_destroy(struct mlxsw_sp_fib_node * fib_node)6613 static void mlxsw_sp_fib_node_destroy(struct mlxsw_sp_fib_node *fib_node)
6614 {
6615 list_del(&fib_node->list);
6616 kfree(fib_node);
6617 }
6618
mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)6619 static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp *mlxsw_sp,
6620 struct mlxsw_sp_fib_node *fib_node)
6621 {
6622 struct mlxsw_sp_prefix_usage req_prefix_usage;
6623 struct mlxsw_sp_fib *fib = fib_node->fib;
6624 struct mlxsw_sp_lpm_tree *lpm_tree;
6625 int err;
6626
6627 lpm_tree = mlxsw_sp->router->lpm.proto_trees[fib->proto];
6628 if (lpm_tree->prefix_ref_count[fib_node->key.prefix_len] != 0)
6629 goto out;
6630
6631 mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &lpm_tree->prefix_usage);
6632 mlxsw_sp_prefix_usage_set(&req_prefix_usage, fib_node->key.prefix_len);
6633 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
6634 fib->proto);
6635 if (IS_ERR(lpm_tree))
6636 return PTR_ERR(lpm_tree);
6637
6638 err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
6639 if (err)
6640 goto err_lpm_tree_replace;
6641
6642 out:
6643 lpm_tree->prefix_ref_count[fib_node->key.prefix_len]++;
6644 return 0;
6645
6646 err_lpm_tree_replace:
6647 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
6648 return err;
6649 }
6650
mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)6651 static void mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp *mlxsw_sp,
6652 struct mlxsw_sp_fib_node *fib_node)
6653 {
6654 struct mlxsw_sp_lpm_tree *lpm_tree = fib_node->fib->lpm_tree;
6655 struct mlxsw_sp_prefix_usage req_prefix_usage;
6656 struct mlxsw_sp_fib *fib = fib_node->fib;
6657 int err;
6658
6659 if (--lpm_tree->prefix_ref_count[fib_node->key.prefix_len] != 0)
6660 return;
6661 /* Try to construct a new LPM tree from the current prefix usage
6662 * minus the unused one. If we fail, continue using the old one.
6663 */
6664 mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &lpm_tree->prefix_usage);
6665 mlxsw_sp_prefix_usage_clear(&req_prefix_usage,
6666 fib_node->key.prefix_len);
6667 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
6668 fib->proto);
6669 if (IS_ERR(lpm_tree))
6670 return;
6671
6672 err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
6673 if (err)
6674 goto err_lpm_tree_replace;
6675
6676 return;
6677
6678 err_lpm_tree_replace:
6679 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
6680 }
6681
mlxsw_sp_fib_node_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node,struct mlxsw_sp_fib * fib)6682 static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp,
6683 struct mlxsw_sp_fib_node *fib_node,
6684 struct mlxsw_sp_fib *fib)
6685 {
6686 int err;
6687
6688 err = mlxsw_sp_fib_node_insert(fib, fib_node);
6689 if (err)
6690 return err;
6691 fib_node->fib = fib;
6692
6693 err = mlxsw_sp_fib_lpm_tree_link(mlxsw_sp, fib_node);
6694 if (err)
6695 goto err_fib_lpm_tree_link;
6696
6697 return 0;
6698
6699 err_fib_lpm_tree_link:
6700 fib_node->fib = NULL;
6701 mlxsw_sp_fib_node_remove(fib, fib_node);
6702 return err;
6703 }
6704
mlxsw_sp_fib_node_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)6705 static void mlxsw_sp_fib_node_fini(struct mlxsw_sp *mlxsw_sp,
6706 struct mlxsw_sp_fib_node *fib_node)
6707 {
6708 struct mlxsw_sp_fib *fib = fib_node->fib;
6709
6710 mlxsw_sp_fib_lpm_tree_unlink(mlxsw_sp, fib_node);
6711 fib_node->fib = NULL;
6712 mlxsw_sp_fib_node_remove(fib, fib_node);
6713 }
6714
6715 static struct mlxsw_sp_fib_node *
mlxsw_sp_fib_node_get(struct mlxsw_sp * mlxsw_sp,u32 tb_id,const void * addr,size_t addr_len,unsigned char prefix_len,enum mlxsw_sp_l3proto proto)6716 mlxsw_sp_fib_node_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id, const void *addr,
6717 size_t addr_len, unsigned char prefix_len,
6718 enum mlxsw_sp_l3proto proto)
6719 {
6720 struct mlxsw_sp_fib_node *fib_node;
6721 struct mlxsw_sp_fib *fib;
6722 struct mlxsw_sp_vr *vr;
6723 int err;
6724
6725 vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id, NULL);
6726 if (IS_ERR(vr))
6727 return ERR_CAST(vr);
6728 fib = mlxsw_sp_vr_fib(vr, proto);
6729
6730 fib_node = mlxsw_sp_fib_node_lookup(fib, addr, addr_len, prefix_len);
6731 if (fib_node)
6732 return fib_node;
6733
6734 fib_node = mlxsw_sp_fib_node_create(fib, addr, addr_len, prefix_len);
6735 if (!fib_node) {
6736 err = -ENOMEM;
6737 goto err_fib_node_create;
6738 }
6739
6740 err = mlxsw_sp_fib_node_init(mlxsw_sp, fib_node, fib);
6741 if (err)
6742 goto err_fib_node_init;
6743
6744 return fib_node;
6745
6746 err_fib_node_init:
6747 mlxsw_sp_fib_node_destroy(fib_node);
6748 err_fib_node_create:
6749 mlxsw_sp_vr_put(mlxsw_sp, vr);
6750 return ERR_PTR(err);
6751 }
6752
mlxsw_sp_fib_node_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)6753 static void mlxsw_sp_fib_node_put(struct mlxsw_sp *mlxsw_sp,
6754 struct mlxsw_sp_fib_node *fib_node)
6755 {
6756 struct mlxsw_sp_vr *vr = fib_node->fib->vr;
6757
6758 if (fib_node->fib_entry)
6759 return;
6760 mlxsw_sp_fib_node_fini(mlxsw_sp, fib_node);
6761 mlxsw_sp_fib_node_destroy(fib_node);
6762 mlxsw_sp_vr_put(mlxsw_sp, vr);
6763 }
6764
mlxsw_sp_fib_node_entry_link(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6765 static int mlxsw_sp_fib_node_entry_link(struct mlxsw_sp *mlxsw_sp,
6766 struct mlxsw_sp_fib_entry *fib_entry)
6767 {
6768 struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
6769 int err;
6770
6771 fib_node->fib_entry = fib_entry;
6772
6773 err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
6774 if (err)
6775 goto err_fib_entry_update;
6776
6777 return 0;
6778
6779 err_fib_entry_update:
6780 fib_node->fib_entry = NULL;
6781 return err;
6782 }
6783
6784 static void
mlxsw_sp_fib_node_entry_unlink(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)6785 mlxsw_sp_fib_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
6786 struct mlxsw_sp_fib_entry *fib_entry)
6787 {
6788 struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
6789
6790 mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry);
6791 fib_node->fib_entry = NULL;
6792 }
6793
mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry * fib4_entry)6794 static bool mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry *fib4_entry)
6795 {
6796 struct mlxsw_sp_fib_node *fib_node = fib4_entry->common.fib_node;
6797 struct mlxsw_sp_fib4_entry *fib4_replaced;
6798
6799 if (!fib_node->fib_entry)
6800 return true;
6801
6802 fib4_replaced = container_of(fib_node->fib_entry,
6803 struct mlxsw_sp_fib4_entry, common);
6804 if (fib4_entry->tb_id == RT_TABLE_MAIN &&
6805 fib4_replaced->tb_id == RT_TABLE_LOCAL)
6806 return false;
6807
6808 return true;
6809 }
6810
6811 static int
mlxsw_sp_router_fib4_replace(struct mlxsw_sp * mlxsw_sp,const struct fib_entry_notifier_info * fen_info)6812 mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
6813 const struct fib_entry_notifier_info *fen_info)
6814 {
6815 struct mlxsw_sp_fib4_entry *fib4_entry, *fib4_replaced;
6816 struct mlxsw_sp_fib_entry *replaced;
6817 struct mlxsw_sp_fib_node *fib_node;
6818 int err;
6819
6820 if (fen_info->fi->nh &&
6821 !mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp, fen_info->fi->nh->id))
6822 return 0;
6823
6824 fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, fen_info->tb_id,
6825 &fen_info->dst, sizeof(fen_info->dst),
6826 fen_info->dst_len,
6827 MLXSW_SP_L3_PROTO_IPV4);
6828 if (IS_ERR(fib_node)) {
6829 dev_warn(mlxsw_sp->bus_info->dev, "Failed to get FIB node\n");
6830 return PTR_ERR(fib_node);
6831 }
6832
6833 fib4_entry = mlxsw_sp_fib4_entry_create(mlxsw_sp, fib_node, fen_info);
6834 if (IS_ERR(fib4_entry)) {
6835 dev_warn(mlxsw_sp->bus_info->dev, "Failed to create FIB entry\n");
6836 err = PTR_ERR(fib4_entry);
6837 goto err_fib4_entry_create;
6838 }
6839
6840 if (!mlxsw_sp_fib4_allow_replace(fib4_entry)) {
6841 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
6842 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
6843 return 0;
6844 }
6845
6846 replaced = fib_node->fib_entry;
6847 err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib4_entry->common);
6848 if (err) {
6849 dev_warn(mlxsw_sp->bus_info->dev, "Failed to link FIB entry to node\n");
6850 goto err_fib_node_entry_link;
6851 }
6852
6853 /* Nothing to replace */
6854 if (!replaced)
6855 return 0;
6856
6857 mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, replaced);
6858 fib4_replaced = container_of(replaced, struct mlxsw_sp_fib4_entry,
6859 common);
6860 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_replaced);
6861
6862 return 0;
6863
6864 err_fib_node_entry_link:
6865 fib_node->fib_entry = replaced;
6866 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
6867 err_fib4_entry_create:
6868 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
6869 return err;
6870 }
6871
mlxsw_sp_router_fib4_del(struct mlxsw_sp * mlxsw_sp,struct fib_entry_notifier_info * fen_info)6872 static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
6873 struct fib_entry_notifier_info *fen_info)
6874 {
6875 struct mlxsw_sp_fib4_entry *fib4_entry;
6876 struct mlxsw_sp_fib_node *fib_node;
6877
6878 fib4_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info);
6879 if (!fib4_entry)
6880 return;
6881 fib_node = fib4_entry->common.fib_node;
6882
6883 mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib4_entry->common);
6884 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
6885 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
6886 }
6887
mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info * rt)6888 static bool mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info *rt)
6889 {
6890 /* Multicast routes aren't supported, so ignore them. Neighbour
6891 * Discovery packets are specifically trapped.
6892 */
6893 if (ipv6_addr_type(&rt->fib6_dst.addr) & IPV6_ADDR_MULTICAST)
6894 return true;
6895
6896 /* Cloned routes are irrelevant in the forwarding path. */
6897 if (rt->fib6_flags & RTF_CACHE)
6898 return true;
6899
6900 return false;
6901 }
6902
mlxsw_sp_rt6_create(struct fib6_info * rt)6903 static struct mlxsw_sp_rt6 *mlxsw_sp_rt6_create(struct fib6_info *rt)
6904 {
6905 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
6906
6907 mlxsw_sp_rt6 = kzalloc_obj(*mlxsw_sp_rt6);
6908 if (!mlxsw_sp_rt6)
6909 return ERR_PTR(-ENOMEM);
6910
6911 /* In case of route replace, replaced route is deleted with
6912 * no notification. Take reference to prevent accessing freed
6913 * memory.
6914 */
6915 mlxsw_sp_rt6->rt = rt;
6916 fib6_info_hold(rt);
6917
6918 return mlxsw_sp_rt6;
6919 }
6920
6921 #if IS_ENABLED(CONFIG_IPV6)
mlxsw_sp_rt6_release(struct fib6_info * rt)6922 static void mlxsw_sp_rt6_release(struct fib6_info *rt)
6923 {
6924 fib6_info_release(rt);
6925 }
6926 #else
mlxsw_sp_rt6_release(struct fib6_info * rt)6927 static void mlxsw_sp_rt6_release(struct fib6_info *rt)
6928 {
6929 }
6930 #endif
6931
mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 * mlxsw_sp_rt6)6932 static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
6933 {
6934 struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
6935
6936 if (!mlxsw_sp_rt6->rt->nh)
6937 fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
6938 mlxsw_sp_rt6_release(mlxsw_sp_rt6->rt);
6939 kfree(mlxsw_sp_rt6);
6940 }
6941
6942 static struct fib6_info *
mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry * fib6_entry)6943 mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry)
6944 {
6945 return list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6,
6946 list)->rt;
6947 }
6948
6949 static struct mlxsw_sp_rt6 *
mlxsw_sp_fib6_entry_rt_find(const struct mlxsw_sp_fib6_entry * fib6_entry,const struct fib6_info * rt)6950 mlxsw_sp_fib6_entry_rt_find(const struct mlxsw_sp_fib6_entry *fib6_entry,
6951 const struct fib6_info *rt)
6952 {
6953 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
6954
6955 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
6956 if (mlxsw_sp_rt6->rt == rt)
6957 return mlxsw_sp_rt6;
6958 }
6959
6960 return NULL;
6961 }
6962
mlxsw_sp_nexthop6_ipip_type(const struct mlxsw_sp * mlxsw_sp,const struct fib6_info * rt,enum mlxsw_sp_ipip_type * ret)6963 static bool mlxsw_sp_nexthop6_ipip_type(const struct mlxsw_sp *mlxsw_sp,
6964 const struct fib6_info *rt,
6965 enum mlxsw_sp_ipip_type *ret)
6966 {
6967 return rt->fib6_nh->fib_nh_dev &&
6968 mlxsw_sp_netdev_ipip_type(mlxsw_sp, rt->fib6_nh->fib_nh_dev, ret);
6969 }
6970
mlxsw_sp_nexthop6_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,struct mlxsw_sp_nexthop * nh,const struct fib6_info * rt)6971 static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,
6972 struct mlxsw_sp_nexthop_group *nh_grp,
6973 struct mlxsw_sp_nexthop *nh,
6974 const struct fib6_info *rt)
6975 {
6976 struct net_device *dev = rt->fib6_nh->fib_nh_dev;
6977 int err;
6978
6979 nh->nhgi = nh_grp->nhgi;
6980 nh->nh_weight = rt->fib6_nh->fib_nh_weight;
6981 memcpy(&nh->gw_addr, &rt->fib6_nh->fib_nh_gw6, sizeof(nh->gw_addr));
6982 #if IS_ENABLED(CONFIG_IPV6)
6983 nh->neigh_tbl = &nd_tbl;
6984 #endif
6985
6986 err = mlxsw_sp_nexthop_counter_enable(mlxsw_sp, nh);
6987 if (err)
6988 return err;
6989
6990 list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
6991
6992 if (!dev)
6993 return 0;
6994 nh->ifindex = dev->ifindex;
6995
6996 err = mlxsw_sp_nexthop_type_init(mlxsw_sp, nh, dev);
6997 if (err)
6998 goto err_nexthop_type_init;
6999
7000 return 0;
7001
7002 err_nexthop_type_init:
7003 list_del(&nh->router_list_node);
7004 mlxsw_sp_nexthop_counter_disable(mlxsw_sp, nh);
7005 return err;
7006 }
7007
mlxsw_sp_nexthop6_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop * nh)7008 static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp,
7009 struct mlxsw_sp_nexthop *nh)
7010 {
7011 mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh);
7012 list_del(&nh->router_list_node);
7013 mlxsw_sp_nexthop_counter_disable(mlxsw_sp, nh);
7014 }
7015
mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp * mlxsw_sp,const struct fib6_info * rt)7016 static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp,
7017 const struct fib6_info *rt)
7018 {
7019 return rt->fib6_nh->fib_nh_gw_family ||
7020 mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL);
7021 }
7022
7023 static int
mlxsw_sp_nexthop6_group_info_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp,struct mlxsw_sp_fib6_entry * fib6_entry)7024 mlxsw_sp_nexthop6_group_info_init(struct mlxsw_sp *mlxsw_sp,
7025 struct mlxsw_sp_nexthop_group *nh_grp,
7026 struct mlxsw_sp_fib6_entry *fib6_entry)
7027 {
7028 struct mlxsw_sp_nexthop_group_info *nhgi;
7029 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
7030 struct mlxsw_sp_nexthop *nh;
7031 int err, i;
7032
7033 nhgi = kzalloc_flex(*nhgi, nexthops, fib6_entry->nrt6);
7034 if (!nhgi)
7035 return -ENOMEM;
7036 nh_grp->nhgi = nhgi;
7037 nhgi->nh_grp = nh_grp;
7038 mlxsw_sp_rt6 = list_first_entry(&fib6_entry->rt6_list,
7039 struct mlxsw_sp_rt6, list);
7040 nhgi->gateway = mlxsw_sp_rt6_is_gateway(mlxsw_sp, mlxsw_sp_rt6->rt);
7041 nhgi->count = fib6_entry->nrt6;
7042 for (i = 0; i < nhgi->count; i++) {
7043 struct fib6_info *rt = mlxsw_sp_rt6->rt;
7044
7045 nh = &nhgi->nexthops[i];
7046 err = mlxsw_sp_nexthop6_init(mlxsw_sp, nh_grp, nh, rt);
7047 if (err)
7048 goto err_nexthop6_init;
7049 mlxsw_sp_rt6 = list_next_entry(mlxsw_sp_rt6, list);
7050 }
7051 nh_grp->nhgi = nhgi;
7052 err = mlxsw_sp_nexthop_group_inc(mlxsw_sp);
7053 if (err)
7054 goto err_group_inc;
7055 err = mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
7056 if (err)
7057 goto err_group_refresh;
7058
7059 return 0;
7060
7061 err_group_refresh:
7062 mlxsw_sp_nexthop_group_dec(mlxsw_sp);
7063 err_group_inc:
7064 i = nhgi->count;
7065 err_nexthop6_init:
7066 for (i--; i >= 0; i--) {
7067 nh = &nhgi->nexthops[i];
7068 mlxsw_sp_nexthop6_fini(mlxsw_sp, nh);
7069 }
7070 kfree(nhgi);
7071 return err;
7072 }
7073
7074 static void
mlxsw_sp_nexthop6_group_info_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)7075 mlxsw_sp_nexthop6_group_info_fini(struct mlxsw_sp *mlxsw_sp,
7076 struct mlxsw_sp_nexthop_group *nh_grp)
7077 {
7078 struct mlxsw_sp_nexthop_group_info *nhgi = nh_grp->nhgi;
7079 int i;
7080
7081 mlxsw_sp_nexthop_group_dec(mlxsw_sp);
7082 for (i = nhgi->count - 1; i >= 0; i--) {
7083 struct mlxsw_sp_nexthop *nh = &nhgi->nexthops[i];
7084
7085 mlxsw_sp_nexthop6_fini(mlxsw_sp, nh);
7086 }
7087 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
7088 WARN_ON_ONCE(nhgi->adj_index_valid);
7089 kfree(nhgi);
7090 }
7091
7092 static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop6_group_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)7093 mlxsw_sp_nexthop6_group_create(struct mlxsw_sp *mlxsw_sp,
7094 struct mlxsw_sp_fib6_entry *fib6_entry)
7095 {
7096 struct mlxsw_sp_nexthop_group *nh_grp;
7097 int err;
7098
7099 nh_grp = kzalloc_obj(*nh_grp);
7100 if (!nh_grp)
7101 return ERR_PTR(-ENOMEM);
7102 INIT_LIST_HEAD(&nh_grp->vr_list);
7103 err = rhashtable_init(&nh_grp->vr_ht,
7104 &mlxsw_sp_nexthop_group_vr_ht_params);
7105 if (err)
7106 goto err_nexthop_group_vr_ht_init;
7107 INIT_LIST_HEAD(&nh_grp->fib_list);
7108 nh_grp->type = MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV6;
7109
7110 err = mlxsw_sp_nexthop6_group_info_init(mlxsw_sp, nh_grp, fib6_entry);
7111 if (err)
7112 goto err_nexthop_group_info_init;
7113
7114 err = mlxsw_sp_nexthop_group_insert(mlxsw_sp, nh_grp);
7115 if (err)
7116 goto err_nexthop_group_insert;
7117
7118 nh_grp->can_destroy = true;
7119
7120 return nh_grp;
7121
7122 err_nexthop_group_insert:
7123 mlxsw_sp_nexthop6_group_info_fini(mlxsw_sp, nh_grp);
7124 err_nexthop_group_info_init:
7125 rhashtable_destroy(&nh_grp->vr_ht);
7126 err_nexthop_group_vr_ht_init:
7127 kfree(nh_grp);
7128 return ERR_PTR(err);
7129 }
7130
7131 static void
mlxsw_sp_nexthop6_group_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_nexthop_group * nh_grp)7132 mlxsw_sp_nexthop6_group_destroy(struct mlxsw_sp *mlxsw_sp,
7133 struct mlxsw_sp_nexthop_group *nh_grp)
7134 {
7135 if (!nh_grp->can_destroy)
7136 return;
7137 mlxsw_sp_nexthop_group_remove(mlxsw_sp, nh_grp);
7138 mlxsw_sp_nexthop6_group_info_fini(mlxsw_sp, nh_grp);
7139 WARN_ON_ONCE(!list_empty(&nh_grp->vr_list));
7140 rhashtable_destroy(&nh_grp->vr_ht);
7141 kfree(nh_grp);
7142 }
7143
mlxsw_sp_nexthop6_group_get(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)7144 static int mlxsw_sp_nexthop6_group_get(struct mlxsw_sp *mlxsw_sp,
7145 struct mlxsw_sp_fib6_entry *fib6_entry)
7146 {
7147 struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
7148 struct mlxsw_sp_nexthop_group *nh_grp;
7149
7150 if (rt->nh) {
7151 nh_grp = mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp,
7152 rt->nh->id);
7153 if (WARN_ON_ONCE(!nh_grp))
7154 return -EINVAL;
7155 goto out;
7156 }
7157
7158 nh_grp = mlxsw_sp_nexthop6_group_lookup(mlxsw_sp, fib6_entry);
7159 if (!nh_grp) {
7160 nh_grp = mlxsw_sp_nexthop6_group_create(mlxsw_sp, fib6_entry);
7161 if (IS_ERR(nh_grp))
7162 return PTR_ERR(nh_grp);
7163 }
7164
7165 /* The route and the nexthop are described by the same struct, so we
7166 * need to the update the nexthop offload indication for the new route.
7167 */
7168 __mlxsw_sp_nexthop6_group_offload_refresh(nh_grp, fib6_entry);
7169
7170 out:
7171 list_add_tail(&fib6_entry->common.nexthop_group_node,
7172 &nh_grp->fib_list);
7173 fib6_entry->common.nh_group = nh_grp;
7174
7175 return 0;
7176 }
7177
mlxsw_sp_nexthop6_group_put(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry)7178 static void mlxsw_sp_nexthop6_group_put(struct mlxsw_sp *mlxsw_sp,
7179 struct mlxsw_sp_fib_entry *fib_entry)
7180 {
7181 struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
7182
7183 list_del(&fib_entry->nexthop_group_node);
7184 if (!list_empty(&nh_grp->fib_list))
7185 return;
7186
7187 if (nh_grp->type == MLXSW_SP_NEXTHOP_GROUP_TYPE_OBJ) {
7188 mlxsw_sp_nexthop_obj_group_destroy(mlxsw_sp, nh_grp);
7189 return;
7190 }
7191
7192 mlxsw_sp_nexthop6_group_destroy(mlxsw_sp, nh_grp);
7193 }
7194
7195 static int
mlxsw_sp_nexthop6_group_update(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)7196 mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp,
7197 struct mlxsw_sp_fib6_entry *fib6_entry)
7198 {
7199 struct mlxsw_sp_nexthop_group *old_nh_grp = fib6_entry->common.nh_group;
7200 struct mlxsw_sp_fib_node *fib_node = fib6_entry->common.fib_node;
7201 int err;
7202
7203 mlxsw_sp_nexthop_group_vr_unlink(old_nh_grp, fib_node->fib);
7204 fib6_entry->common.nh_group = NULL;
7205 list_del(&fib6_entry->common.nexthop_group_node);
7206
7207 err = mlxsw_sp_nexthop6_group_get(mlxsw_sp, fib6_entry);
7208 if (err)
7209 goto err_nexthop6_group_get;
7210
7211 err = mlxsw_sp_nexthop_group_vr_link(fib6_entry->common.nh_group,
7212 fib_node->fib);
7213 if (err)
7214 goto err_nexthop_group_vr_link;
7215
7216 /* In case this entry is offloaded, then the adjacency index
7217 * currently associated with it in the device's table is that
7218 * of the old group. Start using the new one instead.
7219 */
7220 err = mlxsw_sp_fib_entry_update(mlxsw_sp, &fib6_entry->common);
7221 if (err)
7222 goto err_fib_entry_update;
7223
7224 if (list_empty(&old_nh_grp->fib_list))
7225 mlxsw_sp_nexthop6_group_destroy(mlxsw_sp, old_nh_grp);
7226
7227 return 0;
7228
7229 err_fib_entry_update:
7230 mlxsw_sp_nexthop_group_vr_unlink(fib6_entry->common.nh_group,
7231 fib_node->fib);
7232 err_nexthop_group_vr_link:
7233 mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common);
7234 err_nexthop6_group_get:
7235 list_add_tail(&fib6_entry->common.nexthop_group_node,
7236 &old_nh_grp->fib_list);
7237 fib6_entry->common.nh_group = old_nh_grp;
7238 mlxsw_sp_nexthop_group_vr_link(old_nh_grp, fib_node->fib);
7239 return err;
7240 }
7241
7242 static int
mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry,struct fib6_info ** rt_arr,unsigned int nrt6)7243 mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,
7244 struct mlxsw_sp_fib6_entry *fib6_entry,
7245 struct fib6_info **rt_arr, unsigned int nrt6)
7246 {
7247 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
7248 int err, i;
7249
7250 for (i = 0; i < nrt6; i++) {
7251 mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt_arr[i]);
7252 if (IS_ERR(mlxsw_sp_rt6)) {
7253 err = PTR_ERR(mlxsw_sp_rt6);
7254 goto err_rt6_unwind;
7255 }
7256
7257 list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list);
7258 fib6_entry->nrt6++;
7259 }
7260
7261 err = mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
7262 if (err)
7263 goto err_rt6_unwind;
7264
7265 return 0;
7266
7267 err_rt6_unwind:
7268 for (; i > 0; i--) {
7269 fib6_entry->nrt6--;
7270 mlxsw_sp_rt6 = list_last_entry(&fib6_entry->rt6_list,
7271 struct mlxsw_sp_rt6, list);
7272 list_del(&mlxsw_sp_rt6->list);
7273 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
7274 }
7275 return err;
7276 }
7277
7278 static void
mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry,struct fib6_info ** rt_arr,unsigned int nrt6)7279 mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,
7280 struct mlxsw_sp_fib6_entry *fib6_entry,
7281 struct fib6_info **rt_arr, unsigned int nrt6)
7282 {
7283 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
7284 int i;
7285
7286 for (i = 0; i < nrt6; i++) {
7287 mlxsw_sp_rt6 = mlxsw_sp_fib6_entry_rt_find(fib6_entry,
7288 rt_arr[i]);
7289 if (WARN_ON_ONCE(!mlxsw_sp_rt6))
7290 continue;
7291
7292 fib6_entry->nrt6--;
7293 list_del(&mlxsw_sp_rt6->list);
7294 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
7295 }
7296
7297 mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
7298 }
7299
7300 static int
mlxsw_sp_fib6_entry_type_set_local(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,const struct fib6_info * rt)7301 mlxsw_sp_fib6_entry_type_set_local(struct mlxsw_sp *mlxsw_sp,
7302 struct mlxsw_sp_fib_entry *fib_entry,
7303 const struct fib6_info *rt)
7304 {
7305 struct mlxsw_sp_nexthop_group_info *nhgi = fib_entry->nh_group->nhgi;
7306 union mlxsw_sp_l3addr dip = { .addr6 = rt->fib6_dst.addr };
7307 u32 tb_id = mlxsw_sp_fix_tb_id(rt->fib6_table->tb6_id);
7308 struct mlxsw_sp_router *router = mlxsw_sp->router;
7309 int ifindex = nhgi->nexthops[0].ifindex;
7310 struct mlxsw_sp_ipip_entry *ipip_entry;
7311
7312 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
7313 ipip_entry = mlxsw_sp_ipip_entry_find_by_decap(mlxsw_sp, ifindex,
7314 MLXSW_SP_L3_PROTO_IPV6,
7315 dip);
7316
7317 if (ipip_entry && ipip_entry->ol_dev->flags & IFF_UP) {
7318 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
7319 return mlxsw_sp_fib_entry_decap_init(mlxsw_sp, fib_entry,
7320 ipip_entry);
7321 }
7322 if (mlxsw_sp_router_nve_is_decap(mlxsw_sp, tb_id,
7323 MLXSW_SP_L3_PROTO_IPV6, &dip)) {
7324 u32 tunnel_index;
7325
7326 tunnel_index = router->nve_decap_config.tunnel_index;
7327 fib_entry->decap.tunnel_index = tunnel_index;
7328 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP;
7329 }
7330
7331 return 0;
7332 }
7333
mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_entry * fib_entry,const struct fib6_info * rt)7334 static int mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
7335 struct mlxsw_sp_fib_entry *fib_entry,
7336 const struct fib6_info *rt)
7337 {
7338 if (rt->fib6_flags & RTF_LOCAL)
7339 return mlxsw_sp_fib6_entry_type_set_local(mlxsw_sp, fib_entry,
7340 rt);
7341 if (rt->fib6_flags & RTF_ANYCAST)
7342 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
7343 else if (rt->fib6_type == RTN_BLACKHOLE)
7344 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE;
7345 else if (rt->fib6_flags & RTF_REJECT)
7346 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE;
7347 else if (fib_entry->nh_group->nhgi->gateway)
7348 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
7349 else
7350 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
7351
7352 return 0;
7353 }
7354
7355 static void
mlxsw_sp_fib6_entry_rt_destroy_all(struct mlxsw_sp_fib6_entry * fib6_entry)7356 mlxsw_sp_fib6_entry_rt_destroy_all(struct mlxsw_sp_fib6_entry *fib6_entry)
7357 {
7358 struct mlxsw_sp_rt6 *mlxsw_sp_rt6, *tmp;
7359
7360 list_for_each_entry_safe(mlxsw_sp_rt6, tmp, &fib6_entry->rt6_list,
7361 list) {
7362 fib6_entry->nrt6--;
7363 list_del(&mlxsw_sp_rt6->list);
7364 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
7365 }
7366 }
7367
7368 static struct mlxsw_sp_fib6_entry *
mlxsw_sp_fib6_entry_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node,struct fib6_info ** rt_arr,unsigned int nrt6)7369 mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
7370 struct mlxsw_sp_fib_node *fib_node,
7371 struct fib6_info **rt_arr, unsigned int nrt6)
7372 {
7373 struct mlxsw_sp_fib6_entry *fib6_entry;
7374 struct mlxsw_sp_fib_entry *fib_entry;
7375 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
7376 int err, i;
7377
7378 fib6_entry = kzalloc_obj(*fib6_entry);
7379 if (!fib6_entry)
7380 return ERR_PTR(-ENOMEM);
7381 fib_entry = &fib6_entry->common;
7382
7383 INIT_LIST_HEAD(&fib6_entry->rt6_list);
7384
7385 for (i = 0; i < nrt6; i++) {
7386 mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt_arr[i]);
7387 if (IS_ERR(mlxsw_sp_rt6)) {
7388 err = PTR_ERR(mlxsw_sp_rt6);
7389 goto err_rt6_unwind;
7390 }
7391 list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list);
7392 fib6_entry->nrt6++;
7393 }
7394
7395 err = mlxsw_sp_nexthop6_group_get(mlxsw_sp, fib6_entry);
7396 if (err)
7397 goto err_rt6_unwind;
7398
7399 err = mlxsw_sp_nexthop_group_vr_link(fib_entry->nh_group,
7400 fib_node->fib);
7401 if (err)
7402 goto err_nexthop_group_vr_link;
7403
7404 err = mlxsw_sp_fib6_entry_type_set(mlxsw_sp, fib_entry, rt_arr[0]);
7405 if (err)
7406 goto err_fib6_entry_type_set;
7407
7408 fib_entry->fib_node = fib_node;
7409
7410 return fib6_entry;
7411
7412 err_fib6_entry_type_set:
7413 mlxsw_sp_nexthop_group_vr_unlink(fib_entry->nh_group, fib_node->fib);
7414 err_nexthop_group_vr_link:
7415 mlxsw_sp_nexthop6_group_put(mlxsw_sp, fib_entry);
7416 err_rt6_unwind:
7417 for (; i > 0; i--) {
7418 fib6_entry->nrt6--;
7419 mlxsw_sp_rt6 = list_last_entry(&fib6_entry->rt6_list,
7420 struct mlxsw_sp_rt6, list);
7421 list_del(&mlxsw_sp_rt6->list);
7422 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
7423 }
7424 kfree(fib6_entry);
7425 return ERR_PTR(err);
7426 }
7427
7428 static void
mlxsw_sp_fib6_entry_type_unset(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)7429 mlxsw_sp_fib6_entry_type_unset(struct mlxsw_sp *mlxsw_sp,
7430 struct mlxsw_sp_fib6_entry *fib6_entry)
7431 {
7432 mlxsw_sp_fib_entry_type_unset(mlxsw_sp, &fib6_entry->common);
7433 }
7434
mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib6_entry * fib6_entry)7435 static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp *mlxsw_sp,
7436 struct mlxsw_sp_fib6_entry *fib6_entry)
7437 {
7438 struct mlxsw_sp_fib_node *fib_node = fib6_entry->common.fib_node;
7439
7440 mlxsw_sp_fib6_entry_type_unset(mlxsw_sp, fib6_entry);
7441 mlxsw_sp_nexthop_group_vr_unlink(fib6_entry->common.nh_group,
7442 fib_node->fib);
7443 mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common);
7444 mlxsw_sp_fib6_entry_rt_destroy_all(fib6_entry);
7445 WARN_ON(fib6_entry->nrt6);
7446 kfree(fib6_entry);
7447 }
7448
7449 static struct mlxsw_sp_fib6_entry *
mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp * mlxsw_sp,const struct fib6_info * rt)7450 mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp,
7451 const struct fib6_info *rt)
7452 {
7453 struct mlxsw_sp_fib6_entry *fib6_entry;
7454 struct mlxsw_sp_fib_node *fib_node;
7455 struct mlxsw_sp_fib *fib;
7456 struct fib6_info *cmp_rt;
7457 struct mlxsw_sp_vr *vr;
7458
7459 vr = mlxsw_sp_vr_find(mlxsw_sp, rt->fib6_table->tb6_id);
7460 if (!vr)
7461 return NULL;
7462 fib = mlxsw_sp_vr_fib(vr, MLXSW_SP_L3_PROTO_IPV6);
7463
7464 fib_node = mlxsw_sp_fib_node_lookup(fib, &rt->fib6_dst.addr,
7465 sizeof(rt->fib6_dst.addr),
7466 rt->fib6_dst.plen);
7467 if (!fib_node)
7468 return NULL;
7469
7470 fib6_entry = container_of(fib_node->fib_entry,
7471 struct mlxsw_sp_fib6_entry, common);
7472 cmp_rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
7473 if (rt->fib6_table->tb6_id == cmp_rt->fib6_table->tb6_id &&
7474 rt->fib6_metric == cmp_rt->fib6_metric &&
7475 mlxsw_sp_fib6_entry_rt_find(fib6_entry, rt))
7476 return fib6_entry;
7477
7478 return NULL;
7479 }
7480
mlxsw_sp_fib6_allow_replace(struct mlxsw_sp_fib6_entry * fib6_entry)7481 static bool mlxsw_sp_fib6_allow_replace(struct mlxsw_sp_fib6_entry *fib6_entry)
7482 {
7483 struct mlxsw_sp_fib_node *fib_node = fib6_entry->common.fib_node;
7484 struct mlxsw_sp_fib6_entry *fib6_replaced;
7485 struct fib6_info *rt, *rt_replaced;
7486
7487 if (!fib_node->fib_entry)
7488 return true;
7489
7490 fib6_replaced = container_of(fib_node->fib_entry,
7491 struct mlxsw_sp_fib6_entry,
7492 common);
7493 rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
7494 rt_replaced = mlxsw_sp_fib6_entry_rt(fib6_replaced);
7495 if (rt->fib6_table->tb6_id == RT_TABLE_MAIN &&
7496 rt_replaced->fib6_table->tb6_id == RT_TABLE_LOCAL)
7497 return false;
7498
7499 return true;
7500 }
7501
mlxsw_sp_router_fib6_replace(struct mlxsw_sp * mlxsw_sp,struct fib6_info ** rt_arr,unsigned int nrt6)7502 static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
7503 struct fib6_info **rt_arr,
7504 unsigned int nrt6)
7505 {
7506 struct mlxsw_sp_fib6_entry *fib6_entry, *fib6_replaced;
7507 struct mlxsw_sp_fib_entry *replaced;
7508 struct mlxsw_sp_fib_node *fib_node;
7509 struct fib6_info *rt = rt_arr[0];
7510 int err;
7511
7512 if (rt->fib6_src.plen)
7513 return -EINVAL;
7514
7515 if (mlxsw_sp_fib6_rt_should_ignore(rt))
7516 return 0;
7517
7518 if (rt->nh && !mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp, rt->nh->id))
7519 return 0;
7520
7521 fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, rt->fib6_table->tb6_id,
7522 &rt->fib6_dst.addr,
7523 sizeof(rt->fib6_dst.addr),
7524 rt->fib6_dst.plen,
7525 MLXSW_SP_L3_PROTO_IPV6);
7526 if (IS_ERR(fib_node))
7527 return PTR_ERR(fib_node);
7528
7529 fib6_entry = mlxsw_sp_fib6_entry_create(mlxsw_sp, fib_node, rt_arr,
7530 nrt6);
7531 if (IS_ERR(fib6_entry)) {
7532 err = PTR_ERR(fib6_entry);
7533 goto err_fib6_entry_create;
7534 }
7535
7536 if (!mlxsw_sp_fib6_allow_replace(fib6_entry)) {
7537 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
7538 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
7539 return 0;
7540 }
7541
7542 replaced = fib_node->fib_entry;
7543 err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib6_entry->common);
7544 if (err)
7545 goto err_fib_node_entry_link;
7546
7547 /* Nothing to replace */
7548 if (!replaced)
7549 return 0;
7550
7551 mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, replaced);
7552 fib6_replaced = container_of(replaced, struct mlxsw_sp_fib6_entry,
7553 common);
7554 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_replaced);
7555
7556 return 0;
7557
7558 err_fib_node_entry_link:
7559 fib_node->fib_entry = replaced;
7560 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
7561 err_fib6_entry_create:
7562 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
7563 return err;
7564 }
7565
mlxsw_sp_router_fib6_append(struct mlxsw_sp * mlxsw_sp,struct fib6_info ** rt_arr,unsigned int nrt6)7566 static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp,
7567 struct fib6_info **rt_arr,
7568 unsigned int nrt6)
7569 {
7570 struct mlxsw_sp_fib6_entry *fib6_entry;
7571 struct mlxsw_sp_fib_node *fib_node;
7572 struct fib6_info *rt = rt_arr[0];
7573 int err;
7574
7575 if (rt->fib6_src.plen)
7576 return -EINVAL;
7577
7578 if (mlxsw_sp_fib6_rt_should_ignore(rt))
7579 return 0;
7580
7581 fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, rt->fib6_table->tb6_id,
7582 &rt->fib6_dst.addr,
7583 sizeof(rt->fib6_dst.addr),
7584 rt->fib6_dst.plen,
7585 MLXSW_SP_L3_PROTO_IPV6);
7586 if (IS_ERR(fib_node))
7587 return PTR_ERR(fib_node);
7588
7589 if (WARN_ON_ONCE(!fib_node->fib_entry)) {
7590 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
7591 return -EINVAL;
7592 }
7593
7594 fib6_entry = container_of(fib_node->fib_entry,
7595 struct mlxsw_sp_fib6_entry, common);
7596 err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt_arr,
7597 nrt6);
7598 if (err)
7599 goto err_fib6_entry_nexthop_add;
7600
7601 return 0;
7602
7603 err_fib6_entry_nexthop_add:
7604 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
7605 return err;
7606 }
7607
mlxsw_sp_router_fib6_del(struct mlxsw_sp * mlxsw_sp,struct fib6_info ** rt_arr,unsigned int nrt6)7608 static void mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
7609 struct fib6_info **rt_arr,
7610 unsigned int nrt6)
7611 {
7612 struct mlxsw_sp_fib6_entry *fib6_entry;
7613 struct mlxsw_sp_fib_node *fib_node;
7614 struct fib6_info *rt = rt_arr[0];
7615
7616 if (mlxsw_sp_fib6_rt_should_ignore(rt))
7617 return;
7618
7619 /* Multipath routes are first added to the FIB trie and only then
7620 * notified. If we vetoed the addition, we will get a delete
7621 * notification for a route we do not have. Therefore, do not warn if
7622 * route was not found.
7623 */
7624 fib6_entry = mlxsw_sp_fib6_entry_lookup(mlxsw_sp, rt);
7625 if (!fib6_entry)
7626 return;
7627
7628 /* If not all the nexthops are deleted, then only reduce the nexthop
7629 * group.
7630 */
7631 if (nrt6 != fib6_entry->nrt6) {
7632 mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp, fib6_entry, rt_arr,
7633 nrt6);
7634 return;
7635 }
7636
7637 fib_node = fib6_entry->common.fib_node;
7638
7639 mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib6_entry->common);
7640 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
7641 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
7642 }
7643
7644 static struct mlxsw_sp_mr_table *
mlxsw_sp_router_fibmr_family_to_table(struct mlxsw_sp_vr * vr,int family)7645 mlxsw_sp_router_fibmr_family_to_table(struct mlxsw_sp_vr *vr, int family)
7646 {
7647 if (family == RTNL_FAMILY_IPMR)
7648 return vr->mr_table[MLXSW_SP_L3_PROTO_IPV4];
7649 else
7650 return vr->mr_table[MLXSW_SP_L3_PROTO_IPV6];
7651 }
7652
mlxsw_sp_router_fibmr_add(struct mlxsw_sp * mlxsw_sp,struct mfc_entry_notifier_info * men_info,bool replace)7653 static int mlxsw_sp_router_fibmr_add(struct mlxsw_sp *mlxsw_sp,
7654 struct mfc_entry_notifier_info *men_info,
7655 bool replace)
7656 {
7657 struct mlxsw_sp_mr_table *mrt;
7658 struct mlxsw_sp_vr *vr;
7659
7660 vr = mlxsw_sp_vr_get(mlxsw_sp, men_info->tb_id, NULL);
7661 if (IS_ERR(vr))
7662 return PTR_ERR(vr);
7663
7664 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, men_info->info.family);
7665 return mlxsw_sp_mr_route_add(mrt, men_info->mfc, replace);
7666 }
7667
mlxsw_sp_router_fibmr_del(struct mlxsw_sp * mlxsw_sp,struct mfc_entry_notifier_info * men_info)7668 static void mlxsw_sp_router_fibmr_del(struct mlxsw_sp *mlxsw_sp,
7669 struct mfc_entry_notifier_info *men_info)
7670 {
7671 struct mlxsw_sp_mr_table *mrt;
7672 struct mlxsw_sp_vr *vr;
7673
7674 vr = mlxsw_sp_vr_find(mlxsw_sp, men_info->tb_id);
7675 if (WARN_ON(!vr))
7676 return;
7677
7678 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, men_info->info.family);
7679 mlxsw_sp_mr_route_del(mrt, men_info->mfc);
7680 mlxsw_sp_vr_put(mlxsw_sp, vr);
7681 }
7682
7683 static int
mlxsw_sp_router_fibmr_vif_add(struct mlxsw_sp * mlxsw_sp,struct vif_entry_notifier_info * ven_info)7684 mlxsw_sp_router_fibmr_vif_add(struct mlxsw_sp *mlxsw_sp,
7685 struct vif_entry_notifier_info *ven_info)
7686 {
7687 struct mlxsw_sp_mr_table *mrt;
7688 struct mlxsw_sp_rif *rif;
7689 struct mlxsw_sp_vr *vr;
7690
7691 vr = mlxsw_sp_vr_get(mlxsw_sp, ven_info->tb_id, NULL);
7692 if (IS_ERR(vr))
7693 return PTR_ERR(vr);
7694
7695 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, ven_info->info.family);
7696 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, ven_info->dev);
7697 return mlxsw_sp_mr_vif_add(mrt, ven_info->dev,
7698 ven_info->vif_index,
7699 ven_info->vif_flags, rif);
7700 }
7701
7702 static void
mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp * mlxsw_sp,struct vif_entry_notifier_info * ven_info)7703 mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp *mlxsw_sp,
7704 struct vif_entry_notifier_info *ven_info)
7705 {
7706 struct mlxsw_sp_mr_table *mrt;
7707 struct mlxsw_sp_vr *vr;
7708
7709 vr = mlxsw_sp_vr_find(mlxsw_sp, ven_info->tb_id);
7710 if (WARN_ON(!vr))
7711 return;
7712
7713 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, ven_info->info.family);
7714 mlxsw_sp_mr_vif_del(mrt, ven_info->vif_index);
7715 mlxsw_sp_vr_put(mlxsw_sp, vr);
7716 }
7717
mlxsw_sp_fib4_node_flush(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)7718 static void mlxsw_sp_fib4_node_flush(struct mlxsw_sp *mlxsw_sp,
7719 struct mlxsw_sp_fib_node *fib_node)
7720 {
7721 struct mlxsw_sp_fib4_entry *fib4_entry;
7722
7723 fib4_entry = container_of(fib_node->fib_entry,
7724 struct mlxsw_sp_fib4_entry, common);
7725 mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, fib_node->fib_entry);
7726 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
7727 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
7728 }
7729
mlxsw_sp_fib6_node_flush(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)7730 static void mlxsw_sp_fib6_node_flush(struct mlxsw_sp *mlxsw_sp,
7731 struct mlxsw_sp_fib_node *fib_node)
7732 {
7733 struct mlxsw_sp_fib6_entry *fib6_entry;
7734
7735 fib6_entry = container_of(fib_node->fib_entry,
7736 struct mlxsw_sp_fib6_entry, common);
7737 mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, fib_node->fib_entry);
7738 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
7739 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
7740 }
7741
mlxsw_sp_fib_node_flush(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fib_node * fib_node)7742 static void mlxsw_sp_fib_node_flush(struct mlxsw_sp *mlxsw_sp,
7743 struct mlxsw_sp_fib_node *fib_node)
7744 {
7745 switch (fib_node->fib->proto) {
7746 case MLXSW_SP_L3_PROTO_IPV4:
7747 mlxsw_sp_fib4_node_flush(mlxsw_sp, fib_node);
7748 break;
7749 case MLXSW_SP_L3_PROTO_IPV6:
7750 mlxsw_sp_fib6_node_flush(mlxsw_sp, fib_node);
7751 break;
7752 }
7753 }
7754
mlxsw_sp_vr_fib_flush(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_vr * vr,enum mlxsw_sp_l3proto proto)7755 static void mlxsw_sp_vr_fib_flush(struct mlxsw_sp *mlxsw_sp,
7756 struct mlxsw_sp_vr *vr,
7757 enum mlxsw_sp_l3proto proto)
7758 {
7759 struct mlxsw_sp_fib *fib = mlxsw_sp_vr_fib(vr, proto);
7760 struct mlxsw_sp_fib_node *fib_node, *tmp;
7761
7762 list_for_each_entry_safe(fib_node, tmp, &fib->node_list, list) {
7763 bool do_break = &tmp->list == &fib->node_list;
7764
7765 mlxsw_sp_fib_node_flush(mlxsw_sp, fib_node);
7766 if (do_break)
7767 break;
7768 }
7769 }
7770
mlxsw_sp_router_fib_flush(struct mlxsw_sp * mlxsw_sp)7771 static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp)
7772 {
7773 int max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS);
7774 int i, j;
7775
7776 for (i = 0; i < max_vrs; i++) {
7777 struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
7778
7779 if (!mlxsw_sp_vr_is_used(vr))
7780 continue;
7781
7782 for (j = 0; j < MLXSW_SP_L3_PROTO_MAX; j++)
7783 mlxsw_sp_mr_table_flush(vr->mr_table[j]);
7784 mlxsw_sp_vr_fib_flush(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
7785
7786 /* If virtual router was only used for IPv4, then it's no
7787 * longer used.
7788 */
7789 if (!mlxsw_sp_vr_is_used(vr))
7790 continue;
7791 mlxsw_sp_vr_fib_flush(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
7792 }
7793 }
7794
7795 struct mlxsw_sp_fib6_event_work {
7796 struct fib6_info **rt_arr;
7797 unsigned int nrt6;
7798 };
7799
7800 struct mlxsw_sp_fib_event_work {
7801 struct work_struct work;
7802 netdevice_tracker dev_tracker;
7803 union {
7804 struct mlxsw_sp_fib6_event_work fib6_work;
7805 struct fib_entry_notifier_info fen_info;
7806 struct fib_rule_notifier_info fr_info;
7807 struct fib_nh_notifier_info fnh_info;
7808 struct mfc_entry_notifier_info men_info;
7809 struct vif_entry_notifier_info ven_info;
7810 };
7811 struct mlxsw_sp *mlxsw_sp;
7812 unsigned long event;
7813 };
7814
7815 static int
mlxsw_sp_router_fib6_work_init(struct mlxsw_sp_fib6_event_work * fib6_work,struct fib6_entry_notifier_info * fen6_info)7816 mlxsw_sp_router_fib6_work_init(struct mlxsw_sp_fib6_event_work *fib6_work,
7817 struct fib6_entry_notifier_info *fen6_info)
7818 {
7819 struct fib6_info *rt = fen6_info->rt;
7820 struct fib6_info **rt_arr;
7821 struct fib6_info *iter;
7822 unsigned int nrt6;
7823 int i = 0;
7824
7825 nrt6 = fen6_info->nsiblings + 1;
7826
7827 rt_arr = kzalloc_objs(struct fib6_info *, nrt6, GFP_ATOMIC);
7828 if (!rt_arr)
7829 return -ENOMEM;
7830
7831 fib6_work->rt_arr = rt_arr;
7832 fib6_work->nrt6 = nrt6;
7833
7834 rt_arr[0] = rt;
7835 fib6_info_hold(rt);
7836
7837 if (!fen6_info->nsiblings)
7838 return 0;
7839
7840 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
7841 if (i == fen6_info->nsiblings)
7842 break;
7843
7844 rt_arr[i + 1] = iter;
7845 fib6_info_hold(iter);
7846 i++;
7847 }
7848 WARN_ON_ONCE(i != fen6_info->nsiblings);
7849
7850 return 0;
7851 }
7852
7853 static void
mlxsw_sp_router_fib6_work_fini(struct mlxsw_sp_fib6_event_work * fib6_work)7854 mlxsw_sp_router_fib6_work_fini(struct mlxsw_sp_fib6_event_work *fib6_work)
7855 {
7856 int i;
7857
7858 for (i = 0; i < fib6_work->nrt6; i++)
7859 mlxsw_sp_rt6_release(fib6_work->rt_arr[i]);
7860 kfree(fib6_work->rt_arr);
7861 }
7862
mlxsw_sp_router_fib4_event_work(struct work_struct * work)7863 static void mlxsw_sp_router_fib4_event_work(struct work_struct *work)
7864 {
7865 struct mlxsw_sp_fib_event_work *fib_work =
7866 container_of(work, struct mlxsw_sp_fib_event_work, work);
7867 struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
7868 int err;
7869
7870 mutex_lock(&mlxsw_sp->router->lock);
7871 mlxsw_sp_span_respin(mlxsw_sp);
7872
7873 switch (fib_work->event) {
7874 case FIB_EVENT_ENTRY_REPLACE:
7875 err = mlxsw_sp_router_fib4_replace(mlxsw_sp,
7876 &fib_work->fen_info);
7877 if (err) {
7878 dev_warn(mlxsw_sp->bus_info->dev, "FIB replace failed.\n");
7879 mlxsw_sp_fib4_offload_failed_flag_set(mlxsw_sp,
7880 &fib_work->fen_info);
7881 }
7882 fib_info_put(fib_work->fen_info.fi);
7883 break;
7884 case FIB_EVENT_ENTRY_DEL:
7885 mlxsw_sp_router_fib4_del(mlxsw_sp, &fib_work->fen_info);
7886 fib_info_put(fib_work->fen_info.fi);
7887 break;
7888 case FIB_EVENT_NH_ADD:
7889 case FIB_EVENT_NH_DEL:
7890 mlxsw_sp_nexthop4_event(mlxsw_sp, fib_work->event,
7891 fib_work->fnh_info.fib_nh);
7892 fib_info_put(fib_work->fnh_info.fib_nh->nh_parent);
7893 break;
7894 }
7895 mutex_unlock(&mlxsw_sp->router->lock);
7896 kfree(fib_work);
7897 }
7898
mlxsw_sp_router_fib6_event_work(struct work_struct * work)7899 static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
7900 {
7901 struct mlxsw_sp_fib_event_work *fib_work =
7902 container_of(work, struct mlxsw_sp_fib_event_work, work);
7903 struct mlxsw_sp_fib6_event_work *fib6_work = &fib_work->fib6_work;
7904 struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
7905 int err;
7906
7907 mutex_lock(&mlxsw_sp->router->lock);
7908 mlxsw_sp_span_respin(mlxsw_sp);
7909
7910 switch (fib_work->event) {
7911 case FIB_EVENT_ENTRY_REPLACE:
7912 err = mlxsw_sp_router_fib6_replace(mlxsw_sp,
7913 fib6_work->rt_arr,
7914 fib6_work->nrt6);
7915 if (err) {
7916 dev_warn(mlxsw_sp->bus_info->dev, "FIB replace failed.\n");
7917 mlxsw_sp_fib6_offload_failed_flag_set(mlxsw_sp,
7918 fib6_work->rt_arr,
7919 fib6_work->nrt6);
7920 }
7921 mlxsw_sp_router_fib6_work_fini(fib6_work);
7922 break;
7923 case FIB_EVENT_ENTRY_APPEND:
7924 err = mlxsw_sp_router_fib6_append(mlxsw_sp,
7925 fib6_work->rt_arr,
7926 fib6_work->nrt6);
7927 if (err) {
7928 dev_warn(mlxsw_sp->bus_info->dev, "FIB append failed.\n");
7929 mlxsw_sp_fib6_offload_failed_flag_set(mlxsw_sp,
7930 fib6_work->rt_arr,
7931 fib6_work->nrt6);
7932 }
7933 mlxsw_sp_router_fib6_work_fini(fib6_work);
7934 break;
7935 case FIB_EVENT_ENTRY_DEL:
7936 mlxsw_sp_router_fib6_del(mlxsw_sp,
7937 fib6_work->rt_arr,
7938 fib6_work->nrt6);
7939 mlxsw_sp_router_fib6_work_fini(fib6_work);
7940 break;
7941 }
7942 mutex_unlock(&mlxsw_sp->router->lock);
7943 kfree(fib_work);
7944 }
7945
mlxsw_sp_router_fibmr_event_work(struct work_struct * work)7946 static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work)
7947 {
7948 struct mlxsw_sp_fib_event_work *fib_work =
7949 container_of(work, struct mlxsw_sp_fib_event_work, work);
7950 struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
7951 bool replace;
7952 int err;
7953
7954 rtnl_lock();
7955 mutex_lock(&mlxsw_sp->router->lock);
7956 switch (fib_work->event) {
7957 case FIB_EVENT_ENTRY_REPLACE:
7958 case FIB_EVENT_ENTRY_ADD:
7959 replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
7960
7961 err = mlxsw_sp_router_fibmr_add(mlxsw_sp, &fib_work->men_info,
7962 replace);
7963 if (err)
7964 dev_warn(mlxsw_sp->bus_info->dev, "MR entry add failed.\n");
7965 mr_cache_put(fib_work->men_info.mfc);
7966 break;
7967 case FIB_EVENT_ENTRY_DEL:
7968 mlxsw_sp_router_fibmr_del(mlxsw_sp, &fib_work->men_info);
7969 mr_cache_put(fib_work->men_info.mfc);
7970 break;
7971 case FIB_EVENT_VIF_ADD:
7972 err = mlxsw_sp_router_fibmr_vif_add(mlxsw_sp,
7973 &fib_work->ven_info);
7974 if (err)
7975 dev_warn(mlxsw_sp->bus_info->dev, "MR VIF add failed.\n");
7976 netdev_put(fib_work->ven_info.dev, &fib_work->dev_tracker);
7977 break;
7978 case FIB_EVENT_VIF_DEL:
7979 mlxsw_sp_router_fibmr_vif_del(mlxsw_sp,
7980 &fib_work->ven_info);
7981 netdev_put(fib_work->ven_info.dev, &fib_work->dev_tracker);
7982 break;
7983 }
7984 mutex_unlock(&mlxsw_sp->router->lock);
7985 rtnl_unlock();
7986 kfree(fib_work);
7987 }
7988
mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work * fib_work,struct fib_notifier_info * info)7989 static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work *fib_work,
7990 struct fib_notifier_info *info)
7991 {
7992 struct fib_entry_notifier_info *fen_info;
7993 struct fib_nh_notifier_info *fnh_info;
7994
7995 switch (fib_work->event) {
7996 case FIB_EVENT_ENTRY_REPLACE:
7997 case FIB_EVENT_ENTRY_DEL:
7998 fen_info = container_of(info, struct fib_entry_notifier_info,
7999 info);
8000 fib_work->fen_info = *fen_info;
8001 /* Take reference on fib_info to prevent it from being
8002 * freed while work is queued. Release it afterwards.
8003 */
8004 fib_info_hold(fib_work->fen_info.fi);
8005 break;
8006 case FIB_EVENT_NH_ADD:
8007 case FIB_EVENT_NH_DEL:
8008 fnh_info = container_of(info, struct fib_nh_notifier_info,
8009 info);
8010 fib_work->fnh_info = *fnh_info;
8011 fib_info_hold(fib_work->fnh_info.fib_nh->nh_parent);
8012 break;
8013 }
8014 }
8015
mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work * fib_work,struct fib_notifier_info * info)8016 static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work,
8017 struct fib_notifier_info *info)
8018 {
8019 struct fib6_entry_notifier_info *fen6_info;
8020 int err;
8021
8022 switch (fib_work->event) {
8023 case FIB_EVENT_ENTRY_REPLACE:
8024 case FIB_EVENT_ENTRY_APPEND:
8025 case FIB_EVENT_ENTRY_DEL:
8026 fen6_info = container_of(info, struct fib6_entry_notifier_info,
8027 info);
8028 err = mlxsw_sp_router_fib6_work_init(&fib_work->fib6_work,
8029 fen6_info);
8030 if (err)
8031 return err;
8032 break;
8033 }
8034
8035 return 0;
8036 }
8037
8038 static void
mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event_work * fib_work,struct fib_notifier_info * info)8039 mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event_work *fib_work,
8040 struct fib_notifier_info *info)
8041 {
8042 switch (fib_work->event) {
8043 case FIB_EVENT_ENTRY_REPLACE:
8044 case FIB_EVENT_ENTRY_ADD:
8045 case FIB_EVENT_ENTRY_DEL:
8046 memcpy(&fib_work->men_info, info, sizeof(fib_work->men_info));
8047 mr_cache_hold(fib_work->men_info.mfc);
8048 break;
8049 case FIB_EVENT_VIF_ADD:
8050 case FIB_EVENT_VIF_DEL:
8051 memcpy(&fib_work->ven_info, info, sizeof(fib_work->ven_info));
8052 netdev_hold(fib_work->ven_info.dev, &fib_work->dev_tracker,
8053 GFP_ATOMIC);
8054 break;
8055 }
8056 }
8057
mlxsw_sp_router_fib_rule_event(unsigned long event,struct fib_notifier_info * info,struct mlxsw_sp * mlxsw_sp)8058 static int mlxsw_sp_router_fib_rule_event(unsigned long event,
8059 struct fib_notifier_info *info,
8060 struct mlxsw_sp *mlxsw_sp)
8061 {
8062 struct netlink_ext_ack *extack = info->extack;
8063 struct fib_rule_notifier_info *fr_info;
8064 struct fib_rule *rule;
8065 int err = 0;
8066
8067 /* nothing to do at the moment */
8068 if (event == FIB_EVENT_RULE_DEL)
8069 return 0;
8070
8071 fr_info = container_of(info, struct fib_rule_notifier_info, info);
8072 rule = fr_info->rule;
8073
8074 /* Rule only affects locally generated traffic */
8075 if (rule->iifindex == mlxsw_sp_net(mlxsw_sp)->loopback_dev->ifindex)
8076 return 0;
8077
8078 switch (info->family) {
8079 case AF_INET:
8080 if (!fib4_rule_default(rule) && !rule->l3mdev)
8081 err = -EOPNOTSUPP;
8082 break;
8083 case AF_INET6:
8084 if (!fib6_rule_default(rule) && !rule->l3mdev)
8085 err = -EOPNOTSUPP;
8086 break;
8087 case RTNL_FAMILY_IPMR:
8088 if (!ipmr_rule_default(rule) && !rule->l3mdev)
8089 err = -EOPNOTSUPP;
8090 break;
8091 case RTNL_FAMILY_IP6MR:
8092 if (!ip6mr_rule_default(rule) && !rule->l3mdev)
8093 err = -EOPNOTSUPP;
8094 break;
8095 }
8096
8097 if (err < 0)
8098 NL_SET_ERR_MSG_MOD(extack, "FIB rules not supported");
8099
8100 return err;
8101 }
8102
8103 /* Called with rcu_read_lock() */
mlxsw_sp_router_fib_event(struct notifier_block * nb,unsigned long event,void * ptr)8104 static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
8105 unsigned long event, void *ptr)
8106 {
8107 struct mlxsw_sp_fib_event_work *fib_work;
8108 struct fib_notifier_info *info = ptr;
8109 struct mlxsw_sp_router *router;
8110 int err;
8111
8112 if ((info->family != AF_INET && info->family != AF_INET6 &&
8113 info->family != RTNL_FAMILY_IPMR &&
8114 info->family != RTNL_FAMILY_IP6MR))
8115 return NOTIFY_DONE;
8116
8117 router = container_of(nb, struct mlxsw_sp_router, fib_nb);
8118
8119 switch (event) {
8120 case FIB_EVENT_RULE_ADD:
8121 case FIB_EVENT_RULE_DEL:
8122 err = mlxsw_sp_router_fib_rule_event(event, info,
8123 router->mlxsw_sp);
8124 return notifier_from_errno(err);
8125 case FIB_EVENT_ENTRY_ADD:
8126 case FIB_EVENT_ENTRY_REPLACE:
8127 case FIB_EVENT_ENTRY_APPEND:
8128 if (info->family == AF_INET) {
8129 struct fib_entry_notifier_info *fen_info = ptr;
8130
8131 if (fen_info->fi->fib_nh_is_v6) {
8132 NL_SET_ERR_MSG_MOD(info->extack, "IPv6 gateway with IPv4 route is not supported");
8133 return notifier_from_errno(-EINVAL);
8134 }
8135 }
8136 break;
8137 }
8138
8139 fib_work = kzalloc_obj(*fib_work, GFP_ATOMIC);
8140 if (!fib_work)
8141 return NOTIFY_BAD;
8142
8143 fib_work->mlxsw_sp = router->mlxsw_sp;
8144 fib_work->event = event;
8145
8146 switch (info->family) {
8147 case AF_INET:
8148 INIT_WORK(&fib_work->work, mlxsw_sp_router_fib4_event_work);
8149 mlxsw_sp_router_fib4_event(fib_work, info);
8150 break;
8151 case AF_INET6:
8152 INIT_WORK(&fib_work->work, mlxsw_sp_router_fib6_event_work);
8153 err = mlxsw_sp_router_fib6_event(fib_work, info);
8154 if (err)
8155 goto err_fib_event;
8156 break;
8157 case RTNL_FAMILY_IP6MR:
8158 case RTNL_FAMILY_IPMR:
8159 INIT_WORK(&fib_work->work, mlxsw_sp_router_fibmr_event_work);
8160 mlxsw_sp_router_fibmr_event(fib_work, info);
8161 break;
8162 }
8163
8164 mlxsw_core_schedule_work(&fib_work->work);
8165
8166 return NOTIFY_DONE;
8167
8168 err_fib_event:
8169 kfree(fib_work);
8170 return NOTIFY_BAD;
8171 }
8172
8173 static struct mlxsw_sp_rif *
mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp * mlxsw_sp,const struct net_device * dev)8174 mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
8175 const struct net_device *dev)
8176 {
8177 int max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
8178 int i;
8179
8180 for (i = 0; i < max_rifs; i++)
8181 if (mlxsw_sp->router->rifs[i] &&
8182 mlxsw_sp_rif_dev_is(mlxsw_sp->router->rifs[i], dev))
8183 return mlxsw_sp->router->rifs[i];
8184
8185 return NULL;
8186 }
8187
mlxsw_sp_router_rif_disable(struct mlxsw_sp * mlxsw_sp,u16 rif)8188 static int mlxsw_sp_router_rif_disable(struct mlxsw_sp *mlxsw_sp, u16 rif)
8189 {
8190 char ritr_pl[MLXSW_REG_RITR_LEN];
8191 int err;
8192
8193 mlxsw_reg_ritr_rif_pack(ritr_pl, rif);
8194 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
8195 if (err)
8196 return err;
8197
8198 mlxsw_reg_ritr_enable_set(ritr_pl, false);
8199 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
8200 }
8201
mlxsw_sp_router_rif_made_sync(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif)8202 static int mlxsw_sp_router_rif_made_sync(struct mlxsw_sp *mlxsw_sp,
8203 struct mlxsw_sp_rif *rif)
8204 {
8205 int err;
8206
8207 err = mlxsw_sp_neigh_rif_made_sync(mlxsw_sp, rif);
8208 if (err)
8209 return err;
8210
8211 err = mlxsw_sp_nexthop_rif_made_sync(mlxsw_sp, rif);
8212 if (err)
8213 goto err_nexthop;
8214
8215 return 0;
8216
8217 err_nexthop:
8218 mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif);
8219 return err;
8220 }
8221
mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif)8222 static void mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
8223 struct mlxsw_sp_rif *rif)
8224 {
8225 /* Signal to nexthop cleanup that the RIF is going away. */
8226 rif->crif->rif = NULL;
8227
8228 mlxsw_sp_router_rif_disable(mlxsw_sp, rif->rif_index);
8229 mlxsw_sp_nexthop_rif_gone_sync(mlxsw_sp, rif);
8230 mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif);
8231 }
8232
__mlxsw_sp_dev_addr_list_empty(const struct net_device * dev)8233 static bool __mlxsw_sp_dev_addr_list_empty(const struct net_device *dev)
8234 {
8235 struct inet6_dev *inet6_dev;
8236 struct in_device *idev;
8237
8238 idev = __in_dev_get_rcu(dev);
8239 if (idev && idev->ifa_list)
8240 return false;
8241
8242 inet6_dev = __in6_dev_get(dev);
8243 if (inet6_dev && !list_empty(&inet6_dev->addr_list))
8244 return false;
8245
8246 return true;
8247 }
8248
mlxsw_sp_dev_addr_list_empty(const struct net_device * dev)8249 static bool mlxsw_sp_dev_addr_list_empty(const struct net_device *dev)
8250 {
8251 bool addr_list_empty;
8252
8253 rcu_read_lock();
8254 addr_list_empty = __mlxsw_sp_dev_addr_list_empty(dev);
8255 rcu_read_unlock();
8256
8257 return addr_list_empty;
8258 }
8259
8260 static bool
mlxsw_sp_rif_should_config(struct mlxsw_sp_rif * rif,struct net_device * dev,unsigned long event)8261 mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *rif, struct net_device *dev,
8262 unsigned long event)
8263 {
8264 bool addr_list_empty;
8265
8266 switch (event) {
8267 case NETDEV_UP:
8268 return rif == NULL;
8269 case NETDEV_DOWN:
8270 addr_list_empty = mlxsw_sp_dev_addr_list_empty(dev);
8271
8272 /* macvlans do not have a RIF, but rather piggy back on the
8273 * RIF of their lower device.
8274 */
8275 if (netif_is_macvlan(dev) && addr_list_empty)
8276 return true;
8277
8278 if (rif && addr_list_empty &&
8279 !netif_is_l3_slave(mlxsw_sp_rif_dev(rif)))
8280 return true;
8281 /* It is possible we already removed the RIF ourselves
8282 * if it was assigned to a netdev that is now a bridge
8283 * or LAG slave.
8284 */
8285 return false;
8286 }
8287
8288 return false;
8289 }
8290
8291 static enum mlxsw_sp_rif_type
mlxsw_sp_dev_rif_type(const struct mlxsw_sp * mlxsw_sp,const struct net_device * dev)8292 mlxsw_sp_dev_rif_type(const struct mlxsw_sp *mlxsw_sp,
8293 const struct net_device *dev)
8294 {
8295 enum mlxsw_sp_fid_type type;
8296
8297 if (mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, NULL))
8298 return MLXSW_SP_RIF_TYPE_IPIP_LB;
8299
8300 /* Otherwise RIF type is derived from the type of the underlying FID. */
8301 if (is_vlan_dev(dev) && netif_is_bridge_master(vlan_dev_real_dev(dev)))
8302 type = MLXSW_SP_FID_TYPE_8021Q;
8303 else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev))
8304 type = MLXSW_SP_FID_TYPE_8021Q;
8305 else if (netif_is_bridge_master(dev))
8306 type = MLXSW_SP_FID_TYPE_8021D;
8307 else
8308 type = MLXSW_SP_FID_TYPE_RFID;
8309
8310 return mlxsw_sp_fid_type_rif_type(mlxsw_sp, type);
8311 }
8312
mlxsw_sp_rif_index_alloc(struct mlxsw_sp * mlxsw_sp,u16 * p_rif_index,u8 rif_entries)8313 static int mlxsw_sp_rif_index_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_rif_index,
8314 u8 rif_entries)
8315 {
8316 *p_rif_index = gen_pool_alloc(mlxsw_sp->router->rifs_table,
8317 rif_entries);
8318 if (*p_rif_index == 0)
8319 return -ENOBUFS;
8320 *p_rif_index -= MLXSW_SP_ROUTER_GENALLOC_OFFSET;
8321
8322 /* RIF indexes must be aligned to the allocation size. */
8323 WARN_ON_ONCE(*p_rif_index % rif_entries);
8324
8325 return 0;
8326 }
8327
mlxsw_sp_rif_index_free(struct mlxsw_sp * mlxsw_sp,u16 rif_index,u8 rif_entries)8328 static void mlxsw_sp_rif_index_free(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
8329 u8 rif_entries)
8330 {
8331 gen_pool_free(mlxsw_sp->router->rifs_table,
8332 MLXSW_SP_ROUTER_GENALLOC_OFFSET + rif_index, rif_entries);
8333 }
8334
mlxsw_sp_rif_alloc(size_t rif_size,u16 rif_index,u16 vr_id,struct mlxsw_sp_crif * crif)8335 static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index,
8336 u16 vr_id,
8337 struct mlxsw_sp_crif *crif)
8338 {
8339 struct net_device *l3_dev = crif ? crif->key.dev : NULL;
8340 struct mlxsw_sp_rif *rif;
8341
8342 rif = kzalloc(rif_size, GFP_KERNEL);
8343 if (!rif)
8344 return NULL;
8345
8346 INIT_LIST_HEAD(&rif->neigh_list);
8347 if (l3_dev) {
8348 ether_addr_copy(rif->addr, l3_dev->dev_addr);
8349 rif->mtu = l3_dev->mtu;
8350 }
8351 rif->vr_id = vr_id;
8352 rif->rif_index = rif_index;
8353 if (crif) {
8354 rif->crif = crif;
8355 crif->rif = rif;
8356 }
8357
8358 return rif;
8359 }
8360
mlxsw_sp_rif_free(struct mlxsw_sp_rif * rif)8361 static void mlxsw_sp_rif_free(struct mlxsw_sp_rif *rif)
8362 {
8363 WARN_ON(!list_empty(&rif->neigh_list));
8364
8365 if (rif->crif)
8366 rif->crif->rif = NULL;
8367 kfree(rif);
8368 }
8369
mlxsw_sp_rif_by_index(const struct mlxsw_sp * mlxsw_sp,u16 rif_index)8370 struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
8371 u16 rif_index)
8372 {
8373 return mlxsw_sp->router->rifs[rif_index];
8374 }
8375
mlxsw_sp_rif_index(const struct mlxsw_sp_rif * rif)8376 u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif)
8377 {
8378 return rif->rif_index;
8379 }
8380
mlxsw_sp_ipip_lb_rif_index(const struct mlxsw_sp_rif_ipip_lb * lb_rif)8381 u16 mlxsw_sp_ipip_lb_rif_index(const struct mlxsw_sp_rif_ipip_lb *lb_rif)
8382 {
8383 return lb_rif->common.rif_index;
8384 }
8385
mlxsw_sp_ipip_lb_ul_rif_id(const struct mlxsw_sp_rif_ipip_lb * lb_rif)8386 u16 mlxsw_sp_ipip_lb_ul_rif_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif)
8387 {
8388 return lb_rif->ul_rif_id;
8389 }
8390
8391 static bool
mlxsw_sp_router_port_l3_stats_enabled(struct mlxsw_sp_rif * rif)8392 mlxsw_sp_router_port_l3_stats_enabled(struct mlxsw_sp_rif *rif)
8393 {
8394 return mlxsw_sp_rif_counter_valid_get(rif,
8395 MLXSW_SP_RIF_COUNTER_EGRESS) &&
8396 mlxsw_sp_rif_counter_valid_get(rif,
8397 MLXSW_SP_RIF_COUNTER_INGRESS);
8398 }
8399
8400 static int
mlxsw_sp_router_port_l3_stats_enable(struct mlxsw_sp_rif * rif)8401 mlxsw_sp_router_port_l3_stats_enable(struct mlxsw_sp_rif *rif)
8402 {
8403 int err;
8404
8405 err = mlxsw_sp_rif_counter_alloc(rif, MLXSW_SP_RIF_COUNTER_INGRESS);
8406 if (err)
8407 return err;
8408
8409 /* Clear stale data. */
8410 err = mlxsw_sp_rif_counter_fetch_clear(rif,
8411 MLXSW_SP_RIF_COUNTER_INGRESS,
8412 NULL);
8413 if (err)
8414 goto err_clear_ingress;
8415
8416 err = mlxsw_sp_rif_counter_alloc(rif, MLXSW_SP_RIF_COUNTER_EGRESS);
8417 if (err)
8418 goto err_alloc_egress;
8419
8420 /* Clear stale data. */
8421 err = mlxsw_sp_rif_counter_fetch_clear(rif,
8422 MLXSW_SP_RIF_COUNTER_EGRESS,
8423 NULL);
8424 if (err)
8425 goto err_clear_egress;
8426
8427 return 0;
8428
8429 err_clear_egress:
8430 mlxsw_sp_rif_counter_free(rif, MLXSW_SP_RIF_COUNTER_EGRESS);
8431 err_alloc_egress:
8432 err_clear_ingress:
8433 mlxsw_sp_rif_counter_free(rif, MLXSW_SP_RIF_COUNTER_INGRESS);
8434 return err;
8435 }
8436
8437 static void
mlxsw_sp_router_port_l3_stats_disable(struct mlxsw_sp_rif * rif)8438 mlxsw_sp_router_port_l3_stats_disable(struct mlxsw_sp_rif *rif)
8439 {
8440 mlxsw_sp_rif_counter_free(rif, MLXSW_SP_RIF_COUNTER_EGRESS);
8441 mlxsw_sp_rif_counter_free(rif, MLXSW_SP_RIF_COUNTER_INGRESS);
8442 }
8443
8444 static void
mlxsw_sp_router_port_l3_stats_report_used(struct mlxsw_sp_rif * rif,struct netdev_notifier_offload_xstats_info * info)8445 mlxsw_sp_router_port_l3_stats_report_used(struct mlxsw_sp_rif *rif,
8446 struct netdev_notifier_offload_xstats_info *info)
8447 {
8448 if (!mlxsw_sp_router_port_l3_stats_enabled(rif))
8449 return;
8450 netdev_offload_xstats_report_used(info->report_used);
8451 }
8452
8453 static int
mlxsw_sp_router_port_l3_stats_fetch(struct mlxsw_sp_rif * rif,struct rtnl_hw_stats64 * p_stats)8454 mlxsw_sp_router_port_l3_stats_fetch(struct mlxsw_sp_rif *rif,
8455 struct rtnl_hw_stats64 *p_stats)
8456 {
8457 struct mlxsw_sp_rif_counter_set_basic ingress;
8458 struct mlxsw_sp_rif_counter_set_basic egress;
8459 int err;
8460
8461 err = mlxsw_sp_rif_counter_fetch_clear(rif,
8462 MLXSW_SP_RIF_COUNTER_INGRESS,
8463 &ingress);
8464 if (err)
8465 return err;
8466
8467 err = mlxsw_sp_rif_counter_fetch_clear(rif,
8468 MLXSW_SP_RIF_COUNTER_EGRESS,
8469 &egress);
8470 if (err)
8471 return err;
8472
8473 #define MLXSW_SP_ROUTER_ALL_GOOD(SET, SFX) \
8474 ((SET.good_unicast_ ## SFX) + \
8475 (SET.good_multicast_ ## SFX) + \
8476 (SET.good_broadcast_ ## SFX))
8477
8478 p_stats->rx_packets = MLXSW_SP_ROUTER_ALL_GOOD(ingress, packets);
8479 p_stats->tx_packets = MLXSW_SP_ROUTER_ALL_GOOD(egress, packets);
8480 p_stats->rx_bytes = MLXSW_SP_ROUTER_ALL_GOOD(ingress, bytes);
8481 p_stats->tx_bytes = MLXSW_SP_ROUTER_ALL_GOOD(egress, bytes);
8482 p_stats->rx_errors = ingress.error_packets;
8483 p_stats->tx_errors = egress.error_packets;
8484 p_stats->rx_dropped = ingress.discard_packets;
8485 p_stats->tx_dropped = egress.discard_packets;
8486 p_stats->multicast = ingress.good_multicast_packets +
8487 ingress.good_broadcast_packets;
8488
8489 #undef MLXSW_SP_ROUTER_ALL_GOOD
8490
8491 return 0;
8492 }
8493
8494 static int
mlxsw_sp_router_port_l3_stats_report_delta(struct mlxsw_sp_rif * rif,struct netdev_notifier_offload_xstats_info * info)8495 mlxsw_sp_router_port_l3_stats_report_delta(struct mlxsw_sp_rif *rif,
8496 struct netdev_notifier_offload_xstats_info *info)
8497 {
8498 struct rtnl_hw_stats64 stats = {};
8499 int err;
8500
8501 if (!mlxsw_sp_router_port_l3_stats_enabled(rif))
8502 return 0;
8503
8504 err = mlxsw_sp_router_port_l3_stats_fetch(rif, &stats);
8505 if (err)
8506 return err;
8507
8508 netdev_offload_xstats_report_delta(info->report_delta, &stats);
8509 return 0;
8510 }
8511
8512 struct mlxsw_sp_router_hwstats_notify_work {
8513 struct work_struct work;
8514 struct net_device *dev;
8515 netdevice_tracker dev_tracker;
8516 };
8517
mlxsw_sp_router_hwstats_notify_work(struct work_struct * work)8518 static void mlxsw_sp_router_hwstats_notify_work(struct work_struct *work)
8519 {
8520 struct mlxsw_sp_router_hwstats_notify_work *hws_work =
8521 container_of(work, struct mlxsw_sp_router_hwstats_notify_work,
8522 work);
8523
8524 rtnl_lock();
8525 rtnl_offload_xstats_notify(hws_work->dev);
8526 rtnl_unlock();
8527 netdev_put(hws_work->dev, &hws_work->dev_tracker);
8528 kfree(hws_work);
8529 }
8530
8531 static void
mlxsw_sp_router_hwstats_notify_schedule(struct net_device * dev)8532 mlxsw_sp_router_hwstats_notify_schedule(struct net_device *dev)
8533 {
8534 struct mlxsw_sp_router_hwstats_notify_work *hws_work;
8535
8536 /* To collect notification payload, the core ends up sending another
8537 * notifier block message, which would deadlock on the attempt to
8538 * acquire the router lock again. Just postpone the notification until
8539 * later.
8540 */
8541
8542 hws_work = kzalloc_obj(*hws_work);
8543 if (!hws_work)
8544 return;
8545
8546 INIT_WORK(&hws_work->work, mlxsw_sp_router_hwstats_notify_work);
8547 netdev_hold(dev, &hws_work->dev_tracker, GFP_KERNEL);
8548 hws_work->dev = dev;
8549 mlxsw_core_schedule_work(&hws_work->work);
8550 }
8551
mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif * rif)8552 int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif)
8553 {
8554 return mlxsw_sp_rif_dev(rif)->ifindex;
8555 }
8556
mlxsw_sp_rif_has_dev(const struct mlxsw_sp_rif * rif)8557 bool mlxsw_sp_rif_has_dev(const struct mlxsw_sp_rif *rif)
8558 {
8559 return !!mlxsw_sp_rif_dev(rif);
8560 }
8561
mlxsw_sp_rif_dev_is(const struct mlxsw_sp_rif * rif,const struct net_device * dev)8562 bool mlxsw_sp_rif_dev_is(const struct mlxsw_sp_rif *rif,
8563 const struct net_device *dev)
8564 {
8565 return mlxsw_sp_rif_dev(rif) == dev;
8566 }
8567
mlxsw_sp_rif_push_l3_stats(struct mlxsw_sp_rif * rif)8568 static void mlxsw_sp_rif_push_l3_stats(struct mlxsw_sp_rif *rif)
8569 {
8570 struct rtnl_hw_stats64 stats = {};
8571
8572 if (!mlxsw_sp_router_port_l3_stats_fetch(rif, &stats))
8573 netdev_offload_xstats_push_delta(mlxsw_sp_rif_dev(rif),
8574 NETDEV_OFFLOAD_XSTATS_TYPE_L3,
8575 &stats);
8576 }
8577
8578 static struct mlxsw_sp_rif *
mlxsw_sp_rif_create(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_rif_params * params,struct netlink_ext_ack * extack)8579 mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
8580 const struct mlxsw_sp_rif_params *params,
8581 struct netlink_ext_ack *extack)
8582 {
8583 u8 rif_entries = params->double_entry ? 2 : 1;
8584 u32 tb_id = l3mdev_fib_table(params->dev);
8585 const struct mlxsw_sp_rif_ops *ops;
8586 struct mlxsw_sp_fid *fid = NULL;
8587 enum mlxsw_sp_rif_type type;
8588 struct mlxsw_sp_crif *crif;
8589 struct mlxsw_sp_rif *rif;
8590 struct mlxsw_sp_vr *vr;
8591 u16 rif_index;
8592 int i, err;
8593
8594 type = mlxsw_sp_dev_rif_type(mlxsw_sp, params->dev);
8595 ops = mlxsw_sp->router->rif_ops_arr[type];
8596
8597 vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN, extack);
8598 if (IS_ERR(vr))
8599 return ERR_CAST(vr);
8600 vr->rif_count++;
8601
8602 err = mlxsw_sp_rif_index_alloc(mlxsw_sp, &rif_index, rif_entries);
8603 if (err) {
8604 NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported router interfaces");
8605 goto err_rif_index_alloc;
8606 }
8607
8608 crif = mlxsw_sp_crif_lookup(mlxsw_sp->router, params->dev);
8609 if (WARN_ON(!crif)) {
8610 err = -ENOENT;
8611 goto err_crif_lookup;
8612 }
8613
8614 rif = mlxsw_sp_rif_alloc(ops->rif_size, rif_index, vr->id, crif);
8615 if (!rif) {
8616 err = -ENOMEM;
8617 goto err_rif_alloc;
8618 }
8619 netdev_hold(params->dev, &rif->dev_tracker, GFP_KERNEL);
8620 mlxsw_sp->router->rifs[rif_index] = rif;
8621 rif->mlxsw_sp = mlxsw_sp;
8622 rif->ops = ops;
8623 rif->rif_entries = rif_entries;
8624
8625 if (ops->setup)
8626 ops->setup(rif, params);
8627
8628 if (ops->fid_get) {
8629 fid = ops->fid_get(rif, params, extack);
8630 if (IS_ERR(fid)) {
8631 err = PTR_ERR(fid);
8632 goto err_fid_get;
8633 }
8634 rif->fid = fid;
8635 }
8636
8637 err = ops->configure(rif, extack);
8638 if (err)
8639 goto err_configure;
8640
8641 for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++) {
8642 err = mlxsw_sp_mr_rif_add(vr->mr_table[i], rif);
8643 if (err)
8644 goto err_mr_rif_add;
8645 }
8646
8647 err = mlxsw_sp_router_rif_made_sync(mlxsw_sp, rif);
8648 if (err)
8649 goto err_rif_made_sync;
8650
8651 if (netdev_offload_xstats_enabled(params->dev,
8652 NETDEV_OFFLOAD_XSTATS_TYPE_L3)) {
8653 err = mlxsw_sp_router_port_l3_stats_enable(rif);
8654 if (err)
8655 goto err_stats_enable;
8656 mlxsw_sp_router_hwstats_notify_schedule(params->dev);
8657 } else {
8658 mlxsw_sp_rif_counters_alloc(rif);
8659 }
8660
8661 atomic_add(rif_entries, &mlxsw_sp->router->rifs_count);
8662 return rif;
8663
8664 err_stats_enable:
8665 mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
8666 err_rif_made_sync:
8667 err_mr_rif_add:
8668 for (i--; i >= 0; i--)
8669 mlxsw_sp_mr_rif_del(vr->mr_table[i], rif);
8670 ops->deconfigure(rif);
8671 err_configure:
8672 if (fid)
8673 mlxsw_sp_fid_put(fid);
8674 err_fid_get:
8675 mlxsw_sp->router->rifs[rif_index] = NULL;
8676 netdev_put(params->dev, &rif->dev_tracker);
8677 mlxsw_sp_rif_free(rif);
8678 err_rif_alloc:
8679 err_crif_lookup:
8680 mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries);
8681 err_rif_index_alloc:
8682 vr->rif_count--;
8683 mlxsw_sp_vr_put(mlxsw_sp, vr);
8684 return ERR_PTR(err);
8685 }
8686
mlxsw_sp_rif_destroy(struct mlxsw_sp_rif * rif)8687 static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
8688 {
8689 struct net_device *dev = mlxsw_sp_rif_dev(rif);
8690 const struct mlxsw_sp_rif_ops *ops = rif->ops;
8691 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
8692 struct mlxsw_sp_crif *crif = rif->crif;
8693 struct mlxsw_sp_fid *fid = rif->fid;
8694 u8 rif_entries = rif->rif_entries;
8695 u16 rif_index = rif->rif_index;
8696 struct mlxsw_sp_vr *vr;
8697 int i;
8698
8699 atomic_sub(rif_entries, &mlxsw_sp->router->rifs_count);
8700 mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
8701 vr = &mlxsw_sp->router->vrs[rif->vr_id];
8702
8703 if (netdev_offload_xstats_enabled(dev, NETDEV_OFFLOAD_XSTATS_TYPE_L3)) {
8704 mlxsw_sp_rif_push_l3_stats(rif);
8705 mlxsw_sp_router_port_l3_stats_disable(rif);
8706 mlxsw_sp_router_hwstats_notify_schedule(dev);
8707 } else {
8708 mlxsw_sp_rif_counters_free(rif);
8709 }
8710
8711 for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++)
8712 mlxsw_sp_mr_rif_del(vr->mr_table[i], rif);
8713 ops->deconfigure(rif);
8714 if (fid)
8715 /* Loopback RIFs are not associated with a FID. */
8716 mlxsw_sp_fid_put(fid);
8717 mlxsw_sp->router->rifs[rif->rif_index] = NULL;
8718 netdev_put(dev, &rif->dev_tracker);
8719 mlxsw_sp_rif_free(rif);
8720 mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries);
8721 vr->rif_count--;
8722 mlxsw_sp_vr_put(mlxsw_sp, vr);
8723
8724 if (crif->can_destroy)
8725 mlxsw_sp_crif_free(crif);
8726 }
8727
mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp * mlxsw_sp,struct net_device * dev)8728 void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp,
8729 struct net_device *dev)
8730 {
8731 struct mlxsw_sp_rif *rif;
8732
8733 mutex_lock(&mlxsw_sp->router->lock);
8734 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
8735 if (!rif)
8736 goto out;
8737 mlxsw_sp_rif_destroy(rif);
8738 out:
8739 mutex_unlock(&mlxsw_sp->router->lock);
8740 }
8741
mlxsw_sp_rif_destroy_vlan_upper(struct mlxsw_sp * mlxsw_sp,struct net_device * br_dev,u16 vid)8742 static void mlxsw_sp_rif_destroy_vlan_upper(struct mlxsw_sp *mlxsw_sp,
8743 struct net_device *br_dev,
8744 u16 vid)
8745 {
8746 struct net_device *upper_dev;
8747 struct mlxsw_sp_crif *crif;
8748
8749 rcu_read_lock();
8750 upper_dev = __vlan_find_dev_deep_rcu(br_dev, htons(ETH_P_8021Q), vid);
8751 rcu_read_unlock();
8752
8753 if (!upper_dev)
8754 return;
8755
8756 crif = mlxsw_sp_crif_lookup(mlxsw_sp->router, upper_dev);
8757 if (!crif || !crif->rif)
8758 return;
8759
8760 mlxsw_sp_rif_destroy(crif->rif);
8761 }
8762
8763 static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
8764 struct net_device *l3_dev,
8765 int lower_pvid,
8766 unsigned long event,
8767 struct netlink_ext_ack *extack);
8768
mlxsw_sp_router_bridge_vlan_add(struct mlxsw_sp * mlxsw_sp,struct net_device * br_dev,u16 new_vid,bool is_pvid,struct netlink_ext_ack * extack)8769 int mlxsw_sp_router_bridge_vlan_add(struct mlxsw_sp *mlxsw_sp,
8770 struct net_device *br_dev,
8771 u16 new_vid, bool is_pvid,
8772 struct netlink_ext_ack *extack)
8773 {
8774 struct mlxsw_sp_rif *old_rif;
8775 struct mlxsw_sp_rif *new_rif;
8776 struct net_device *upper_dev;
8777 u16 old_pvid = 0;
8778 u16 new_pvid;
8779 int err = 0;
8780
8781 mutex_lock(&mlxsw_sp->router->lock);
8782 old_rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, br_dev);
8783 if (old_rif) {
8784 /* If the RIF on the bridge is not a VLAN RIF, we shouldn't have
8785 * gotten a PVID notification.
8786 */
8787 if (WARN_ON(old_rif->ops->type != MLXSW_SP_RIF_TYPE_VLAN))
8788 old_rif = NULL;
8789 else
8790 old_pvid = mlxsw_sp_fid_8021q_vid(old_rif->fid);
8791 }
8792
8793 if (is_pvid)
8794 new_pvid = new_vid;
8795 else if (old_pvid == new_vid)
8796 new_pvid = 0;
8797 else
8798 goto out;
8799
8800 if (old_pvid == new_pvid)
8801 goto out;
8802
8803 if (new_pvid) {
8804 struct mlxsw_sp_rif_params params = {
8805 .dev = br_dev,
8806 .vid = new_pvid,
8807 };
8808
8809 /* If there is a VLAN upper with the same VID as the new PVID,
8810 * kill its RIF, if there is one.
8811 */
8812 mlxsw_sp_rif_destroy_vlan_upper(mlxsw_sp, br_dev, new_pvid);
8813
8814 if (mlxsw_sp_dev_addr_list_empty(br_dev))
8815 goto out;
8816 new_rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms, extack);
8817 if (IS_ERR(new_rif)) {
8818 err = PTR_ERR(new_rif);
8819 goto out;
8820 }
8821
8822 if (old_pvid)
8823 mlxsw_sp_rif_migrate_destroy(mlxsw_sp, old_rif, new_rif,
8824 true);
8825 } else {
8826 mlxsw_sp_rif_destroy(old_rif);
8827 }
8828
8829 if (old_pvid) {
8830 rcu_read_lock();
8831 upper_dev = __vlan_find_dev_deep_rcu(br_dev, htons(ETH_P_8021Q),
8832 old_pvid);
8833 rcu_read_unlock();
8834 if (upper_dev)
8835 err = mlxsw_sp_inetaddr_bridge_event(mlxsw_sp,
8836 upper_dev,
8837 new_pvid,
8838 NETDEV_UP, extack);
8839 }
8840
8841 out:
8842 mutex_unlock(&mlxsw_sp->router->lock);
8843 return err;
8844 }
8845
8846 static void
mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params * params,struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan)8847 mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params,
8848 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
8849 {
8850 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
8851
8852 params->vid = mlxsw_sp_port_vlan->vid;
8853 params->lag = mlxsw_sp_port->lagged;
8854 if (params->lag)
8855 params->lag_id = mlxsw_sp_port->lag_id;
8856 else
8857 params->system_port = mlxsw_sp_port->local_port;
8858 }
8859
8860 static struct mlxsw_sp_rif_subport *
mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif * rif)8861 mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif)
8862 {
8863 return container_of(rif, struct mlxsw_sp_rif_subport, common);
8864 }
8865
mlxsw_sp_rif_subport_port(const struct mlxsw_sp_rif * rif,u16 * port,bool * is_lag)8866 int mlxsw_sp_rif_subport_port(const struct mlxsw_sp_rif *rif,
8867 u16 *port, bool *is_lag)
8868 {
8869 struct mlxsw_sp_rif_subport *rif_subport;
8870
8871 if (WARN_ON(rif->ops->type != MLXSW_SP_RIF_TYPE_SUBPORT))
8872 return -EINVAL;
8873
8874 rif_subport = mlxsw_sp_rif_subport_rif(rif);
8875 *is_lag = rif_subport->lag;
8876 *port = *is_lag ? rif_subport->lag_id : rif_subport->system_port;
8877 return 0;
8878 }
8879
8880 static struct mlxsw_sp_rif *
mlxsw_sp_rif_subport_get(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_rif_params * params,struct netlink_ext_ack * extack)8881 mlxsw_sp_rif_subport_get(struct mlxsw_sp *mlxsw_sp,
8882 const struct mlxsw_sp_rif_params *params,
8883 struct netlink_ext_ack *extack)
8884 {
8885 struct mlxsw_sp_rif_subport *rif_subport;
8886 struct mlxsw_sp_rif *rif;
8887
8888 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, params->dev);
8889 if (!rif)
8890 return mlxsw_sp_rif_create(mlxsw_sp, params, extack);
8891
8892 rif_subport = mlxsw_sp_rif_subport_rif(rif);
8893 refcount_inc(&rif_subport->ref_count);
8894 return rif;
8895 }
8896
mlxsw_sp_rif_subport_put(struct mlxsw_sp_rif * rif)8897 static void mlxsw_sp_rif_subport_put(struct mlxsw_sp_rif *rif)
8898 {
8899 struct mlxsw_sp_rif_subport *rif_subport;
8900
8901 rif_subport = mlxsw_sp_rif_subport_rif(rif);
8902 if (!refcount_dec_and_test(&rif_subport->ref_count))
8903 return;
8904
8905 mlxsw_sp_rif_destroy(rif);
8906 }
8907
mlxsw_sp_rif_mac_profile_index_alloc(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif_mac_profile * profile,struct netlink_ext_ack * extack)8908 static int mlxsw_sp_rif_mac_profile_index_alloc(struct mlxsw_sp *mlxsw_sp,
8909 struct mlxsw_sp_rif_mac_profile *profile,
8910 struct netlink_ext_ack *extack)
8911 {
8912 u8 max_rif_mac_profiles = mlxsw_sp->router->max_rif_mac_profile;
8913 struct mlxsw_sp_router *router = mlxsw_sp->router;
8914 int id;
8915
8916 id = idr_alloc(&router->rif_mac_profiles_idr, profile, 0,
8917 max_rif_mac_profiles, GFP_KERNEL);
8918
8919 if (id >= 0) {
8920 profile->id = id;
8921 return 0;
8922 }
8923
8924 if (id == -ENOSPC)
8925 NL_SET_ERR_MSG_MOD(extack,
8926 "Exceeded number of supported router interface MAC profiles");
8927
8928 return id;
8929 }
8930
8931 static struct mlxsw_sp_rif_mac_profile *
mlxsw_sp_rif_mac_profile_index_free(struct mlxsw_sp * mlxsw_sp,u8 mac_profile)8932 mlxsw_sp_rif_mac_profile_index_free(struct mlxsw_sp *mlxsw_sp, u8 mac_profile)
8933 {
8934 struct mlxsw_sp_rif_mac_profile *profile;
8935
8936 profile = idr_remove(&mlxsw_sp->router->rif_mac_profiles_idr,
8937 mac_profile);
8938 WARN_ON(!profile);
8939 return profile;
8940 }
8941
8942 static struct mlxsw_sp_rif_mac_profile *
mlxsw_sp_rif_mac_profile_alloc(const char * mac)8943 mlxsw_sp_rif_mac_profile_alloc(const char *mac)
8944 {
8945 struct mlxsw_sp_rif_mac_profile *profile;
8946
8947 profile = kzalloc_obj(*profile);
8948 if (!profile)
8949 return NULL;
8950
8951 ether_addr_copy(profile->mac_prefix, mac);
8952 refcount_set(&profile->ref_count, 1);
8953 return profile;
8954 }
8955
8956 static struct mlxsw_sp_rif_mac_profile *
mlxsw_sp_rif_mac_profile_find(const struct mlxsw_sp * mlxsw_sp,const char * mac)8957 mlxsw_sp_rif_mac_profile_find(const struct mlxsw_sp *mlxsw_sp, const char *mac)
8958 {
8959 struct mlxsw_sp_router *router = mlxsw_sp->router;
8960 struct mlxsw_sp_rif_mac_profile *profile;
8961 int id;
8962
8963 idr_for_each_entry(&router->rif_mac_profiles_idr, profile, id) {
8964 if (ether_addr_equal_masked(profile->mac_prefix, mac,
8965 mlxsw_sp->mac_mask))
8966 return profile;
8967 }
8968
8969 return NULL;
8970 }
8971
mlxsw_sp_rif_mac_profiles_occ_get(void * priv)8972 static u64 mlxsw_sp_rif_mac_profiles_occ_get(void *priv)
8973 {
8974 const struct mlxsw_sp *mlxsw_sp = priv;
8975
8976 return atomic_read(&mlxsw_sp->router->rif_mac_profiles_count);
8977 }
8978
mlxsw_sp_rifs_occ_get(void * priv)8979 static u64 mlxsw_sp_rifs_occ_get(void *priv)
8980 {
8981 const struct mlxsw_sp *mlxsw_sp = priv;
8982
8983 return atomic_read(&mlxsw_sp->router->rifs_count);
8984 }
8985
8986 static struct mlxsw_sp_rif_mac_profile *
mlxsw_sp_rif_mac_profile_create(struct mlxsw_sp * mlxsw_sp,const char * mac,struct netlink_ext_ack * extack)8987 mlxsw_sp_rif_mac_profile_create(struct mlxsw_sp *mlxsw_sp, const char *mac,
8988 struct netlink_ext_ack *extack)
8989 {
8990 struct mlxsw_sp_rif_mac_profile *profile;
8991 int err;
8992
8993 profile = mlxsw_sp_rif_mac_profile_alloc(mac);
8994 if (!profile)
8995 return ERR_PTR(-ENOMEM);
8996
8997 err = mlxsw_sp_rif_mac_profile_index_alloc(mlxsw_sp, profile, extack);
8998 if (err)
8999 goto profile_index_alloc_err;
9000
9001 atomic_inc(&mlxsw_sp->router->rif_mac_profiles_count);
9002 return profile;
9003
9004 profile_index_alloc_err:
9005 kfree(profile);
9006 return ERR_PTR(err);
9007 }
9008
mlxsw_sp_rif_mac_profile_destroy(struct mlxsw_sp * mlxsw_sp,u8 mac_profile)9009 static void mlxsw_sp_rif_mac_profile_destroy(struct mlxsw_sp *mlxsw_sp,
9010 u8 mac_profile)
9011 {
9012 struct mlxsw_sp_rif_mac_profile *profile;
9013
9014 atomic_dec(&mlxsw_sp->router->rif_mac_profiles_count);
9015 profile = mlxsw_sp_rif_mac_profile_index_free(mlxsw_sp, mac_profile);
9016 kfree(profile);
9017 }
9018
mlxsw_sp_rif_mac_profile_get(struct mlxsw_sp * mlxsw_sp,const char * mac,u8 * p_mac_profile,struct netlink_ext_ack * extack)9019 static int mlxsw_sp_rif_mac_profile_get(struct mlxsw_sp *mlxsw_sp,
9020 const char *mac, u8 *p_mac_profile,
9021 struct netlink_ext_ack *extack)
9022 {
9023 struct mlxsw_sp_rif_mac_profile *profile;
9024
9025 profile = mlxsw_sp_rif_mac_profile_find(mlxsw_sp, mac);
9026 if (profile) {
9027 refcount_inc(&profile->ref_count);
9028 goto out;
9029 }
9030
9031 profile = mlxsw_sp_rif_mac_profile_create(mlxsw_sp, mac, extack);
9032 if (IS_ERR(profile))
9033 return PTR_ERR(profile);
9034
9035 out:
9036 *p_mac_profile = profile->id;
9037 return 0;
9038 }
9039
mlxsw_sp_rif_mac_profile_put(struct mlxsw_sp * mlxsw_sp,u8 mac_profile)9040 static void mlxsw_sp_rif_mac_profile_put(struct mlxsw_sp *mlxsw_sp,
9041 u8 mac_profile)
9042 {
9043 struct mlxsw_sp_rif_mac_profile *profile;
9044
9045 profile = idr_find(&mlxsw_sp->router->rif_mac_profiles_idr,
9046 mac_profile);
9047 if (WARN_ON(!profile))
9048 return;
9049
9050 if (!refcount_dec_and_test(&profile->ref_count))
9051 return;
9052
9053 mlxsw_sp_rif_mac_profile_destroy(mlxsw_sp, mac_profile);
9054 }
9055
mlxsw_sp_rif_mac_profile_is_shared(const struct mlxsw_sp_rif * rif)9056 static bool mlxsw_sp_rif_mac_profile_is_shared(const struct mlxsw_sp_rif *rif)
9057 {
9058 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
9059 struct mlxsw_sp_rif_mac_profile *profile;
9060
9061 profile = idr_find(&mlxsw_sp->router->rif_mac_profiles_idr,
9062 rif->mac_profile_id);
9063 if (WARN_ON(!profile))
9064 return false;
9065
9066 return refcount_read(&profile->ref_count) > 1;
9067 }
9068
mlxsw_sp_rif_mac_profile_edit(struct mlxsw_sp_rif * rif,const char * new_mac)9069 static int mlxsw_sp_rif_mac_profile_edit(struct mlxsw_sp_rif *rif,
9070 const char *new_mac)
9071 {
9072 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
9073 struct mlxsw_sp_rif_mac_profile *profile;
9074
9075 profile = idr_find(&mlxsw_sp->router->rif_mac_profiles_idr,
9076 rif->mac_profile_id);
9077 if (WARN_ON(!profile))
9078 return -EINVAL;
9079
9080 ether_addr_copy(profile->mac_prefix, new_mac);
9081 return 0;
9082 }
9083
9084 static int
mlxsw_sp_rif_mac_profile_replace(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif,const char * new_mac,struct netlink_ext_ack * extack)9085 mlxsw_sp_rif_mac_profile_replace(struct mlxsw_sp *mlxsw_sp,
9086 struct mlxsw_sp_rif *rif,
9087 const char *new_mac,
9088 struct netlink_ext_ack *extack)
9089 {
9090 u8 mac_profile;
9091 int err;
9092
9093 if (!mlxsw_sp_rif_mac_profile_is_shared(rif) &&
9094 !mlxsw_sp_rif_mac_profile_find(mlxsw_sp, new_mac))
9095 return mlxsw_sp_rif_mac_profile_edit(rif, new_mac);
9096
9097 err = mlxsw_sp_rif_mac_profile_get(mlxsw_sp, new_mac,
9098 &mac_profile, extack);
9099 if (err)
9100 return err;
9101
9102 mlxsw_sp_rif_mac_profile_put(mlxsw_sp, rif->mac_profile_id);
9103 rif->mac_profile_id = mac_profile;
9104 return 0;
9105 }
9106
9107 static int
__mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan,struct net_device * l3_dev,struct netlink_ext_ack * extack)9108 __mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
9109 struct net_device *l3_dev,
9110 struct netlink_ext_ack *extack)
9111 {
9112 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
9113 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
9114 struct mlxsw_sp_rif_params params;
9115 u16 vid = mlxsw_sp_port_vlan->vid;
9116 struct mlxsw_sp_rif *rif;
9117 struct mlxsw_sp_fid *fid;
9118 int err;
9119
9120 params = (struct mlxsw_sp_rif_params) {
9121 .dev = l3_dev,
9122 .vid = vid,
9123 };
9124
9125 mlxsw_sp_rif_subport_params_init(¶ms, mlxsw_sp_port_vlan);
9126 rif = mlxsw_sp_rif_subport_get(mlxsw_sp, ¶ms, extack);
9127 if (IS_ERR(rif))
9128 return PTR_ERR(rif);
9129
9130 /* FID was already created, just take a reference */
9131 fid = rif->ops->fid_get(rif, ¶ms, extack);
9132 err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
9133 if (err)
9134 goto err_fid_port_vid_map;
9135
9136 err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
9137 if (err)
9138 goto err_port_vid_learning_set;
9139
9140 err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid,
9141 BR_STATE_FORWARDING);
9142 if (err)
9143 goto err_port_vid_stp_set;
9144
9145 mlxsw_sp_port_vlan->fid = fid;
9146
9147 return 0;
9148
9149 err_port_vid_stp_set:
9150 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
9151 err_port_vid_learning_set:
9152 mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
9153 err_fid_port_vid_map:
9154 mlxsw_sp_fid_put(fid);
9155 mlxsw_sp_rif_subport_put(rif);
9156 return err;
9157 }
9158
9159 static void
__mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan)9160 __mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
9161 {
9162 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
9163 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
9164 struct mlxsw_sp_rif *rif = mlxsw_sp_fid_rif(fid);
9165 u16 vid = mlxsw_sp_port_vlan->vid;
9166
9167 if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_RFID))
9168 return;
9169
9170 mlxsw_sp_port_vlan->fid = NULL;
9171 mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING);
9172 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
9173 mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
9174 mlxsw_sp_fid_put(fid);
9175 mlxsw_sp_rif_subport_put(rif);
9176 }
9177
9178 static int
mlxsw_sp_port_vlan_router_join_existing(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan,struct net_device * l3_dev,struct netlink_ext_ack * extack)9179 mlxsw_sp_port_vlan_router_join_existing(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
9180 struct net_device *l3_dev,
9181 struct netlink_ext_ack *extack)
9182 {
9183 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port_vlan->mlxsw_sp_port->mlxsw_sp;
9184
9185 lockdep_assert_held(&mlxsw_sp->router->lock);
9186
9187 if (!mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev))
9188 return 0;
9189
9190 return __mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan, l3_dev,
9191 extack);
9192 }
9193
9194 void
mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan)9195 mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
9196 {
9197 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port_vlan->mlxsw_sp_port->mlxsw_sp;
9198
9199 mutex_lock(&mlxsw_sp->router->lock);
9200 __mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
9201 mutex_unlock(&mlxsw_sp->router->lock);
9202 }
9203
mlxsw_sp_inetaddr_port_vlan_event(struct net_device * l3_dev,struct net_device * port_dev,unsigned long event,u16 vid,struct netlink_ext_ack * extack)9204 static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev,
9205 struct net_device *port_dev,
9206 unsigned long event, u16 vid,
9207 struct netlink_ext_ack *extack)
9208 {
9209 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(port_dev);
9210 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
9211
9212 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
9213 if (WARN_ON(!mlxsw_sp_port_vlan))
9214 return -EINVAL;
9215
9216 switch (event) {
9217 case NETDEV_UP:
9218 return __mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan,
9219 l3_dev, extack);
9220 case NETDEV_DOWN:
9221 __mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
9222 break;
9223 }
9224
9225 return 0;
9226 }
9227
mlxsw_sp_inetaddr_port_event(struct net_device * port_dev,unsigned long event,bool nomaster,struct netlink_ext_ack * extack)9228 static int mlxsw_sp_inetaddr_port_event(struct net_device *port_dev,
9229 unsigned long event, bool nomaster,
9230 struct netlink_ext_ack *extack)
9231 {
9232 if (!nomaster && (netif_is_any_bridge_port(port_dev) ||
9233 netif_is_lag_port(port_dev)))
9234 return 0;
9235
9236 return mlxsw_sp_inetaddr_port_vlan_event(port_dev, port_dev, event,
9237 MLXSW_SP_DEFAULT_VID, extack);
9238 }
9239
__mlxsw_sp_inetaddr_lag_event(struct net_device * l3_dev,struct net_device * lag_dev,unsigned long event,u16 vid,struct netlink_ext_ack * extack)9240 static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev,
9241 struct net_device *lag_dev,
9242 unsigned long event, u16 vid,
9243 struct netlink_ext_ack *extack)
9244 {
9245 struct net_device *port_dev;
9246 struct list_head *iter;
9247 int err;
9248
9249 netdev_for_each_lower_dev(lag_dev, port_dev, iter) {
9250 if (mlxsw_sp_port_dev_check(port_dev)) {
9251 err = mlxsw_sp_inetaddr_port_vlan_event(l3_dev,
9252 port_dev,
9253 event, vid,
9254 extack);
9255 if (err)
9256 return err;
9257 }
9258 }
9259
9260 return 0;
9261 }
9262
mlxsw_sp_inetaddr_lag_event(struct net_device * lag_dev,unsigned long event,bool nomaster,struct netlink_ext_ack * extack)9263 static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
9264 unsigned long event, bool nomaster,
9265 struct netlink_ext_ack *extack)
9266 {
9267 if (!nomaster && netif_is_bridge_port(lag_dev))
9268 return 0;
9269
9270 return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event,
9271 MLXSW_SP_DEFAULT_VID, extack);
9272 }
9273
mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp * mlxsw_sp,struct net_device * l3_dev,int lower_pvid,unsigned long event,struct netlink_ext_ack * extack)9274 static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
9275 struct net_device *l3_dev,
9276 int lower_pvid,
9277 unsigned long event,
9278 struct netlink_ext_ack *extack)
9279 {
9280 struct mlxsw_sp_rif_params params = {
9281 .dev = l3_dev,
9282 };
9283 struct mlxsw_sp_rif *rif;
9284 int err;
9285
9286 switch (event) {
9287 case NETDEV_UP:
9288 if (netif_is_bridge_master(l3_dev) && br_vlan_enabled(l3_dev)) {
9289 u16 proto;
9290
9291 br_vlan_get_proto(l3_dev, &proto);
9292 if (proto == ETH_P_8021AD) {
9293 NL_SET_ERR_MSG_MOD(extack, "Adding an IP address to 802.1ad bridge is not supported");
9294 return -EOPNOTSUPP;
9295 }
9296 err = br_vlan_get_pvid(l3_dev, ¶ms.vid);
9297 if (err)
9298 return err;
9299 if (!params.vid)
9300 return 0;
9301 } else if (is_vlan_dev(l3_dev)) {
9302 params.vid = vlan_dev_vlan_id(l3_dev);
9303
9304 /* If the VID matches PVID of the bridge below, the
9305 * bridge owns the RIF for this VLAN. Don't do anything.
9306 */
9307 if ((int)params.vid == lower_pvid)
9308 return 0;
9309 }
9310
9311 rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms, extack);
9312 if (IS_ERR(rif))
9313 return PTR_ERR(rif);
9314 break;
9315 case NETDEV_DOWN:
9316 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
9317 mlxsw_sp_rif_destroy(rif);
9318 break;
9319 }
9320
9321 return 0;
9322 }
9323
mlxsw_sp_inetaddr_vlan_event(struct mlxsw_sp * mlxsw_sp,struct net_device * vlan_dev,unsigned long event,bool nomaster,struct netlink_ext_ack * extack)9324 static int mlxsw_sp_inetaddr_vlan_event(struct mlxsw_sp *mlxsw_sp,
9325 struct net_device *vlan_dev,
9326 unsigned long event, bool nomaster,
9327 struct netlink_ext_ack *extack)
9328 {
9329 struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
9330 u16 vid = vlan_dev_vlan_id(vlan_dev);
9331 u16 lower_pvid;
9332 int err;
9333
9334 if (!nomaster && netif_is_bridge_port(vlan_dev))
9335 return 0;
9336
9337 if (mlxsw_sp_port_dev_check(real_dev)) {
9338 return mlxsw_sp_inetaddr_port_vlan_event(vlan_dev, real_dev,
9339 event, vid, extack);
9340 } else if (netif_is_lag_master(real_dev)) {
9341 return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
9342 vid, extack);
9343 } else if (netif_is_bridge_master(real_dev) &&
9344 br_vlan_enabled(real_dev)) {
9345 err = br_vlan_get_pvid(real_dev, &lower_pvid);
9346 if (err)
9347 return err;
9348 return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, vlan_dev,
9349 lower_pvid, event,
9350 extack);
9351 }
9352
9353 return 0;
9354 }
9355
mlxsw_sp_rif_macvlan_is_vrrp4(const u8 * mac)9356 static bool mlxsw_sp_rif_macvlan_is_vrrp4(const u8 *mac)
9357 {
9358 u8 vrrp4[ETH_ALEN] = { 0x00, 0x00, 0x5e, 0x00, 0x01, 0x00 };
9359 u8 mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
9360
9361 return ether_addr_equal_masked(mac, vrrp4, mask);
9362 }
9363
mlxsw_sp_rif_macvlan_is_vrrp6(const u8 * mac)9364 static bool mlxsw_sp_rif_macvlan_is_vrrp6(const u8 *mac)
9365 {
9366 u8 vrrp6[ETH_ALEN] = { 0x00, 0x00, 0x5e, 0x00, 0x02, 0x00 };
9367 u8 mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
9368
9369 return ether_addr_equal_masked(mac, vrrp6, mask);
9370 }
9371
mlxsw_sp_rif_vrrp_op(struct mlxsw_sp * mlxsw_sp,u16 rif_index,const u8 * mac,bool adding)9372 static int mlxsw_sp_rif_vrrp_op(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
9373 const u8 *mac, bool adding)
9374 {
9375 char ritr_pl[MLXSW_REG_RITR_LEN];
9376 u8 vrrp_id = adding ? mac[5] : 0;
9377 int err;
9378
9379 if (!mlxsw_sp_rif_macvlan_is_vrrp4(mac) &&
9380 !mlxsw_sp_rif_macvlan_is_vrrp6(mac))
9381 return 0;
9382
9383 mlxsw_reg_ritr_rif_pack(ritr_pl, rif_index);
9384 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
9385 if (err)
9386 return err;
9387
9388 if (mlxsw_sp_rif_macvlan_is_vrrp4(mac))
9389 mlxsw_reg_ritr_if_vrrp_id_ipv4_set(ritr_pl, vrrp_id);
9390 else
9391 mlxsw_reg_ritr_if_vrrp_id_ipv6_set(ritr_pl, vrrp_id);
9392
9393 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
9394 }
9395
mlxsw_sp_rif_macvlan_add(struct mlxsw_sp * mlxsw_sp,const struct net_device * macvlan_dev,struct netlink_ext_ack * extack)9396 static int mlxsw_sp_rif_macvlan_add(struct mlxsw_sp *mlxsw_sp,
9397 const struct net_device *macvlan_dev,
9398 struct netlink_ext_ack *extack)
9399 {
9400 struct macvlan_dev *vlan = netdev_priv(macvlan_dev);
9401 struct mlxsw_sp_rif *rif;
9402 int err;
9403
9404 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan->lowerdev);
9405 if (!rif)
9406 return 0;
9407
9408 err = mlxsw_sp_rif_fdb_op(mlxsw_sp, macvlan_dev->dev_addr,
9409 mlxsw_sp_fid_index(rif->fid), true);
9410 if (err)
9411 return err;
9412
9413 err = mlxsw_sp_rif_vrrp_op(mlxsw_sp, rif->rif_index,
9414 macvlan_dev->dev_addr, true);
9415 if (err)
9416 goto err_rif_vrrp_add;
9417
9418 /* Make sure the bridge driver does not have this MAC pointing at
9419 * some other port.
9420 */
9421 if (rif->ops->fdb_del)
9422 rif->ops->fdb_del(rif, macvlan_dev->dev_addr);
9423
9424 return 0;
9425
9426 err_rif_vrrp_add:
9427 mlxsw_sp_rif_fdb_op(mlxsw_sp, macvlan_dev->dev_addr,
9428 mlxsw_sp_fid_index(rif->fid), false);
9429 return err;
9430 }
9431
__mlxsw_sp_rif_macvlan_del(struct mlxsw_sp * mlxsw_sp,const struct net_device * macvlan_dev)9432 static void __mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp,
9433 const struct net_device *macvlan_dev)
9434 {
9435 struct macvlan_dev *vlan = netdev_priv(macvlan_dev);
9436 struct mlxsw_sp_rif *rif;
9437
9438 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan->lowerdev);
9439 /* If we do not have a RIF, then we already took care of
9440 * removing the macvlan's MAC during RIF deletion.
9441 */
9442 if (!rif)
9443 return;
9444 mlxsw_sp_rif_vrrp_op(mlxsw_sp, rif->rif_index, macvlan_dev->dev_addr,
9445 false);
9446 mlxsw_sp_rif_fdb_op(mlxsw_sp, macvlan_dev->dev_addr,
9447 mlxsw_sp_fid_index(rif->fid), false);
9448 }
9449
mlxsw_sp_rif_macvlan_del(struct mlxsw_sp * mlxsw_sp,const struct net_device * macvlan_dev)9450 void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp,
9451 const struct net_device *macvlan_dev)
9452 {
9453 mutex_lock(&mlxsw_sp->router->lock);
9454 __mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev);
9455 mutex_unlock(&mlxsw_sp->router->lock);
9456 }
9457
mlxsw_sp_inetaddr_macvlan_event(struct mlxsw_sp * mlxsw_sp,struct net_device * macvlan_dev,unsigned long event,struct netlink_ext_ack * extack)9458 static int mlxsw_sp_inetaddr_macvlan_event(struct mlxsw_sp *mlxsw_sp,
9459 struct net_device *macvlan_dev,
9460 unsigned long event,
9461 struct netlink_ext_ack *extack)
9462 {
9463 switch (event) {
9464 case NETDEV_UP:
9465 return mlxsw_sp_rif_macvlan_add(mlxsw_sp, macvlan_dev, extack);
9466 case NETDEV_DOWN:
9467 __mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev);
9468 break;
9469 }
9470
9471 return 0;
9472 }
9473
__mlxsw_sp_inetaddr_event(struct mlxsw_sp * mlxsw_sp,struct net_device * dev,unsigned long event,bool nomaster,struct netlink_ext_ack * extack)9474 static int __mlxsw_sp_inetaddr_event(struct mlxsw_sp *mlxsw_sp,
9475 struct net_device *dev,
9476 unsigned long event, bool nomaster,
9477 struct netlink_ext_ack *extack)
9478 {
9479 if (mlxsw_sp_port_dev_check(dev))
9480 return mlxsw_sp_inetaddr_port_event(dev, event, nomaster,
9481 extack);
9482 else if (netif_is_lag_master(dev))
9483 return mlxsw_sp_inetaddr_lag_event(dev, event, nomaster,
9484 extack);
9485 else if (netif_is_bridge_master(dev))
9486 return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, dev, -1, event,
9487 extack);
9488 else if (is_vlan_dev(dev))
9489 return mlxsw_sp_inetaddr_vlan_event(mlxsw_sp, dev, event,
9490 nomaster, extack);
9491 else if (netif_is_macvlan(dev))
9492 return mlxsw_sp_inetaddr_macvlan_event(mlxsw_sp, dev, event,
9493 extack);
9494 else
9495 return 0;
9496 }
9497
mlxsw_sp_inetaddr_event(struct notifier_block * nb,unsigned long event,void * ptr)9498 static int mlxsw_sp_inetaddr_event(struct notifier_block *nb,
9499 unsigned long event, void *ptr)
9500 {
9501 struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
9502 struct net_device *dev = ifa->ifa_dev->dev;
9503 struct mlxsw_sp_router *router;
9504 struct mlxsw_sp_rif *rif;
9505 int err = 0;
9506
9507 /* NETDEV_UP event is handled by mlxsw_sp_inetaddr_valid_event */
9508 if (event == NETDEV_UP)
9509 return NOTIFY_DONE;
9510
9511 router = container_of(nb, struct mlxsw_sp_router, inetaddr_nb);
9512 mutex_lock(&router->lock);
9513 rif = mlxsw_sp_rif_find_by_dev(router->mlxsw_sp, dev);
9514 if (!mlxsw_sp_rif_should_config(rif, dev, event))
9515 goto out;
9516
9517 err = __mlxsw_sp_inetaddr_event(router->mlxsw_sp, dev, event, false,
9518 NULL);
9519 out:
9520 mutex_unlock(&router->lock);
9521 return notifier_from_errno(err);
9522 }
9523
mlxsw_sp_inetaddr_valid_event(struct notifier_block * unused,unsigned long event,void * ptr)9524 static int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused,
9525 unsigned long event, void *ptr)
9526 {
9527 struct in_validator_info *ivi = (struct in_validator_info *) ptr;
9528 struct net_device *dev = ivi->ivi_dev->dev;
9529 struct mlxsw_sp *mlxsw_sp;
9530 struct mlxsw_sp_rif *rif;
9531 int err = 0;
9532
9533 mlxsw_sp = mlxsw_sp_lower_get(dev);
9534 if (!mlxsw_sp)
9535 return NOTIFY_DONE;
9536
9537 mutex_lock(&mlxsw_sp->router->lock);
9538 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
9539 if (!mlxsw_sp_rif_should_config(rif, dev, event))
9540 goto out;
9541
9542 err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, false,
9543 ivi->extack);
9544 out:
9545 mutex_unlock(&mlxsw_sp->router->lock);
9546 return notifier_from_errno(err);
9547 }
9548
9549 struct mlxsw_sp_inet6addr_event_work {
9550 struct work_struct work;
9551 struct mlxsw_sp *mlxsw_sp;
9552 struct net_device *dev;
9553 netdevice_tracker dev_tracker;
9554 unsigned long event;
9555 };
9556
mlxsw_sp_inet6addr_event_work(struct work_struct * work)9557 static void mlxsw_sp_inet6addr_event_work(struct work_struct *work)
9558 {
9559 struct mlxsw_sp_inet6addr_event_work *inet6addr_work =
9560 container_of(work, struct mlxsw_sp_inet6addr_event_work, work);
9561 struct mlxsw_sp *mlxsw_sp = inet6addr_work->mlxsw_sp;
9562 struct net_device *dev = inet6addr_work->dev;
9563 unsigned long event = inet6addr_work->event;
9564 struct mlxsw_sp_rif *rif;
9565
9566 rtnl_lock();
9567 mutex_lock(&mlxsw_sp->router->lock);
9568
9569 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
9570 if (!mlxsw_sp_rif_should_config(rif, dev, event))
9571 goto out;
9572
9573 __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, false, NULL);
9574 out:
9575 mutex_unlock(&mlxsw_sp->router->lock);
9576 rtnl_unlock();
9577 netdev_put(dev, &inet6addr_work->dev_tracker);
9578 kfree(inet6addr_work);
9579 }
9580
9581 /* Called with rcu_read_lock() */
mlxsw_sp_inet6addr_event(struct notifier_block * nb,unsigned long event,void * ptr)9582 static int mlxsw_sp_inet6addr_event(struct notifier_block *nb,
9583 unsigned long event, void *ptr)
9584 {
9585 struct inet6_ifaddr *if6 = (struct inet6_ifaddr *) ptr;
9586 struct mlxsw_sp_inet6addr_event_work *inet6addr_work;
9587 struct net_device *dev = if6->idev->dev;
9588 struct mlxsw_sp_router *router;
9589
9590 /* NETDEV_UP event is handled by mlxsw_sp_inet6addr_valid_event */
9591 if (event == NETDEV_UP)
9592 return NOTIFY_DONE;
9593
9594 inet6addr_work = kzalloc_obj(*inet6addr_work, GFP_ATOMIC);
9595 if (!inet6addr_work)
9596 return NOTIFY_BAD;
9597
9598 router = container_of(nb, struct mlxsw_sp_router, inet6addr_nb);
9599 INIT_WORK(&inet6addr_work->work, mlxsw_sp_inet6addr_event_work);
9600 inet6addr_work->mlxsw_sp = router->mlxsw_sp;
9601 inet6addr_work->dev = dev;
9602 inet6addr_work->event = event;
9603 netdev_hold(dev, &inet6addr_work->dev_tracker, GFP_ATOMIC);
9604 mlxsw_core_schedule_work(&inet6addr_work->work);
9605
9606 return NOTIFY_DONE;
9607 }
9608
mlxsw_sp_inet6addr_valid_event(struct notifier_block * unused,unsigned long event,void * ptr)9609 static int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused,
9610 unsigned long event, void *ptr)
9611 {
9612 struct in6_validator_info *i6vi = (struct in6_validator_info *) ptr;
9613 struct net_device *dev = i6vi->i6vi_dev->dev;
9614 struct mlxsw_sp *mlxsw_sp;
9615 struct mlxsw_sp_rif *rif;
9616 int err = 0;
9617
9618 mlxsw_sp = mlxsw_sp_lower_get(dev);
9619 if (!mlxsw_sp)
9620 return NOTIFY_DONE;
9621
9622 mutex_lock(&mlxsw_sp->router->lock);
9623 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
9624 if (!mlxsw_sp_rif_should_config(rif, dev, event))
9625 goto out;
9626
9627 err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, false,
9628 i6vi->extack);
9629 out:
9630 mutex_unlock(&mlxsw_sp->router->lock);
9631 return notifier_from_errno(err);
9632 }
9633
mlxsw_sp_rif_edit(struct mlxsw_sp * mlxsw_sp,u16 rif_index,const char * mac,int mtu,u8 mac_profile)9634 static int mlxsw_sp_rif_edit(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
9635 const char *mac, int mtu, u8 mac_profile)
9636 {
9637 char ritr_pl[MLXSW_REG_RITR_LEN];
9638 int err;
9639
9640 mlxsw_reg_ritr_rif_pack(ritr_pl, rif_index);
9641 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
9642 if (err)
9643 return err;
9644
9645 mlxsw_reg_ritr_mtu_set(ritr_pl, mtu);
9646 mlxsw_reg_ritr_if_mac_memcpy_to(ritr_pl, mac);
9647 mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, mac_profile);
9648 mlxsw_reg_ritr_op_set(ritr_pl, MLXSW_REG_RITR_RIF_CREATE);
9649 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
9650 }
9651
9652 static int
mlxsw_sp_router_port_change_event(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_rif * rif,struct netlink_ext_ack * extack)9653 mlxsw_sp_router_port_change_event(struct mlxsw_sp *mlxsw_sp,
9654 struct mlxsw_sp_rif *rif,
9655 struct netlink_ext_ack *extack)
9656 {
9657 struct net_device *dev = mlxsw_sp_rif_dev(rif);
9658 u8 old_mac_profile;
9659 u16 fid_index;
9660 int err;
9661
9662 fid_index = mlxsw_sp_fid_index(rif->fid);
9663
9664 err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, false);
9665 if (err)
9666 return err;
9667
9668 old_mac_profile = rif->mac_profile_id;
9669 err = mlxsw_sp_rif_mac_profile_replace(mlxsw_sp, rif, dev->dev_addr,
9670 extack);
9671 if (err)
9672 goto err_rif_mac_profile_replace;
9673
9674 err = mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, dev->dev_addr,
9675 dev->mtu, rif->mac_profile_id);
9676 if (err)
9677 goto err_rif_edit;
9678
9679 err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, fid_index, true);
9680 if (err)
9681 goto err_rif_fdb_op;
9682
9683 if (rif->mtu != dev->mtu) {
9684 struct mlxsw_sp_vr *vr;
9685 int i;
9686
9687 /* The RIF is relevant only to its mr_table instance, as unlike
9688 * unicast routing, in multicast routing a RIF cannot be shared
9689 * between several multicast routing tables.
9690 */
9691 vr = &mlxsw_sp->router->vrs[rif->vr_id];
9692 for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++)
9693 mlxsw_sp_mr_rif_mtu_update(vr->mr_table[i],
9694 rif, dev->mtu);
9695 }
9696
9697 ether_addr_copy(rif->addr, dev->dev_addr);
9698 rif->mtu = dev->mtu;
9699
9700 netdev_dbg(dev, "Updated RIF=%d\n", rif->rif_index);
9701
9702 return 0;
9703
9704 err_rif_fdb_op:
9705 mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu,
9706 old_mac_profile);
9707 err_rif_edit:
9708 mlxsw_sp_rif_mac_profile_replace(mlxsw_sp, rif, rif->addr, extack);
9709 err_rif_mac_profile_replace:
9710 mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, true);
9711 return err;
9712 }
9713
mlxsw_sp_router_port_pre_changeaddr_event(struct mlxsw_sp_rif * rif,struct netdev_notifier_pre_changeaddr_info * info)9714 static int mlxsw_sp_router_port_pre_changeaddr_event(struct mlxsw_sp_rif *rif,
9715 struct netdev_notifier_pre_changeaddr_info *info)
9716 {
9717 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
9718 struct mlxsw_sp_rif_mac_profile *profile;
9719 struct netlink_ext_ack *extack;
9720 u8 max_rif_mac_profiles;
9721 u64 occ;
9722
9723 extack = netdev_notifier_info_to_extack(&info->info);
9724
9725 profile = mlxsw_sp_rif_mac_profile_find(mlxsw_sp, info->dev_addr);
9726 if (profile)
9727 return 0;
9728
9729 max_rif_mac_profiles = mlxsw_sp->router->max_rif_mac_profile;
9730 occ = mlxsw_sp_rif_mac_profiles_occ_get(mlxsw_sp);
9731 if (occ < max_rif_mac_profiles)
9732 return 0;
9733
9734 if (!mlxsw_sp_rif_mac_profile_is_shared(rif))
9735 return 0;
9736
9737 NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported router interface MAC profiles");
9738 return -ENOBUFS;
9739 }
9740
mlxsw_sp_router_netdevice_interesting(struct mlxsw_sp * mlxsw_sp,struct net_device * dev)9741 static bool mlxsw_sp_router_netdevice_interesting(struct mlxsw_sp *mlxsw_sp,
9742 struct net_device *dev)
9743 {
9744 struct vlan_dev_priv *vlan;
9745
9746 if (netif_is_lag_master(dev) ||
9747 netif_is_bridge_master(dev) ||
9748 mlxsw_sp_port_dev_check(dev) ||
9749 mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev) ||
9750 netif_is_l3_master(dev))
9751 return true;
9752
9753 if (!is_vlan_dev(dev))
9754 return false;
9755
9756 vlan = vlan_dev_priv(dev);
9757 return netif_is_lag_master(vlan->real_dev) ||
9758 netif_is_bridge_master(vlan->real_dev) ||
9759 mlxsw_sp_port_dev_check(vlan->real_dev);
9760 }
9761
9762 static struct mlxsw_sp_crif *
mlxsw_sp_crif_register(struct mlxsw_sp_router * router,struct net_device * dev)9763 mlxsw_sp_crif_register(struct mlxsw_sp_router *router, struct net_device *dev)
9764 {
9765 struct mlxsw_sp_crif *crif;
9766 int err;
9767
9768 if (WARN_ON(mlxsw_sp_crif_lookup(router, dev)))
9769 return NULL;
9770
9771 crif = mlxsw_sp_crif_alloc(dev);
9772 if (!crif)
9773 return ERR_PTR(-ENOMEM);
9774
9775 err = mlxsw_sp_crif_insert(router, crif);
9776 if (err)
9777 goto err_netdev_insert;
9778
9779 return crif;
9780
9781 err_netdev_insert:
9782 mlxsw_sp_crif_free(crif);
9783 return ERR_PTR(err);
9784 }
9785
mlxsw_sp_crif_unregister(struct mlxsw_sp_router * router,struct mlxsw_sp_crif * crif)9786 static void mlxsw_sp_crif_unregister(struct mlxsw_sp_router *router,
9787 struct mlxsw_sp_crif *crif)
9788 {
9789 struct mlxsw_sp_nexthop *nh, *tmp;
9790
9791 mlxsw_sp_crif_remove(router, crif);
9792
9793 list_for_each_entry_safe(nh, tmp, &crif->nexthop_list, crif_list_node)
9794 mlxsw_sp_nexthop_type_fini(router->mlxsw_sp, nh);
9795
9796 if (crif->rif)
9797 crif->can_destroy = true;
9798 else
9799 mlxsw_sp_crif_free(crif);
9800 }
9801
mlxsw_sp_netdevice_register(struct mlxsw_sp_router * router,struct net_device * dev)9802 static int mlxsw_sp_netdevice_register(struct mlxsw_sp_router *router,
9803 struct net_device *dev)
9804 {
9805 struct mlxsw_sp_crif *crif;
9806
9807 if (!mlxsw_sp_router_netdevice_interesting(router->mlxsw_sp, dev))
9808 return 0;
9809
9810 crif = mlxsw_sp_crif_register(router, dev);
9811 return PTR_ERR_OR_ZERO(crif);
9812 }
9813
mlxsw_sp_netdevice_unregister(struct mlxsw_sp_router * router,struct net_device * dev)9814 static void mlxsw_sp_netdevice_unregister(struct mlxsw_sp_router *router,
9815 struct net_device *dev)
9816 {
9817 struct mlxsw_sp_crif *crif;
9818
9819 if (!mlxsw_sp_router_netdevice_interesting(router->mlxsw_sp, dev))
9820 return;
9821
9822 /* netdev_run_todo(), by way of netdev_wait_allrefs_any(), rebroadcasts
9823 * the NETDEV_UNREGISTER message, so we can get here twice. If that's
9824 * what happened, the netdevice state is NETREG_UNREGISTERED. In that
9825 * case, we expect to have collected the CRIF already, and warn if it
9826 * still exists. Otherwise we expect the CRIF to exist.
9827 */
9828 crif = mlxsw_sp_crif_lookup(router, dev);
9829 if (dev->reg_state == NETREG_UNREGISTERED) {
9830 if (!WARN_ON(crif))
9831 return;
9832 }
9833 if (WARN_ON(!crif))
9834 return;
9835
9836 mlxsw_sp_crif_unregister(router, crif);
9837 }
9838
mlxsw_sp_is_offload_xstats_event(unsigned long event)9839 static bool mlxsw_sp_is_offload_xstats_event(unsigned long event)
9840 {
9841 switch (event) {
9842 case NETDEV_OFFLOAD_XSTATS_ENABLE:
9843 case NETDEV_OFFLOAD_XSTATS_DISABLE:
9844 case NETDEV_OFFLOAD_XSTATS_REPORT_USED:
9845 case NETDEV_OFFLOAD_XSTATS_REPORT_DELTA:
9846 return true;
9847 }
9848
9849 return false;
9850 }
9851
9852 static int
mlxsw_sp_router_port_offload_xstats_cmd(struct mlxsw_sp_rif * rif,unsigned long event,struct netdev_notifier_offload_xstats_info * info)9853 mlxsw_sp_router_port_offload_xstats_cmd(struct mlxsw_sp_rif *rif,
9854 unsigned long event,
9855 struct netdev_notifier_offload_xstats_info *info)
9856 {
9857 switch (info->type) {
9858 case NETDEV_OFFLOAD_XSTATS_TYPE_L3:
9859 break;
9860 default:
9861 return 0;
9862 }
9863
9864 switch (event) {
9865 case NETDEV_OFFLOAD_XSTATS_ENABLE:
9866 return mlxsw_sp_router_port_l3_stats_enable(rif);
9867 case NETDEV_OFFLOAD_XSTATS_DISABLE:
9868 mlxsw_sp_router_port_l3_stats_disable(rif);
9869 return 0;
9870 case NETDEV_OFFLOAD_XSTATS_REPORT_USED:
9871 mlxsw_sp_router_port_l3_stats_report_used(rif, info);
9872 return 0;
9873 case NETDEV_OFFLOAD_XSTATS_REPORT_DELTA:
9874 return mlxsw_sp_router_port_l3_stats_report_delta(rif, info);
9875 }
9876
9877 WARN_ON_ONCE(1);
9878 return 0;
9879 }
9880
9881 static int
mlxsw_sp_netdevice_offload_xstats_cmd(struct mlxsw_sp * mlxsw_sp,struct net_device * dev,unsigned long event,struct netdev_notifier_offload_xstats_info * info)9882 mlxsw_sp_netdevice_offload_xstats_cmd(struct mlxsw_sp *mlxsw_sp,
9883 struct net_device *dev,
9884 unsigned long event,
9885 struct netdev_notifier_offload_xstats_info *info)
9886 {
9887 struct mlxsw_sp_rif *rif;
9888
9889 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
9890 if (!rif)
9891 return 0;
9892
9893 return mlxsw_sp_router_port_offload_xstats_cmd(rif, event, info);
9894 }
9895
mlxsw_sp_is_router_event(unsigned long event)9896 static bool mlxsw_sp_is_router_event(unsigned long event)
9897 {
9898 switch (event) {
9899 case NETDEV_PRE_CHANGEADDR:
9900 case NETDEV_CHANGEADDR:
9901 case NETDEV_CHANGEMTU:
9902 return true;
9903 default:
9904 return false;
9905 }
9906 }
9907
mlxsw_sp_netdevice_router_port_event(struct net_device * dev,unsigned long event,void * ptr)9908 static int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
9909 unsigned long event, void *ptr)
9910 {
9911 struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
9912 struct mlxsw_sp *mlxsw_sp;
9913 struct mlxsw_sp_rif *rif;
9914
9915 mlxsw_sp = mlxsw_sp_lower_get(dev);
9916 if (!mlxsw_sp)
9917 return 0;
9918
9919 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
9920 if (!rif)
9921 return 0;
9922
9923 switch (event) {
9924 case NETDEV_CHANGEMTU:
9925 case NETDEV_CHANGEADDR:
9926 return mlxsw_sp_router_port_change_event(mlxsw_sp, rif, extack);
9927 case NETDEV_PRE_CHANGEADDR:
9928 return mlxsw_sp_router_port_pre_changeaddr_event(rif, ptr);
9929 default:
9930 WARN_ON_ONCE(1);
9931 break;
9932 }
9933
9934 return 0;
9935 }
9936
mlxsw_sp_port_vrf_join(struct mlxsw_sp * mlxsw_sp,struct net_device * l3_dev,struct netlink_ext_ack * extack)9937 static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp,
9938 struct net_device *l3_dev,
9939 struct netlink_ext_ack *extack)
9940 {
9941 struct mlxsw_sp_rif *rif;
9942
9943 /* If netdev is already associated with a RIF, then we need to
9944 * destroy it and create a new one with the new virtual router ID.
9945 */
9946 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
9947 if (rif)
9948 __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN, false,
9949 extack);
9950
9951 return __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_UP, false,
9952 extack);
9953 }
9954
mlxsw_sp_port_vrf_leave(struct mlxsw_sp * mlxsw_sp,struct net_device * l3_dev)9955 static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp,
9956 struct net_device *l3_dev)
9957 {
9958 struct mlxsw_sp_rif *rif;
9959
9960 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
9961 if (!rif)
9962 return;
9963 __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN, false, NULL);
9964 }
9965
mlxsw_sp_is_vrf_event(unsigned long event,void * ptr)9966 static bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr)
9967 {
9968 struct netdev_notifier_changeupper_info *info = ptr;
9969
9970 if (event != NETDEV_PRECHANGEUPPER && event != NETDEV_CHANGEUPPER)
9971 return false;
9972 return netif_is_l3_master(info->upper_dev);
9973 }
9974
9975 static int
mlxsw_sp_netdevice_vrf_event(struct net_device * l3_dev,unsigned long event,struct netdev_notifier_changeupper_info * info)9976 mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
9977 struct netdev_notifier_changeupper_info *info)
9978 {
9979 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
9980 int err = 0;
9981
9982 /* We do not create a RIF for a macvlan, but only use it to
9983 * direct more MAC addresses to the router.
9984 */
9985 if (!mlxsw_sp || netif_is_macvlan(l3_dev))
9986 return 0;
9987
9988 switch (event) {
9989 case NETDEV_PRECHANGEUPPER:
9990 break;
9991 case NETDEV_CHANGEUPPER:
9992 if (info->linking) {
9993 struct netlink_ext_ack *extack;
9994
9995 extack = netdev_notifier_info_to_extack(&info->info);
9996 err = mlxsw_sp_port_vrf_join(mlxsw_sp, l3_dev, extack);
9997 } else {
9998 mlxsw_sp_port_vrf_leave(mlxsw_sp, l3_dev);
9999 }
10000 break;
10001 }
10002
10003 return err;
10004 }
10005
10006 struct mlxsw_sp_router_replay_inetaddr_up {
10007 struct mlxsw_sp *mlxsw_sp;
10008 struct netlink_ext_ack *extack;
10009 unsigned int done;
10010 bool deslavement;
10011 };
10012
mlxsw_sp_router_replay_inetaddr_up(struct net_device * dev,struct netdev_nested_priv * priv)10013 static int mlxsw_sp_router_replay_inetaddr_up(struct net_device *dev,
10014 struct netdev_nested_priv *priv)
10015 {
10016 struct mlxsw_sp_router_replay_inetaddr_up *ctx = priv->data;
10017 bool nomaster = ctx->deslavement;
10018 struct mlxsw_sp_crif *crif;
10019 int err;
10020
10021 if (mlxsw_sp_dev_addr_list_empty(dev))
10022 return 0;
10023
10024 crif = mlxsw_sp_crif_lookup(ctx->mlxsw_sp->router, dev);
10025 if (!crif || crif->rif)
10026 return 0;
10027
10028 if (!mlxsw_sp_rif_should_config(crif->rif, dev, NETDEV_UP))
10029 return 0;
10030
10031 err = __mlxsw_sp_inetaddr_event(ctx->mlxsw_sp, dev, NETDEV_UP,
10032 nomaster, ctx->extack);
10033 if (err)
10034 return err;
10035
10036 ctx->done++;
10037 return 0;
10038 }
10039
mlxsw_sp_router_unreplay_inetaddr_up(struct net_device * dev,struct netdev_nested_priv * priv)10040 static int mlxsw_sp_router_unreplay_inetaddr_up(struct net_device *dev,
10041 struct netdev_nested_priv *priv)
10042 {
10043 struct mlxsw_sp_router_replay_inetaddr_up *ctx = priv->data;
10044 bool nomaster = ctx->deslavement;
10045 struct mlxsw_sp_crif *crif;
10046
10047 if (!ctx->done)
10048 return 0;
10049
10050 if (mlxsw_sp_dev_addr_list_empty(dev))
10051 return 0;
10052
10053 crif = mlxsw_sp_crif_lookup(ctx->mlxsw_sp->router, dev);
10054 if (!crif || !crif->rif)
10055 return 0;
10056
10057 /* We are rolling back NETDEV_UP, so ask for that. */
10058 if (!mlxsw_sp_rif_should_config(crif->rif, dev, NETDEV_UP))
10059 return 0;
10060
10061 __mlxsw_sp_inetaddr_event(ctx->mlxsw_sp, dev, NETDEV_DOWN, nomaster,
10062 NULL);
10063
10064 ctx->done--;
10065 return 0;
10066 }
10067
mlxsw_sp_netdevice_enslavement_replay(struct mlxsw_sp * mlxsw_sp,struct net_device * upper_dev,struct netlink_ext_ack * extack)10068 int mlxsw_sp_netdevice_enslavement_replay(struct mlxsw_sp *mlxsw_sp,
10069 struct net_device *upper_dev,
10070 struct netlink_ext_ack *extack)
10071 {
10072 struct mlxsw_sp_router_replay_inetaddr_up ctx = {
10073 .mlxsw_sp = mlxsw_sp,
10074 .extack = extack,
10075 .deslavement = false,
10076 };
10077 struct netdev_nested_priv priv = {
10078 .data = &ctx,
10079 };
10080 int err;
10081
10082 err = mlxsw_sp_router_replay_inetaddr_up(upper_dev, &priv);
10083 if (err)
10084 return err;
10085
10086 err = netdev_walk_all_upper_dev_rcu(upper_dev,
10087 mlxsw_sp_router_replay_inetaddr_up,
10088 &priv);
10089 if (err)
10090 goto err_replay_up;
10091
10092 return 0;
10093
10094 err_replay_up:
10095 netdev_walk_all_upper_dev_rcu(upper_dev,
10096 mlxsw_sp_router_unreplay_inetaddr_up,
10097 &priv);
10098 mlxsw_sp_router_unreplay_inetaddr_up(upper_dev, &priv);
10099 return err;
10100 }
10101
mlxsw_sp_netdevice_deslavement_replay(struct mlxsw_sp * mlxsw_sp,struct net_device * dev)10102 void mlxsw_sp_netdevice_deslavement_replay(struct mlxsw_sp *mlxsw_sp,
10103 struct net_device *dev)
10104 {
10105 struct mlxsw_sp_router_replay_inetaddr_up ctx = {
10106 .mlxsw_sp = mlxsw_sp,
10107 .deslavement = true,
10108 };
10109 struct netdev_nested_priv priv = {
10110 .data = &ctx,
10111 };
10112
10113 mlxsw_sp_router_replay_inetaddr_up(dev, &priv);
10114 }
10115
10116 static int
mlxsw_sp_port_vid_router_join_existing(struct mlxsw_sp_port * mlxsw_sp_port,u16 vid,struct net_device * dev,struct netlink_ext_ack * extack)10117 mlxsw_sp_port_vid_router_join_existing(struct mlxsw_sp_port *mlxsw_sp_port,
10118 u16 vid, struct net_device *dev,
10119 struct netlink_ext_ack *extack)
10120 {
10121 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
10122
10123 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port,
10124 vid);
10125 if (WARN_ON(!mlxsw_sp_port_vlan))
10126 return -EINVAL;
10127
10128 return mlxsw_sp_port_vlan_router_join_existing(mlxsw_sp_port_vlan,
10129 dev, extack);
10130 }
10131
10132 static void
mlxsw_sp_port_vid_router_leave(struct mlxsw_sp_port * mlxsw_sp_port,u16 vid,struct net_device * dev)10133 mlxsw_sp_port_vid_router_leave(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
10134 struct net_device *dev)
10135 {
10136 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
10137
10138 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port,
10139 vid);
10140 if (WARN_ON(!mlxsw_sp_port_vlan))
10141 return;
10142
10143 __mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
10144 }
10145
__mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port * mlxsw_sp_port,struct net_device * lag_dev,struct netlink_ext_ack * extack)10146 static int __mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port,
10147 struct net_device *lag_dev,
10148 struct netlink_ext_ack *extack)
10149 {
10150 u16 default_vid = MLXSW_SP_DEFAULT_VID;
10151 struct net_device *upper_dev;
10152 struct list_head *iter;
10153 int done = 0;
10154 u16 vid;
10155 int err;
10156
10157 err = mlxsw_sp_port_vid_router_join_existing(mlxsw_sp_port, default_vid,
10158 lag_dev, extack);
10159 if (err)
10160 return err;
10161
10162 netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
10163 if (!is_vlan_dev(upper_dev))
10164 continue;
10165
10166 vid = vlan_dev_vlan_id(upper_dev);
10167 err = mlxsw_sp_port_vid_router_join_existing(mlxsw_sp_port, vid,
10168 upper_dev, extack);
10169 if (err)
10170 goto err_router_join_dev;
10171
10172 ++done;
10173 }
10174
10175 return 0;
10176
10177 err_router_join_dev:
10178 netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
10179 if (!is_vlan_dev(upper_dev))
10180 continue;
10181 if (!done--)
10182 break;
10183
10184 vid = vlan_dev_vlan_id(upper_dev);
10185 mlxsw_sp_port_vid_router_leave(mlxsw_sp_port, vid, upper_dev);
10186 }
10187
10188 mlxsw_sp_port_vid_router_leave(mlxsw_sp_port, default_vid, lag_dev);
10189 return err;
10190 }
10191
10192 static void
__mlxsw_sp_router_port_leave_lag(struct mlxsw_sp_port * mlxsw_sp_port,struct net_device * lag_dev)10193 __mlxsw_sp_router_port_leave_lag(struct mlxsw_sp_port *mlxsw_sp_port,
10194 struct net_device *lag_dev)
10195 {
10196 u16 default_vid = MLXSW_SP_DEFAULT_VID;
10197 struct net_device *upper_dev;
10198 struct list_head *iter;
10199 u16 vid;
10200
10201 netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
10202 if (!is_vlan_dev(upper_dev))
10203 continue;
10204
10205 vid = vlan_dev_vlan_id(upper_dev);
10206 mlxsw_sp_port_vid_router_leave(mlxsw_sp_port, vid, upper_dev);
10207 }
10208
10209 mlxsw_sp_port_vid_router_leave(mlxsw_sp_port, default_vid, lag_dev);
10210 }
10211
mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port * mlxsw_sp_port,struct net_device * lag_dev,struct netlink_ext_ack * extack)10212 int mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port,
10213 struct net_device *lag_dev,
10214 struct netlink_ext_ack *extack)
10215 {
10216 int err;
10217
10218 mutex_lock(&mlxsw_sp_port->mlxsw_sp->router->lock);
10219 err = __mlxsw_sp_router_port_join_lag(mlxsw_sp_port, lag_dev, extack);
10220 mutex_unlock(&mlxsw_sp_port->mlxsw_sp->router->lock);
10221
10222 return err;
10223 }
10224
mlxsw_sp_router_port_leave_lag(struct mlxsw_sp_port * mlxsw_sp_port,struct net_device * lag_dev)10225 void mlxsw_sp_router_port_leave_lag(struct mlxsw_sp_port *mlxsw_sp_port,
10226 struct net_device *lag_dev)
10227 {
10228 mutex_lock(&mlxsw_sp_port->mlxsw_sp->router->lock);
10229 __mlxsw_sp_router_port_leave_lag(mlxsw_sp_port, lag_dev);
10230 mutex_unlock(&mlxsw_sp_port->mlxsw_sp->router->lock);
10231 }
10232
mlxsw_sp_router_netdevice_event(struct notifier_block * nb,unsigned long event,void * ptr)10233 static int mlxsw_sp_router_netdevice_event(struct notifier_block *nb,
10234 unsigned long event, void *ptr)
10235 {
10236 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
10237 struct mlxsw_sp_router *router;
10238 struct mlxsw_sp *mlxsw_sp;
10239 int err = 0;
10240
10241 router = container_of(nb, struct mlxsw_sp_router, netdevice_nb);
10242 mlxsw_sp = router->mlxsw_sp;
10243
10244 mutex_lock(&mlxsw_sp->router->lock);
10245
10246 if (event == NETDEV_REGISTER) {
10247 err = mlxsw_sp_netdevice_register(router, dev);
10248 if (err)
10249 /* No need to roll this back, UNREGISTER will collect it
10250 * anyhow.
10251 */
10252 goto out;
10253 }
10254
10255 if (mlxsw_sp_is_offload_xstats_event(event))
10256 err = mlxsw_sp_netdevice_offload_xstats_cmd(mlxsw_sp, dev,
10257 event, ptr);
10258 else if (mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev))
10259 err = mlxsw_sp_netdevice_ipip_ol_event(mlxsw_sp, dev,
10260 event, ptr);
10261 else if (mlxsw_sp_netdev_is_ipip_ul(mlxsw_sp, dev))
10262 err = mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, dev,
10263 event, ptr);
10264 else if (mlxsw_sp_is_router_event(event))
10265 err = mlxsw_sp_netdevice_router_port_event(dev, event, ptr);
10266 else if (mlxsw_sp_is_vrf_event(event, ptr))
10267 err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr);
10268
10269 if (event == NETDEV_UNREGISTER)
10270 mlxsw_sp_netdevice_unregister(router, dev);
10271
10272 out:
10273 mutex_unlock(&mlxsw_sp->router->lock);
10274
10275 return notifier_from_errno(err);
10276 }
10277
10278 struct mlxsw_sp_macvlan_replay {
10279 struct mlxsw_sp *mlxsw_sp;
10280 struct netlink_ext_ack *extack;
10281 };
10282
mlxsw_sp_macvlan_replay_upper(struct net_device * dev,struct netdev_nested_priv * priv)10283 static int mlxsw_sp_macvlan_replay_upper(struct net_device *dev,
10284 struct netdev_nested_priv *priv)
10285 {
10286 const struct mlxsw_sp_macvlan_replay *rms = priv->data;
10287 struct netlink_ext_ack *extack = rms->extack;
10288 struct mlxsw_sp *mlxsw_sp = rms->mlxsw_sp;
10289
10290 if (!netif_is_macvlan(dev))
10291 return 0;
10292
10293 return mlxsw_sp_rif_macvlan_add(mlxsw_sp, dev, extack);
10294 }
10295
mlxsw_sp_macvlan_replay(struct mlxsw_sp_rif * rif,struct netlink_ext_ack * extack)10296 static int mlxsw_sp_macvlan_replay(struct mlxsw_sp_rif *rif,
10297 struct netlink_ext_ack *extack)
10298 {
10299 struct mlxsw_sp_macvlan_replay rms = {
10300 .mlxsw_sp = rif->mlxsw_sp,
10301 .extack = extack,
10302 };
10303 struct netdev_nested_priv priv = {
10304 .data = &rms,
10305 };
10306
10307 return netdev_walk_all_upper_dev_rcu(mlxsw_sp_rif_dev(rif),
10308 mlxsw_sp_macvlan_replay_upper,
10309 &priv);
10310 }
10311
__mlxsw_sp_rif_macvlan_flush(struct net_device * dev,struct netdev_nested_priv * priv)10312 static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev,
10313 struct netdev_nested_priv *priv)
10314 {
10315 struct mlxsw_sp_rif *rif = (struct mlxsw_sp_rif *)priv->data;
10316
10317 if (!netif_is_macvlan(dev))
10318 return 0;
10319
10320 return mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
10321 mlxsw_sp_fid_index(rif->fid), false);
10322 }
10323
mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif * rif)10324 static int mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif *rif)
10325 {
10326 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10327 struct netdev_nested_priv priv = {
10328 .data = (void *)rif,
10329 };
10330
10331 if (!netif_is_macvlan_port(dev))
10332 return 0;
10333
10334 return netdev_walk_all_upper_dev_rcu(dev,
10335 __mlxsw_sp_rif_macvlan_flush, &priv);
10336 }
10337
mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif * rif,const struct mlxsw_sp_rif_params * params)10338 static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif,
10339 const struct mlxsw_sp_rif_params *params)
10340 {
10341 struct mlxsw_sp_rif_subport *rif_subport;
10342
10343 rif_subport = mlxsw_sp_rif_subport_rif(rif);
10344 refcount_set(&rif_subport->ref_count, 1);
10345 rif_subport->vid = params->vid;
10346 rif_subport->lag = params->lag;
10347 if (params->lag)
10348 rif_subport->lag_id = params->lag_id;
10349 else
10350 rif_subport->system_port = params->system_port;
10351 }
10352
mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif * rif,bool enable)10353 static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable)
10354 {
10355 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10356 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
10357 struct mlxsw_sp_rif_subport *rif_subport;
10358 char ritr_pl[MLXSW_REG_RITR_LEN];
10359 u16 efid;
10360
10361 rif_subport = mlxsw_sp_rif_subport_rif(rif);
10362 mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_SP_IF,
10363 rif->rif_index, rif->vr_id, dev->mtu);
10364 mlxsw_reg_ritr_mac_pack(ritr_pl, dev->dev_addr);
10365 mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, rif->mac_profile_id);
10366 efid = mlxsw_sp_fid_index(rif->fid);
10367 mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag,
10368 rif_subport->lag ? rif_subport->lag_id :
10369 rif_subport->system_port,
10370 efid, 0);
10371 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
10372 }
10373
mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif * rif,struct netlink_ext_ack * extack)10374 static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif,
10375 struct netlink_ext_ack *extack)
10376 {
10377 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10378 u8 mac_profile;
10379 int err;
10380
10381 err = mlxsw_sp_rif_mac_profile_get(rif->mlxsw_sp, rif->addr,
10382 &mac_profile, extack);
10383 if (err)
10384 return err;
10385 rif->mac_profile_id = mac_profile;
10386
10387 err = mlxsw_sp_rif_subport_op(rif, true);
10388 if (err)
10389 goto err_rif_subport_op;
10390
10391 err = mlxsw_sp_macvlan_replay(rif, extack);
10392 if (err)
10393 goto err_macvlan_replay;
10394
10395 err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
10396 mlxsw_sp_fid_index(rif->fid), true);
10397 if (err)
10398 goto err_rif_fdb_op;
10399
10400 err = mlxsw_sp_fid_rif_set(rif->fid, rif);
10401 if (err)
10402 goto err_fid_rif_set;
10403
10404 return 0;
10405
10406 err_fid_rif_set:
10407 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
10408 mlxsw_sp_fid_index(rif->fid), false);
10409 err_rif_fdb_op:
10410 mlxsw_sp_rif_macvlan_flush(rif);
10411 err_macvlan_replay:
10412 mlxsw_sp_rif_subport_op(rif, false);
10413 err_rif_subport_op:
10414 mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, mac_profile);
10415 return err;
10416 }
10417
mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif * rif)10418 static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif)
10419 {
10420 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10421 struct mlxsw_sp_fid *fid = rif->fid;
10422
10423 mlxsw_sp_fid_rif_unset(fid);
10424 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
10425 mlxsw_sp_fid_index(fid), false);
10426 mlxsw_sp_rif_macvlan_flush(rif);
10427 mlxsw_sp_rif_subport_op(rif, false);
10428 mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, rif->mac_profile_id);
10429 }
10430
10431 static struct mlxsw_sp_fid *
mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif * rif,const struct mlxsw_sp_rif_params * params,struct netlink_ext_ack * extack)10432 mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif *rif,
10433 const struct mlxsw_sp_rif_params *params,
10434 struct netlink_ext_ack *extack)
10435 {
10436 return mlxsw_sp_fid_rfid_get(rif->mlxsw_sp, rif->rif_index);
10437 }
10438
10439 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_subport_ops = {
10440 .type = MLXSW_SP_RIF_TYPE_SUBPORT,
10441 .rif_size = sizeof(struct mlxsw_sp_rif_subport),
10442 .setup = mlxsw_sp_rif_subport_setup,
10443 .configure = mlxsw_sp_rif_subport_configure,
10444 .deconfigure = mlxsw_sp_rif_subport_deconfigure,
10445 .fid_get = mlxsw_sp_rif_subport_fid_get,
10446 };
10447
mlxsw_sp_rif_fid_op(struct mlxsw_sp_rif * rif,u16 fid,bool enable)10448 static int mlxsw_sp_rif_fid_op(struct mlxsw_sp_rif *rif, u16 fid, bool enable)
10449 {
10450 enum mlxsw_reg_ritr_if_type type = MLXSW_REG_RITR_FID_IF;
10451 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10452 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
10453 char ritr_pl[MLXSW_REG_RITR_LEN];
10454
10455 mlxsw_reg_ritr_pack(ritr_pl, enable, type, rif->rif_index, rif->vr_id,
10456 dev->mtu);
10457 mlxsw_reg_ritr_mac_pack(ritr_pl, dev->dev_addr);
10458 mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, rif->mac_profile_id);
10459 mlxsw_reg_ritr_fid_if_fid_set(ritr_pl, fid);
10460
10461 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
10462 }
10463
mlxsw_sp_router_port(const struct mlxsw_sp * mlxsw_sp)10464 u16 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp)
10465 {
10466 return mlxsw_core_max_ports(mlxsw_sp->core) + 1;
10467 }
10468
mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif * rif,struct netlink_ext_ack * extack)10469 static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif,
10470 struct netlink_ext_ack *extack)
10471 {
10472 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10473 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
10474 u16 fid_index = mlxsw_sp_fid_index(rif->fid);
10475 u8 mac_profile;
10476 int err;
10477
10478 err = mlxsw_sp_rif_mac_profile_get(mlxsw_sp, rif->addr,
10479 &mac_profile, extack);
10480 if (err)
10481 return err;
10482 rif->mac_profile_id = mac_profile;
10483
10484 err = mlxsw_sp_rif_fid_op(rif, fid_index, true);
10485 if (err)
10486 goto err_rif_fid_op;
10487
10488 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
10489 mlxsw_sp_router_port(mlxsw_sp), true);
10490 if (err)
10491 goto err_fid_mc_flood_set;
10492
10493 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
10494 mlxsw_sp_router_port(mlxsw_sp), true);
10495 if (err)
10496 goto err_fid_bc_flood_set;
10497
10498 err = mlxsw_sp_macvlan_replay(rif, extack);
10499 if (err)
10500 goto err_macvlan_replay;
10501
10502 err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
10503 mlxsw_sp_fid_index(rif->fid), true);
10504 if (err)
10505 goto err_rif_fdb_op;
10506
10507 err = mlxsw_sp_fid_rif_set(rif->fid, rif);
10508 if (err)
10509 goto err_fid_rif_set;
10510
10511 return 0;
10512
10513 err_fid_rif_set:
10514 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
10515 mlxsw_sp_fid_index(rif->fid), false);
10516 err_rif_fdb_op:
10517 mlxsw_sp_rif_macvlan_flush(rif);
10518 err_macvlan_replay:
10519 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
10520 mlxsw_sp_router_port(mlxsw_sp), false);
10521 err_fid_bc_flood_set:
10522 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
10523 mlxsw_sp_router_port(mlxsw_sp), false);
10524 err_fid_mc_flood_set:
10525 mlxsw_sp_rif_fid_op(rif, fid_index, false);
10526 err_rif_fid_op:
10527 mlxsw_sp_rif_mac_profile_put(mlxsw_sp, mac_profile);
10528 return err;
10529 }
10530
mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif * rif)10531 static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)
10532 {
10533 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10534 u16 fid_index = mlxsw_sp_fid_index(rif->fid);
10535 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
10536 struct mlxsw_sp_fid *fid = rif->fid;
10537
10538 mlxsw_sp_fid_rif_unset(fid);
10539 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
10540 mlxsw_sp_fid_index(fid), false);
10541 mlxsw_sp_rif_macvlan_flush(rif);
10542 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
10543 mlxsw_sp_router_port(mlxsw_sp), false);
10544 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
10545 mlxsw_sp_router_port(mlxsw_sp), false);
10546 mlxsw_sp_rif_fid_op(rif, fid_index, false);
10547 mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, rif->mac_profile_id);
10548 }
10549
10550 static struct mlxsw_sp_fid *
mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif * rif,const struct mlxsw_sp_rif_params * params,struct netlink_ext_ack * extack)10551 mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif,
10552 const struct mlxsw_sp_rif_params *params,
10553 struct netlink_ext_ack *extack)
10554 {
10555 int rif_ifindex = mlxsw_sp_rif_dev_ifindex(rif);
10556
10557 return mlxsw_sp_fid_8021d_get(rif->mlxsw_sp, rif_ifindex);
10558 }
10559
mlxsw_sp_rif_fid_fdb_del(struct mlxsw_sp_rif * rif,const char * mac)10560 static void mlxsw_sp_rif_fid_fdb_del(struct mlxsw_sp_rif *rif, const char *mac)
10561 {
10562 struct switchdev_notifier_fdb_info info = {};
10563 struct net_device *dev;
10564
10565 dev = br_fdb_find_port(mlxsw_sp_rif_dev(rif), mac, 0);
10566 if (!dev)
10567 return;
10568
10569 info.addr = mac;
10570 info.vid = 0;
10571 call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info,
10572 NULL);
10573 }
10574
10575 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = {
10576 .type = MLXSW_SP_RIF_TYPE_FID,
10577 .rif_size = sizeof(struct mlxsw_sp_rif),
10578 .configure = mlxsw_sp_rif_fid_configure,
10579 .deconfigure = mlxsw_sp_rif_fid_deconfigure,
10580 .fid_get = mlxsw_sp_rif_fid_fid_get,
10581 .fdb_del = mlxsw_sp_rif_fid_fdb_del,
10582 };
10583
10584 static struct mlxsw_sp_fid *
mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif * rif,const struct mlxsw_sp_rif_params * params,struct netlink_ext_ack * extack)10585 mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif,
10586 const struct mlxsw_sp_rif_params *params,
10587 struct netlink_ext_ack *extack)
10588 {
10589 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10590 struct net_device *br_dev;
10591
10592 if (WARN_ON(!params->vid))
10593 return ERR_PTR(-EINVAL);
10594
10595 if (is_vlan_dev(dev)) {
10596 br_dev = vlan_dev_real_dev(dev);
10597 if (WARN_ON(!netif_is_bridge_master(br_dev)))
10598 return ERR_PTR(-EINVAL);
10599 }
10600
10601 return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, params->vid);
10602 }
10603
mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif * rif,const char * mac)10604 static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac)
10605 {
10606 struct net_device *rif_dev = mlxsw_sp_rif_dev(rif);
10607 struct switchdev_notifier_fdb_info info = {};
10608 u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
10609 struct net_device *br_dev;
10610 struct net_device *dev;
10611
10612 br_dev = is_vlan_dev(rif_dev) ? vlan_dev_real_dev(rif_dev) : rif_dev;
10613 dev = br_fdb_find_port(br_dev, mac, vid);
10614 if (!dev)
10615 return;
10616
10617 info.addr = mac;
10618 info.vid = vid;
10619 call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info,
10620 NULL);
10621 }
10622
mlxsw_sp_rif_vlan_op(struct mlxsw_sp_rif * rif,u16 vid,u16 efid,bool enable)10623 static int mlxsw_sp_rif_vlan_op(struct mlxsw_sp_rif *rif, u16 vid, u16 efid,
10624 bool enable)
10625 {
10626 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10627 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
10628 char ritr_pl[MLXSW_REG_RITR_LEN];
10629
10630 mlxsw_reg_ritr_vlan_if_pack(ritr_pl, enable, rif->rif_index, rif->vr_id,
10631 dev->mtu, dev->dev_addr,
10632 rif->mac_profile_id, vid, efid);
10633
10634 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
10635 }
10636
mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif * rif,u16 efid,struct netlink_ext_ack * extack)10637 static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif, u16 efid,
10638 struct netlink_ext_ack *extack)
10639 {
10640 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10641 u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
10642 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
10643 u8 mac_profile;
10644 int err;
10645
10646 err = mlxsw_sp_rif_mac_profile_get(mlxsw_sp, rif->addr,
10647 &mac_profile, extack);
10648 if (err)
10649 return err;
10650 rif->mac_profile_id = mac_profile;
10651
10652 err = mlxsw_sp_rif_vlan_op(rif, vid, efid, true);
10653 if (err)
10654 goto err_rif_vlan_fid_op;
10655
10656 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
10657 mlxsw_sp_router_port(mlxsw_sp), true);
10658 if (err)
10659 goto err_fid_mc_flood_set;
10660
10661 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
10662 mlxsw_sp_router_port(mlxsw_sp), true);
10663 if (err)
10664 goto err_fid_bc_flood_set;
10665
10666 err = mlxsw_sp_macvlan_replay(rif, extack);
10667 if (err)
10668 goto err_macvlan_replay;
10669
10670 err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
10671 mlxsw_sp_fid_index(rif->fid), true);
10672 if (err)
10673 goto err_rif_fdb_op;
10674
10675 err = mlxsw_sp_fid_rif_set(rif->fid, rif);
10676 if (err)
10677 goto err_fid_rif_set;
10678
10679 return 0;
10680
10681 err_fid_rif_set:
10682 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
10683 mlxsw_sp_fid_index(rif->fid), false);
10684 err_rif_fdb_op:
10685 mlxsw_sp_rif_macvlan_flush(rif);
10686 err_macvlan_replay:
10687 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
10688 mlxsw_sp_router_port(mlxsw_sp), false);
10689 err_fid_bc_flood_set:
10690 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
10691 mlxsw_sp_router_port(mlxsw_sp), false);
10692 err_fid_mc_flood_set:
10693 mlxsw_sp_rif_vlan_op(rif, vid, 0, false);
10694 err_rif_vlan_fid_op:
10695 mlxsw_sp_rif_mac_profile_put(mlxsw_sp, mac_profile);
10696 return err;
10697 }
10698
mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif * rif)10699 static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif *rif)
10700 {
10701 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10702 u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
10703 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
10704
10705 mlxsw_sp_fid_rif_unset(rif->fid);
10706 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
10707 mlxsw_sp_fid_index(rif->fid), false);
10708 mlxsw_sp_rif_macvlan_flush(rif);
10709 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
10710 mlxsw_sp_router_port(mlxsw_sp), false);
10711 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
10712 mlxsw_sp_router_port(mlxsw_sp), false);
10713 mlxsw_sp_rif_vlan_op(rif, vid, 0, false);
10714 mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, rif->mac_profile_id);
10715 }
10716
mlxsw_sp1_rif_vlan_configure(struct mlxsw_sp_rif * rif,struct netlink_ext_ack * extack)10717 static int mlxsw_sp1_rif_vlan_configure(struct mlxsw_sp_rif *rif,
10718 struct netlink_ext_ack *extack)
10719 {
10720 return mlxsw_sp_rif_vlan_configure(rif, 0, extack);
10721 }
10722
10723 static const struct mlxsw_sp_rif_ops mlxsw_sp1_rif_vlan_ops = {
10724 .type = MLXSW_SP_RIF_TYPE_VLAN,
10725 .rif_size = sizeof(struct mlxsw_sp_rif),
10726 .configure = mlxsw_sp1_rif_vlan_configure,
10727 .deconfigure = mlxsw_sp_rif_vlan_deconfigure,
10728 .fid_get = mlxsw_sp_rif_vlan_fid_get,
10729 .fdb_del = mlxsw_sp_rif_vlan_fdb_del,
10730 };
10731
mlxsw_sp2_rif_vlan_configure(struct mlxsw_sp_rif * rif,struct netlink_ext_ack * extack)10732 static int mlxsw_sp2_rif_vlan_configure(struct mlxsw_sp_rif *rif,
10733 struct netlink_ext_ack *extack)
10734 {
10735 u16 efid = mlxsw_sp_fid_index(rif->fid);
10736
10737 return mlxsw_sp_rif_vlan_configure(rif, efid, extack);
10738 }
10739
10740 static const struct mlxsw_sp_rif_ops mlxsw_sp2_rif_vlan_ops = {
10741 .type = MLXSW_SP_RIF_TYPE_VLAN,
10742 .rif_size = sizeof(struct mlxsw_sp_rif),
10743 .configure = mlxsw_sp2_rif_vlan_configure,
10744 .deconfigure = mlxsw_sp_rif_vlan_deconfigure,
10745 .fid_get = mlxsw_sp_rif_vlan_fid_get,
10746 .fdb_del = mlxsw_sp_rif_vlan_fdb_del,
10747 };
10748
10749 static struct mlxsw_sp_rif_ipip_lb *
mlxsw_sp_rif_ipip_lb_rif(struct mlxsw_sp_rif * rif)10750 mlxsw_sp_rif_ipip_lb_rif(struct mlxsw_sp_rif *rif)
10751 {
10752 return container_of(rif, struct mlxsw_sp_rif_ipip_lb, common);
10753 }
10754
10755 static void
mlxsw_sp_rif_ipip_lb_setup(struct mlxsw_sp_rif * rif,const struct mlxsw_sp_rif_params * params)10756 mlxsw_sp_rif_ipip_lb_setup(struct mlxsw_sp_rif *rif,
10757 const struct mlxsw_sp_rif_params *params)
10758 {
10759 struct mlxsw_sp_rif_params_ipip_lb *params_lb;
10760 struct mlxsw_sp_rif_ipip_lb *rif_lb;
10761
10762 params_lb = container_of(params, struct mlxsw_sp_rif_params_ipip_lb,
10763 common);
10764 rif_lb = mlxsw_sp_rif_ipip_lb_rif(rif);
10765 rif_lb->lb_config = params_lb->lb_config;
10766 }
10767
10768 static int
mlxsw_sp1_rif_ipip_lb_configure(struct mlxsw_sp_rif * rif,struct netlink_ext_ack * extack)10769 mlxsw_sp1_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif,
10770 struct netlink_ext_ack *extack)
10771 {
10772 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
10773 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10774 u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(dev);
10775 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
10776 struct mlxsw_sp_vr *ul_vr;
10777 int err;
10778
10779 ul_vr = mlxsw_sp_vr_get(mlxsw_sp, ul_tb_id, extack);
10780 if (IS_ERR(ul_vr))
10781 return PTR_ERR(ul_vr);
10782
10783 err = mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr->id, 0, true);
10784 if (err)
10785 goto err_loopback_op;
10786
10787 lb_rif->ul_vr_id = ul_vr->id;
10788 lb_rif->ul_rif_id = 0;
10789 ++ul_vr->rif_count;
10790 return 0;
10791
10792 err_loopback_op:
10793 mlxsw_sp_vr_put(mlxsw_sp, ul_vr);
10794 return err;
10795 }
10796
mlxsw_sp1_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif * rif)10797 static void mlxsw_sp1_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif)
10798 {
10799 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
10800 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
10801 struct mlxsw_sp_vr *ul_vr;
10802
10803 ul_vr = &mlxsw_sp->router->vrs[lb_rif->ul_vr_id];
10804 mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr->id, 0, false);
10805
10806 --ul_vr->rif_count;
10807 mlxsw_sp_vr_put(mlxsw_sp, ul_vr);
10808 }
10809
10810 static const struct mlxsw_sp_rif_ops mlxsw_sp1_rif_ipip_lb_ops = {
10811 .type = MLXSW_SP_RIF_TYPE_IPIP_LB,
10812 .rif_size = sizeof(struct mlxsw_sp_rif_ipip_lb),
10813 .setup = mlxsw_sp_rif_ipip_lb_setup,
10814 .configure = mlxsw_sp1_rif_ipip_lb_configure,
10815 .deconfigure = mlxsw_sp1_rif_ipip_lb_deconfigure,
10816 };
10817
10818 static const struct mlxsw_sp_rif_ops *mlxsw_sp1_rif_ops_arr[] = {
10819 [MLXSW_SP_RIF_TYPE_SUBPORT] = &mlxsw_sp_rif_subport_ops,
10820 [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp1_rif_vlan_ops,
10821 [MLXSW_SP_RIF_TYPE_FID] = &mlxsw_sp_rif_fid_ops,
10822 [MLXSW_SP_RIF_TYPE_IPIP_LB] = &mlxsw_sp1_rif_ipip_lb_ops,
10823 };
10824
10825 static int
mlxsw_sp_rif_ipip_lb_ul_rif_op(struct mlxsw_sp_rif * ul_rif,bool enable)10826 mlxsw_sp_rif_ipip_lb_ul_rif_op(struct mlxsw_sp_rif *ul_rif, bool enable)
10827 {
10828 struct mlxsw_sp *mlxsw_sp = ul_rif->mlxsw_sp;
10829 char ritr_pl[MLXSW_REG_RITR_LEN];
10830
10831 mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF,
10832 ul_rif->rif_index, ul_rif->vr_id, IP_MAX_MTU);
10833 mlxsw_reg_ritr_loopback_protocol_set(ritr_pl,
10834 MLXSW_REG_RITR_LOOPBACK_GENERIC);
10835
10836 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
10837 }
10838
10839 static struct mlxsw_sp_rif *
mlxsw_sp_ul_rif_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_vr * vr,struct mlxsw_sp_crif * ul_crif,struct netlink_ext_ack * extack)10840 mlxsw_sp_ul_rif_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr,
10841 struct mlxsw_sp_crif *ul_crif,
10842 struct netlink_ext_ack *extack)
10843 {
10844 struct mlxsw_sp_rif *ul_rif;
10845 u8 rif_entries = 1;
10846 u16 rif_index;
10847 int err;
10848
10849 err = mlxsw_sp_rif_index_alloc(mlxsw_sp, &rif_index, rif_entries);
10850 if (err) {
10851 NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported router interfaces");
10852 return ERR_PTR(err);
10853 }
10854
10855 ul_rif = mlxsw_sp_rif_alloc(sizeof(*ul_rif), rif_index, vr->id,
10856 ul_crif);
10857 if (!ul_rif) {
10858 err = -ENOMEM;
10859 goto err_rif_alloc;
10860 }
10861
10862 mlxsw_sp->router->rifs[rif_index] = ul_rif;
10863 ul_rif->mlxsw_sp = mlxsw_sp;
10864 ul_rif->rif_entries = rif_entries;
10865 err = mlxsw_sp_rif_ipip_lb_ul_rif_op(ul_rif, true);
10866 if (err)
10867 goto ul_rif_op_err;
10868
10869 atomic_add(rif_entries, &mlxsw_sp->router->rifs_count);
10870 return ul_rif;
10871
10872 ul_rif_op_err:
10873 mlxsw_sp->router->rifs[rif_index] = NULL;
10874 mlxsw_sp_rif_free(ul_rif);
10875 err_rif_alloc:
10876 mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries);
10877 return ERR_PTR(err);
10878 }
10879
mlxsw_sp_ul_rif_destroy(struct mlxsw_sp_rif * ul_rif)10880 static void mlxsw_sp_ul_rif_destroy(struct mlxsw_sp_rif *ul_rif)
10881 {
10882 struct mlxsw_sp *mlxsw_sp = ul_rif->mlxsw_sp;
10883 u8 rif_entries = ul_rif->rif_entries;
10884 u16 rif_index = ul_rif->rif_index;
10885
10886 atomic_sub(rif_entries, &mlxsw_sp->router->rifs_count);
10887 mlxsw_sp_rif_ipip_lb_ul_rif_op(ul_rif, false);
10888 mlxsw_sp->router->rifs[ul_rif->rif_index] = NULL;
10889 mlxsw_sp_rif_free(ul_rif);
10890 mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries);
10891 }
10892
10893 static struct mlxsw_sp_rif *
mlxsw_sp_ul_rif_get(struct mlxsw_sp * mlxsw_sp,u32 tb_id,struct mlxsw_sp_crif * ul_crif,struct netlink_ext_ack * extack)10894 mlxsw_sp_ul_rif_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
10895 struct mlxsw_sp_crif *ul_crif,
10896 struct netlink_ext_ack *extack)
10897 {
10898 struct mlxsw_sp_vr *vr;
10899 int err;
10900
10901 vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id, extack);
10902 if (IS_ERR(vr))
10903 return ERR_CAST(vr);
10904
10905 if (refcount_inc_not_zero(&vr->ul_rif_refcnt))
10906 return vr->ul_rif;
10907
10908 vr->ul_rif = mlxsw_sp_ul_rif_create(mlxsw_sp, vr, ul_crif, extack);
10909 if (IS_ERR(vr->ul_rif)) {
10910 err = PTR_ERR(vr->ul_rif);
10911 goto err_ul_rif_create;
10912 }
10913
10914 vr->rif_count++;
10915 refcount_set(&vr->ul_rif_refcnt, 1);
10916
10917 return vr->ul_rif;
10918
10919 err_ul_rif_create:
10920 mlxsw_sp_vr_put(mlxsw_sp, vr);
10921 return ERR_PTR(err);
10922 }
10923
mlxsw_sp_ul_rif_put(struct mlxsw_sp_rif * ul_rif)10924 static void mlxsw_sp_ul_rif_put(struct mlxsw_sp_rif *ul_rif)
10925 {
10926 struct mlxsw_sp *mlxsw_sp = ul_rif->mlxsw_sp;
10927 struct mlxsw_sp_vr *vr;
10928
10929 vr = &mlxsw_sp->router->vrs[ul_rif->vr_id];
10930
10931 if (!refcount_dec_and_test(&vr->ul_rif_refcnt))
10932 return;
10933
10934 vr->rif_count--;
10935 mlxsw_sp_ul_rif_destroy(ul_rif);
10936 mlxsw_sp_vr_put(mlxsw_sp, vr);
10937 }
10938
mlxsw_sp_router_ul_rif_get(struct mlxsw_sp * mlxsw_sp,u32 ul_tb_id,u16 * ul_rif_index)10939 int mlxsw_sp_router_ul_rif_get(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
10940 u16 *ul_rif_index)
10941 {
10942 struct mlxsw_sp_rif *ul_rif;
10943 int err = 0;
10944
10945 mutex_lock(&mlxsw_sp->router->lock);
10946 ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, NULL, NULL);
10947 if (IS_ERR(ul_rif)) {
10948 err = PTR_ERR(ul_rif);
10949 goto out;
10950 }
10951 *ul_rif_index = ul_rif->rif_index;
10952 out:
10953 mutex_unlock(&mlxsw_sp->router->lock);
10954 return err;
10955 }
10956
mlxsw_sp_router_ul_rif_put(struct mlxsw_sp * mlxsw_sp,u16 ul_rif_index)10957 void mlxsw_sp_router_ul_rif_put(struct mlxsw_sp *mlxsw_sp, u16 ul_rif_index)
10958 {
10959 struct mlxsw_sp_rif *ul_rif;
10960
10961 mutex_lock(&mlxsw_sp->router->lock);
10962 ul_rif = mlxsw_sp->router->rifs[ul_rif_index];
10963 if (WARN_ON(!ul_rif))
10964 goto out;
10965
10966 mlxsw_sp_ul_rif_put(ul_rif);
10967 out:
10968 mutex_unlock(&mlxsw_sp->router->lock);
10969 }
10970
10971 static int
mlxsw_sp2_rif_ipip_lb_configure(struct mlxsw_sp_rif * rif,struct netlink_ext_ack * extack)10972 mlxsw_sp2_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif,
10973 struct netlink_ext_ack *extack)
10974 {
10975 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
10976 struct net_device *dev = mlxsw_sp_rif_dev(rif);
10977 u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(dev);
10978 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
10979 struct mlxsw_sp_rif *ul_rif;
10980 int err;
10981
10982 ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, NULL, extack);
10983 if (IS_ERR(ul_rif))
10984 return PTR_ERR(ul_rif);
10985
10986 err = mlxsw_sp_rif_ipip_lb_op(lb_rif, 0, ul_rif->rif_index, true);
10987 if (err)
10988 goto err_loopback_op;
10989
10990 lb_rif->ul_vr_id = 0;
10991 lb_rif->ul_rif_id = ul_rif->rif_index;
10992
10993 return 0;
10994
10995 err_loopback_op:
10996 mlxsw_sp_ul_rif_put(ul_rif);
10997 return err;
10998 }
10999
mlxsw_sp2_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif * rif)11000 static void mlxsw_sp2_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif)
11001 {
11002 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
11003 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
11004 struct mlxsw_sp_rif *ul_rif;
11005
11006 ul_rif = mlxsw_sp_rif_by_index(mlxsw_sp, lb_rif->ul_rif_id);
11007 mlxsw_sp_rif_ipip_lb_op(lb_rif, 0, lb_rif->ul_rif_id, false);
11008 mlxsw_sp_ul_rif_put(ul_rif);
11009 }
11010
11011 static const struct mlxsw_sp_rif_ops mlxsw_sp2_rif_ipip_lb_ops = {
11012 .type = MLXSW_SP_RIF_TYPE_IPIP_LB,
11013 .rif_size = sizeof(struct mlxsw_sp_rif_ipip_lb),
11014 .setup = mlxsw_sp_rif_ipip_lb_setup,
11015 .configure = mlxsw_sp2_rif_ipip_lb_configure,
11016 .deconfigure = mlxsw_sp2_rif_ipip_lb_deconfigure,
11017 };
11018
11019 static const struct mlxsw_sp_rif_ops *mlxsw_sp2_rif_ops_arr[] = {
11020 [MLXSW_SP_RIF_TYPE_SUBPORT] = &mlxsw_sp_rif_subport_ops,
11021 [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp2_rif_vlan_ops,
11022 [MLXSW_SP_RIF_TYPE_FID] = &mlxsw_sp_rif_fid_ops,
11023 [MLXSW_SP_RIF_TYPE_IPIP_LB] = &mlxsw_sp2_rif_ipip_lb_ops,
11024 };
11025
mlxsw_sp_rifs_table_init(struct mlxsw_sp * mlxsw_sp)11026 static int mlxsw_sp_rifs_table_init(struct mlxsw_sp *mlxsw_sp)
11027 {
11028 struct gen_pool *rifs_table;
11029 int err;
11030
11031 rifs_table = gen_pool_create(0, -1);
11032 if (!rifs_table)
11033 return -ENOMEM;
11034
11035 gen_pool_set_algo(rifs_table, gen_pool_first_fit_order_align,
11036 NULL);
11037
11038 err = gen_pool_add(rifs_table, MLXSW_SP_ROUTER_GENALLOC_OFFSET,
11039 MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS), -1);
11040 if (err)
11041 goto err_gen_pool_add;
11042
11043 mlxsw_sp->router->rifs_table = rifs_table;
11044
11045 return 0;
11046
11047 err_gen_pool_add:
11048 gen_pool_destroy(rifs_table);
11049 return err;
11050 }
11051
mlxsw_sp_rifs_table_fini(struct mlxsw_sp * mlxsw_sp)11052 static void mlxsw_sp_rifs_table_fini(struct mlxsw_sp *mlxsw_sp)
11053 {
11054 gen_pool_destroy(mlxsw_sp->router->rifs_table);
11055 }
11056
mlxsw_sp_rifs_init(struct mlxsw_sp * mlxsw_sp)11057 static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
11058 {
11059 u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
11060 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
11061 struct mlxsw_core *core = mlxsw_sp->core;
11062 int err;
11063
11064 if (!MLXSW_CORE_RES_VALID(core, MAX_RIF_MAC_PROFILES))
11065 return -EIO;
11066 mlxsw_sp->router->max_rif_mac_profile =
11067 MLXSW_CORE_RES_GET(core, MAX_RIF_MAC_PROFILES);
11068
11069 mlxsw_sp->router->rifs = kzalloc_objs(struct mlxsw_sp_rif *, max_rifs);
11070 if (!mlxsw_sp->router->rifs)
11071 return -ENOMEM;
11072
11073 err = mlxsw_sp_rifs_table_init(mlxsw_sp);
11074 if (err)
11075 goto err_rifs_table_init;
11076
11077 idr_init(&mlxsw_sp->router->rif_mac_profiles_idr);
11078 atomic_set(&mlxsw_sp->router->rif_mac_profiles_count, 0);
11079 atomic_set(&mlxsw_sp->router->rifs_count, 0);
11080 devl_resource_occ_get_register(devlink,
11081 MLXSW_SP_RESOURCE_RIF_MAC_PROFILES,
11082 mlxsw_sp_rif_mac_profiles_occ_get,
11083 mlxsw_sp);
11084 devl_resource_occ_get_register(devlink,
11085 MLXSW_SP_RESOURCE_RIFS,
11086 mlxsw_sp_rifs_occ_get,
11087 mlxsw_sp);
11088
11089 return 0;
11090
11091 err_rifs_table_init:
11092 kfree(mlxsw_sp->router->rifs);
11093 return err;
11094 }
11095
mlxsw_sp_rifs_fini(struct mlxsw_sp * mlxsw_sp)11096 static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp)
11097 {
11098 int max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
11099 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
11100 int i;
11101
11102 WARN_ON_ONCE(atomic_read(&mlxsw_sp->router->rifs_count));
11103 for (i = 0; i < max_rifs; i++)
11104 WARN_ON_ONCE(mlxsw_sp->router->rifs[i]);
11105
11106 devl_resource_occ_get_unregister(devlink, MLXSW_SP_RESOURCE_RIFS);
11107 devl_resource_occ_get_unregister(devlink,
11108 MLXSW_SP_RESOURCE_RIF_MAC_PROFILES);
11109 WARN_ON(!idr_is_empty(&mlxsw_sp->router->rif_mac_profiles_idr));
11110 idr_destroy(&mlxsw_sp->router->rif_mac_profiles_idr);
11111 mlxsw_sp_rifs_table_fini(mlxsw_sp);
11112 kfree(mlxsw_sp->router->rifs);
11113 }
11114
11115 static int
mlxsw_sp_ipip_config_tigcr(struct mlxsw_sp * mlxsw_sp)11116 mlxsw_sp_ipip_config_tigcr(struct mlxsw_sp *mlxsw_sp)
11117 {
11118 char tigcr_pl[MLXSW_REG_TIGCR_LEN];
11119
11120 mlxsw_reg_tigcr_pack(tigcr_pl, true, 0);
11121 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tigcr), tigcr_pl);
11122 }
11123
mlxsw_sp_ipips_init(struct mlxsw_sp * mlxsw_sp)11124 static int mlxsw_sp_ipips_init(struct mlxsw_sp *mlxsw_sp)
11125 {
11126 int err;
11127
11128 INIT_LIST_HEAD(&mlxsw_sp->router->ipip_list);
11129
11130 err = mlxsw_sp_ipip_ecn_encap_init(mlxsw_sp);
11131 if (err)
11132 return err;
11133 err = mlxsw_sp_ipip_ecn_decap_init(mlxsw_sp);
11134 if (err)
11135 return err;
11136
11137 return mlxsw_sp_ipip_config_tigcr(mlxsw_sp);
11138 }
11139
mlxsw_sp1_ipips_init(struct mlxsw_sp * mlxsw_sp)11140 static int mlxsw_sp1_ipips_init(struct mlxsw_sp *mlxsw_sp)
11141 {
11142 mlxsw_sp->router->ipip_ops_arr = mlxsw_sp1_ipip_ops_arr;
11143 return mlxsw_sp_ipips_init(mlxsw_sp);
11144 }
11145
mlxsw_sp2_ipips_init(struct mlxsw_sp * mlxsw_sp)11146 static int mlxsw_sp2_ipips_init(struct mlxsw_sp *mlxsw_sp)
11147 {
11148 mlxsw_sp->router->ipip_ops_arr = mlxsw_sp2_ipip_ops_arr;
11149 return mlxsw_sp_ipips_init(mlxsw_sp);
11150 }
11151
mlxsw_sp_ipips_fini(struct mlxsw_sp * mlxsw_sp)11152 static void mlxsw_sp_ipips_fini(struct mlxsw_sp *mlxsw_sp)
11153 {
11154 WARN_ON(!list_empty(&mlxsw_sp->router->ipip_list));
11155 }
11156
mlxsw_sp_router_fib_dump_flush(struct notifier_block * nb)11157 static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
11158 {
11159 struct mlxsw_sp_router *router;
11160
11161 /* Flush pending FIB notifications and then flush the device's
11162 * table before requesting another dump. The FIB notification
11163 * block is unregistered, so no need to take RTNL.
11164 */
11165 mlxsw_core_flush_owq();
11166 router = container_of(nb, struct mlxsw_sp_router, fib_nb);
11167 mlxsw_sp_router_fib_flush(router->mlxsw_sp);
11168 }
11169
11170 #ifdef CONFIG_IP_ROUTE_MULTIPATH
11171 struct mlxsw_sp_mp_hash_config {
11172 DECLARE_BITMAP(headers, __MLXSW_REG_RECR2_HEADER_CNT);
11173 DECLARE_BITMAP(fields, __MLXSW_REG_RECR2_FIELD_CNT);
11174 DECLARE_BITMAP(inner_headers, __MLXSW_REG_RECR2_HEADER_CNT);
11175 DECLARE_BITMAP(inner_fields, __MLXSW_REG_RECR2_INNER_FIELD_CNT);
11176 bool inc_parsing_depth;
11177 };
11178
11179 #define MLXSW_SP_MP_HASH_HEADER_SET(_headers, _header) \
11180 bitmap_set(_headers, MLXSW_REG_RECR2_##_header, 1)
11181
11182 #define MLXSW_SP_MP_HASH_FIELD_SET(_fields, _field) \
11183 bitmap_set(_fields, MLXSW_REG_RECR2_##_field, 1)
11184
11185 #define MLXSW_SP_MP_HASH_FIELD_RANGE_SET(_fields, _field, _nr) \
11186 bitmap_set(_fields, MLXSW_REG_RECR2_##_field, _nr)
11187
mlxsw_sp_mp_hash_inner_l3(struct mlxsw_sp_mp_hash_config * config)11188 static void mlxsw_sp_mp_hash_inner_l3(struct mlxsw_sp_mp_hash_config *config)
11189 {
11190 unsigned long *inner_headers = config->inner_headers;
11191 unsigned long *inner_fields = config->inner_fields;
11192
11193 /* IPv4 inner */
11194 MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_NOT_TCP_NOT_UDP);
11195 MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_TCP_UDP);
11196 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_SIP0, 4);
11197 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_DIP0, 4);
11198 /* IPv6 inner */
11199 MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_NOT_TCP_NOT_UDP);
11200 MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_TCP_UDP);
11201 MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_SIP0_7);
11202 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_SIP8, 8);
11203 MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_DIP0_7);
11204 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_DIP8, 8);
11205 MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_NEXT_HEADER);
11206 MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_FLOW_LABEL);
11207 }
11208
mlxsw_sp_mp4_hash_outer_addr(struct mlxsw_sp_mp_hash_config * config)11209 static void mlxsw_sp_mp4_hash_outer_addr(struct mlxsw_sp_mp_hash_config *config)
11210 {
11211 unsigned long *headers = config->headers;
11212 unsigned long *fields = config->fields;
11213
11214 MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_NOT_TCP_NOT_UDP);
11215 MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_TCP_UDP);
11216 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_SIP0, 4);
11217 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_DIP0, 4);
11218 }
11219
11220 static void
mlxsw_sp_mp_hash_inner_custom(struct mlxsw_sp_mp_hash_config * config,u32 hash_fields)11221 mlxsw_sp_mp_hash_inner_custom(struct mlxsw_sp_mp_hash_config *config,
11222 u32 hash_fields)
11223 {
11224 unsigned long *inner_headers = config->inner_headers;
11225 unsigned long *inner_fields = config->inner_fields;
11226
11227 /* IPv4 Inner */
11228 MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_NOT_TCP_NOT_UDP);
11229 MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_TCP_UDP);
11230 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP)
11231 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_SIP0, 4);
11232 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP)
11233 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_DIP0, 4);
11234 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_IP_PROTO)
11235 MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV4_PROTOCOL);
11236 /* IPv6 inner */
11237 MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_NOT_TCP_NOT_UDP);
11238 MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_TCP_UDP);
11239 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP) {
11240 MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_SIP0_7);
11241 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_SIP8, 8);
11242 }
11243 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP) {
11244 MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_DIP0_7);
11245 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_DIP8, 8);
11246 }
11247 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_IP_PROTO)
11248 MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_NEXT_HEADER);
11249 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_FLOWLABEL)
11250 MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_FLOW_LABEL);
11251 /* L4 inner */
11252 MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, TCP_UDP_EN_IPV4);
11253 MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, TCP_UDP_EN_IPV6);
11254 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_PORT)
11255 MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_TCP_UDP_SPORT);
11256 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_PORT)
11257 MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_TCP_UDP_DPORT);
11258 }
11259
mlxsw_sp_mp4_hash_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_mp_hash_config * config)11260 static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp,
11261 struct mlxsw_sp_mp_hash_config *config)
11262 {
11263 struct net *net = mlxsw_sp_net(mlxsw_sp);
11264 unsigned long *headers = config->headers;
11265 unsigned long *fields = config->fields;
11266 u32 hash_fields;
11267
11268 switch (READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_policy)) {
11269 case 0:
11270 mlxsw_sp_mp4_hash_outer_addr(config);
11271 break;
11272 case 1:
11273 mlxsw_sp_mp4_hash_outer_addr(config);
11274 MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV4);
11275 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV4_PROTOCOL);
11276 MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
11277 MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
11278 break;
11279 case 2:
11280 /* Outer */
11281 mlxsw_sp_mp4_hash_outer_addr(config);
11282 /* Inner */
11283 mlxsw_sp_mp_hash_inner_l3(config);
11284 break;
11285 case 3:
11286 hash_fields = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_fields);
11287 /* Outer */
11288 MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_NOT_TCP_NOT_UDP);
11289 MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_TCP_UDP);
11290 MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV4);
11291 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_IP)
11292 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_SIP0, 4);
11293 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_IP)
11294 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_DIP0, 4);
11295 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_IP_PROTO)
11296 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV4_PROTOCOL);
11297 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_PORT)
11298 MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
11299 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_PORT)
11300 MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
11301 /* Inner */
11302 mlxsw_sp_mp_hash_inner_custom(config, hash_fields);
11303 break;
11304 }
11305 }
11306
mlxsw_sp_mp6_hash_outer_addr(struct mlxsw_sp_mp_hash_config * config)11307 static void mlxsw_sp_mp6_hash_outer_addr(struct mlxsw_sp_mp_hash_config *config)
11308 {
11309 unsigned long *headers = config->headers;
11310 unsigned long *fields = config->fields;
11311
11312 MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_NOT_TCP_NOT_UDP);
11313 MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_TCP_UDP);
11314 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_SIP0_7);
11315 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_SIP8, 8);
11316 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_DIP0_7);
11317 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_DIP8, 8);
11318 }
11319
mlxsw_sp_mp6_hash_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_mp_hash_config * config)11320 static void mlxsw_sp_mp6_hash_init(struct mlxsw_sp *mlxsw_sp,
11321 struct mlxsw_sp_mp_hash_config *config)
11322 {
11323 u32 hash_fields = ip6_multipath_hash_fields(mlxsw_sp_net(mlxsw_sp));
11324 unsigned long *headers = config->headers;
11325 unsigned long *fields = config->fields;
11326
11327 switch (ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp))) {
11328 case 0:
11329 mlxsw_sp_mp6_hash_outer_addr(config);
11330 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
11331 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_FLOW_LABEL);
11332 break;
11333 case 1:
11334 mlxsw_sp_mp6_hash_outer_addr(config);
11335 MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV6);
11336 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
11337 MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
11338 MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
11339 break;
11340 case 2:
11341 /* Outer */
11342 mlxsw_sp_mp6_hash_outer_addr(config);
11343 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
11344 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_FLOW_LABEL);
11345 /* Inner */
11346 mlxsw_sp_mp_hash_inner_l3(config);
11347 config->inc_parsing_depth = true;
11348 break;
11349 case 3:
11350 /* Outer */
11351 MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_NOT_TCP_NOT_UDP);
11352 MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_TCP_UDP);
11353 MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV6);
11354 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_IP) {
11355 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_SIP0_7);
11356 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_SIP8, 8);
11357 }
11358 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_IP) {
11359 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_DIP0_7);
11360 MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_DIP8, 8);
11361 }
11362 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_IP_PROTO)
11363 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
11364 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_FLOWLABEL)
11365 MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_FLOW_LABEL);
11366 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_PORT)
11367 MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
11368 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_PORT)
11369 MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
11370 /* Inner */
11371 mlxsw_sp_mp_hash_inner_custom(config, hash_fields);
11372 if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_MASK)
11373 config->inc_parsing_depth = true;
11374 break;
11375 }
11376 }
11377
mlxsw_sp_mp_hash_parsing_depth_adjust(struct mlxsw_sp * mlxsw_sp,bool old_inc_parsing_depth,bool new_inc_parsing_depth)11378 static int mlxsw_sp_mp_hash_parsing_depth_adjust(struct mlxsw_sp *mlxsw_sp,
11379 bool old_inc_parsing_depth,
11380 bool new_inc_parsing_depth)
11381 {
11382 int err;
11383
11384 if (!old_inc_parsing_depth && new_inc_parsing_depth) {
11385 err = mlxsw_sp_parsing_depth_inc(mlxsw_sp);
11386 if (err)
11387 return err;
11388 mlxsw_sp->router->inc_parsing_depth = true;
11389 } else if (old_inc_parsing_depth && !new_inc_parsing_depth) {
11390 mlxsw_sp_parsing_depth_dec(mlxsw_sp);
11391 mlxsw_sp->router->inc_parsing_depth = false;
11392 }
11393
11394 return 0;
11395 }
11396
mlxsw_sp_mp_hash_init(struct mlxsw_sp * mlxsw_sp)11397 static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp)
11398 {
11399 bool old_inc_parsing_depth, new_inc_parsing_depth;
11400 struct mlxsw_sp_mp_hash_config config = {};
11401 struct net *net = mlxsw_sp_net(mlxsw_sp);
11402 char recr2_pl[MLXSW_REG_RECR2_LEN];
11403 unsigned long bit;
11404 u32 seed;
11405 int err;
11406
11407 seed = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_seed).user_seed;
11408 if (!seed)
11409 seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0);
11410
11411 mlxsw_reg_recr2_pack(recr2_pl, seed);
11412 mlxsw_sp_mp4_hash_init(mlxsw_sp, &config);
11413 mlxsw_sp_mp6_hash_init(mlxsw_sp, &config);
11414
11415 old_inc_parsing_depth = mlxsw_sp->router->inc_parsing_depth;
11416 new_inc_parsing_depth = config.inc_parsing_depth;
11417 err = mlxsw_sp_mp_hash_parsing_depth_adjust(mlxsw_sp,
11418 old_inc_parsing_depth,
11419 new_inc_parsing_depth);
11420 if (err)
11421 return err;
11422
11423 for_each_set_bit(bit, config.headers, __MLXSW_REG_RECR2_HEADER_CNT)
11424 mlxsw_reg_recr2_outer_header_enables_set(recr2_pl, bit, 1);
11425 for_each_set_bit(bit, config.fields, __MLXSW_REG_RECR2_FIELD_CNT)
11426 mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, bit, 1);
11427 for_each_set_bit(bit, config.inner_headers, __MLXSW_REG_RECR2_HEADER_CNT)
11428 mlxsw_reg_recr2_inner_header_enables_set(recr2_pl, bit, 1);
11429 for_each_set_bit(bit, config.inner_fields, __MLXSW_REG_RECR2_INNER_FIELD_CNT)
11430 mlxsw_reg_recr2_inner_header_fields_enable_set(recr2_pl, bit, 1);
11431
11432 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(recr2), recr2_pl);
11433 if (err)
11434 goto err_reg_write;
11435
11436 return 0;
11437
11438 err_reg_write:
11439 mlxsw_sp_mp_hash_parsing_depth_adjust(mlxsw_sp, new_inc_parsing_depth,
11440 old_inc_parsing_depth);
11441 return err;
11442 }
11443
mlxsw_sp_mp_hash_fini(struct mlxsw_sp * mlxsw_sp)11444 static void mlxsw_sp_mp_hash_fini(struct mlxsw_sp *mlxsw_sp)
11445 {
11446 bool old_inc_parsing_depth = mlxsw_sp->router->inc_parsing_depth;
11447
11448 mlxsw_sp_mp_hash_parsing_depth_adjust(mlxsw_sp, old_inc_parsing_depth,
11449 false);
11450 }
11451 #else
mlxsw_sp_mp_hash_init(struct mlxsw_sp * mlxsw_sp)11452 static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp)
11453 {
11454 return 0;
11455 }
11456
mlxsw_sp_mp_hash_fini(struct mlxsw_sp * mlxsw_sp)11457 static void mlxsw_sp_mp_hash_fini(struct mlxsw_sp *mlxsw_sp)
11458 {
11459 }
11460 #endif
11461
mlxsw_sp_dscp_init(struct mlxsw_sp * mlxsw_sp)11462 static int mlxsw_sp_dscp_init(struct mlxsw_sp *mlxsw_sp)
11463 {
11464 char rdpm_pl[MLXSW_REG_RDPM_LEN];
11465 unsigned int i;
11466
11467 MLXSW_REG_ZERO(rdpm, rdpm_pl);
11468
11469 /* HW is determining switch priority based on DSCP-bits, but the
11470 * kernel is still doing that based on the ToS. Since there's a
11471 * mismatch in bits we need to make sure to translate the right
11472 * value ToS would observe, skipping the 2 least-significant ECN bits.
11473 */
11474 for (i = 0; i < MLXSW_REG_RDPM_DSCP_ENTRY_REC_MAX_COUNT; i++)
11475 mlxsw_reg_rdpm_pack(rdpm_pl, i, rt_tos2priority(i << 2));
11476
11477 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rdpm), rdpm_pl);
11478 }
11479
__mlxsw_sp_router_init(struct mlxsw_sp * mlxsw_sp)11480 static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
11481 {
11482 struct net *net = mlxsw_sp_net(mlxsw_sp);
11483 char rgcr_pl[MLXSW_REG_RGCR_LEN];
11484 u64 max_rifs;
11485 bool usp;
11486
11487 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_RIFS))
11488 return -EIO;
11489 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
11490 usp = READ_ONCE(net->ipv4.sysctl_ip_fwd_update_priority);
11491
11492 mlxsw_reg_rgcr_pack(rgcr_pl, true, true);
11493 mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, max_rifs);
11494 mlxsw_reg_rgcr_usp_set(rgcr_pl, usp);
11495 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
11496 }
11497
__mlxsw_sp_router_fini(struct mlxsw_sp * mlxsw_sp)11498 static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
11499 {
11500 char rgcr_pl[MLXSW_REG_RGCR_LEN];
11501
11502 mlxsw_reg_rgcr_pack(rgcr_pl, false, false);
11503 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
11504 }
11505
mlxsw_sp_lb_rif_init(struct mlxsw_sp * mlxsw_sp,struct netlink_ext_ack * extack)11506 static int mlxsw_sp_lb_rif_init(struct mlxsw_sp *mlxsw_sp,
11507 struct netlink_ext_ack *extack)
11508 {
11509 struct mlxsw_sp_router *router = mlxsw_sp->router;
11510 struct mlxsw_sp_rif *lb_rif;
11511 int err;
11512
11513 router->lb_crif = mlxsw_sp_crif_alloc(NULL);
11514 if (!router->lb_crif)
11515 return -ENOMEM;
11516
11517 /* Create a generic loopback RIF associated with the main table
11518 * (default VRF). Any table can be used, but the main table exists
11519 * anyway, so we do not waste resources. Loopback RIFs are usually
11520 * created with a NULL CRIF, but this RIF is used as a fallback RIF
11521 * for blackhole nexthops, and nexthops expect to have a valid CRIF.
11522 */
11523 lb_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, RT_TABLE_MAIN, router->lb_crif,
11524 extack);
11525 if (IS_ERR(lb_rif)) {
11526 err = PTR_ERR(lb_rif);
11527 goto err_ul_rif_get;
11528 }
11529
11530 return 0;
11531
11532 err_ul_rif_get:
11533 mlxsw_sp_crif_free(router->lb_crif);
11534 return err;
11535 }
11536
mlxsw_sp_lb_rif_fini(struct mlxsw_sp * mlxsw_sp)11537 static void mlxsw_sp_lb_rif_fini(struct mlxsw_sp *mlxsw_sp)
11538 {
11539 mlxsw_sp_ul_rif_put(mlxsw_sp->router->lb_crif->rif);
11540 mlxsw_sp_crif_free(mlxsw_sp->router->lb_crif);
11541 }
11542
mlxsw_sp1_router_init(struct mlxsw_sp * mlxsw_sp)11543 static int mlxsw_sp1_router_init(struct mlxsw_sp *mlxsw_sp)
11544 {
11545 size_t size_ranges_count = ARRAY_SIZE(mlxsw_sp1_adj_grp_size_ranges);
11546
11547 mlxsw_sp->router->rif_ops_arr = mlxsw_sp1_rif_ops_arr;
11548 mlxsw_sp->router->adj_grp_size_ranges = mlxsw_sp1_adj_grp_size_ranges;
11549 mlxsw_sp->router->adj_grp_size_ranges_count = size_ranges_count;
11550
11551 return 0;
11552 }
11553
11554 const struct mlxsw_sp_router_ops mlxsw_sp1_router_ops = {
11555 .init = mlxsw_sp1_router_init,
11556 .ipips_init = mlxsw_sp1_ipips_init,
11557 };
11558
mlxsw_sp2_router_init(struct mlxsw_sp * mlxsw_sp)11559 static int mlxsw_sp2_router_init(struct mlxsw_sp *mlxsw_sp)
11560 {
11561 size_t size_ranges_count = ARRAY_SIZE(mlxsw_sp2_adj_grp_size_ranges);
11562
11563 mlxsw_sp->router->rif_ops_arr = mlxsw_sp2_rif_ops_arr;
11564 mlxsw_sp->router->adj_grp_size_ranges = mlxsw_sp2_adj_grp_size_ranges;
11565 mlxsw_sp->router->adj_grp_size_ranges_count = size_ranges_count;
11566
11567 return 0;
11568 }
11569
11570 const struct mlxsw_sp_router_ops mlxsw_sp2_router_ops = {
11571 .init = mlxsw_sp2_router_init,
11572 .ipips_init = mlxsw_sp2_ipips_init,
11573 };
11574
mlxsw_sp_router_init(struct mlxsw_sp * mlxsw_sp,struct netlink_ext_ack * extack)11575 int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
11576 struct netlink_ext_ack *extack)
11577 {
11578 struct mlxsw_sp_router *router;
11579 struct notifier_block *nb;
11580 int err;
11581
11582 router = kzalloc_obj(*mlxsw_sp->router);
11583 if (!router)
11584 return -ENOMEM;
11585 mutex_init(&router->lock);
11586 mlxsw_sp->router = router;
11587 router->mlxsw_sp = mlxsw_sp;
11588
11589 err = mlxsw_sp->router_ops->init(mlxsw_sp);
11590 if (err)
11591 goto err_router_ops_init;
11592
11593 INIT_LIST_HEAD(&mlxsw_sp->router->nh_res_grp_list);
11594 INIT_DELAYED_WORK(&mlxsw_sp->router->nh_grp_activity_dw,
11595 mlxsw_sp_nh_grp_activity_work);
11596 INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list);
11597 err = __mlxsw_sp_router_init(mlxsw_sp);
11598 if (err)
11599 goto err_router_init;
11600
11601 err = mlxsw_sp->router_ops->ipips_init(mlxsw_sp);
11602 if (err)
11603 goto err_ipips_init;
11604
11605 err = rhashtable_init(&mlxsw_sp->router->crif_ht,
11606 &mlxsw_sp_crif_ht_params);
11607 if (err)
11608 goto err_crif_ht_init;
11609
11610 err = mlxsw_sp_rifs_init(mlxsw_sp);
11611 if (err)
11612 goto err_rifs_init;
11613
11614 err = rhashtable_init(&mlxsw_sp->router->nexthop_ht,
11615 &mlxsw_sp_nexthop_ht_params);
11616 if (err)
11617 goto err_nexthop_ht_init;
11618
11619 err = rhashtable_init(&mlxsw_sp->router->nexthop_group_ht,
11620 &mlxsw_sp_nexthop_group_ht_params);
11621 if (err)
11622 goto err_nexthop_group_ht_init;
11623
11624 INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_list);
11625 err = mlxsw_sp_lpm_init(mlxsw_sp);
11626 if (err)
11627 goto err_lpm_init;
11628
11629 err = mlxsw_sp_mr_init(mlxsw_sp, &mlxsw_sp_mr_tcam_ops);
11630 if (err)
11631 goto err_mr_init;
11632
11633 err = mlxsw_sp_vrs_init(mlxsw_sp);
11634 if (err)
11635 goto err_vrs_init;
11636
11637 err = mlxsw_sp_lb_rif_init(mlxsw_sp, extack);
11638 if (err)
11639 goto err_lb_rif_init;
11640
11641 err = mlxsw_sp_neigh_init(mlxsw_sp);
11642 if (err)
11643 goto err_neigh_init;
11644
11645 err = mlxsw_sp_mp_hash_init(mlxsw_sp);
11646 if (err)
11647 goto err_mp_hash_init;
11648
11649 err = mlxsw_sp_dscp_init(mlxsw_sp);
11650 if (err)
11651 goto err_dscp_init;
11652
11653 router->inetaddr_nb.notifier_call = mlxsw_sp_inetaddr_event;
11654 err = register_inetaddr_notifier(&router->inetaddr_nb);
11655 if (err)
11656 goto err_register_inetaddr_notifier;
11657
11658 router->inet6addr_nb.notifier_call = mlxsw_sp_inet6addr_event;
11659 err = register_inet6addr_notifier(&router->inet6addr_nb);
11660 if (err)
11661 goto err_register_inet6addr_notifier;
11662
11663 router->inetaddr_valid_nb.notifier_call = mlxsw_sp_inetaddr_valid_event;
11664 err = register_inetaddr_validator_notifier(&router->inetaddr_valid_nb);
11665 if (err)
11666 goto err_register_inetaddr_valid_notifier;
11667
11668 nb = &router->inet6addr_valid_nb;
11669 nb->notifier_call = mlxsw_sp_inet6addr_valid_event;
11670 err = register_inet6addr_validator_notifier(nb);
11671 if (err)
11672 goto err_register_inet6addr_valid_notifier;
11673
11674 mlxsw_sp->router->netevent_nb.notifier_call =
11675 mlxsw_sp_router_netevent_event;
11676 err = register_netevent_notifier(&mlxsw_sp->router->netevent_nb);
11677 if (err)
11678 goto err_register_netevent_notifier;
11679
11680 mlxsw_sp->router->netdevice_nb.notifier_call =
11681 mlxsw_sp_router_netdevice_event;
11682 err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
11683 &mlxsw_sp->router->netdevice_nb);
11684 if (err)
11685 goto err_register_netdev_notifier;
11686
11687 mlxsw_sp->router->nexthop_nb.notifier_call =
11688 mlxsw_sp_nexthop_obj_event;
11689 err = register_nexthop_notifier(mlxsw_sp_net(mlxsw_sp),
11690 &mlxsw_sp->router->nexthop_nb,
11691 extack);
11692 if (err)
11693 goto err_register_nexthop_notifier;
11694
11695 mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event;
11696 err = register_fib_notifier(mlxsw_sp_net(mlxsw_sp),
11697 &mlxsw_sp->router->fib_nb,
11698 mlxsw_sp_router_fib_dump_flush, extack);
11699 if (err)
11700 goto err_register_fib_notifier;
11701
11702 return 0;
11703
11704 err_register_fib_notifier:
11705 unregister_nexthop_notifier(mlxsw_sp_net(mlxsw_sp),
11706 &mlxsw_sp->router->nexthop_nb);
11707 err_register_nexthop_notifier:
11708 unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
11709 &router->netdevice_nb);
11710 err_register_netdev_notifier:
11711 unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb);
11712 err_register_netevent_notifier:
11713 unregister_inet6addr_validator_notifier(&router->inet6addr_valid_nb);
11714 err_register_inet6addr_valid_notifier:
11715 unregister_inetaddr_validator_notifier(&router->inetaddr_valid_nb);
11716 err_register_inetaddr_valid_notifier:
11717 unregister_inet6addr_notifier(&router->inet6addr_nb);
11718 err_register_inet6addr_notifier:
11719 unregister_inetaddr_notifier(&router->inetaddr_nb);
11720 err_register_inetaddr_notifier:
11721 mlxsw_core_flush_owq();
11722 err_dscp_init:
11723 mlxsw_sp_mp_hash_fini(mlxsw_sp);
11724 err_mp_hash_init:
11725 mlxsw_sp_neigh_fini(mlxsw_sp);
11726 err_neigh_init:
11727 mlxsw_sp_lb_rif_fini(mlxsw_sp);
11728 err_lb_rif_init:
11729 mlxsw_sp_vrs_fini(mlxsw_sp);
11730 err_vrs_init:
11731 mlxsw_sp_mr_fini(mlxsw_sp);
11732 err_mr_init:
11733 mlxsw_sp_lpm_fini(mlxsw_sp);
11734 err_lpm_init:
11735 rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht);
11736 err_nexthop_group_ht_init:
11737 rhashtable_destroy(&mlxsw_sp->router->nexthop_ht);
11738 err_nexthop_ht_init:
11739 mlxsw_sp_rifs_fini(mlxsw_sp);
11740 err_rifs_init:
11741 rhashtable_destroy(&mlxsw_sp->router->crif_ht);
11742 err_crif_ht_init:
11743 mlxsw_sp_ipips_fini(mlxsw_sp);
11744 err_ipips_init:
11745 __mlxsw_sp_router_fini(mlxsw_sp);
11746 err_router_init:
11747 cancel_delayed_work_sync(&mlxsw_sp->router->nh_grp_activity_dw);
11748 err_router_ops_init:
11749 mutex_destroy(&mlxsw_sp->router->lock);
11750 kfree(mlxsw_sp->router);
11751 return err;
11752 }
11753
mlxsw_sp_router_fini(struct mlxsw_sp * mlxsw_sp)11754 void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
11755 {
11756 struct mlxsw_sp_router *router = mlxsw_sp->router;
11757
11758 unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp), &router->fib_nb);
11759 unregister_nexthop_notifier(mlxsw_sp_net(mlxsw_sp),
11760 &router->nexthop_nb);
11761 unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
11762 &router->netdevice_nb);
11763 unregister_netevent_notifier(&router->netevent_nb);
11764 unregister_inet6addr_validator_notifier(&router->inet6addr_valid_nb);
11765 unregister_inetaddr_validator_notifier(&router->inetaddr_valid_nb);
11766 unregister_inet6addr_notifier(&router->inet6addr_nb);
11767 unregister_inetaddr_notifier(&router->inetaddr_nb);
11768 mlxsw_core_flush_owq();
11769 mlxsw_sp_mp_hash_fini(mlxsw_sp);
11770 mlxsw_sp_neigh_fini(mlxsw_sp);
11771 mlxsw_sp_lb_rif_fini(mlxsw_sp);
11772 mlxsw_sp_vrs_fini(mlxsw_sp);
11773 mlxsw_sp_mr_fini(mlxsw_sp);
11774 mlxsw_sp_lpm_fini(mlxsw_sp);
11775 rhashtable_destroy(&router->nexthop_group_ht);
11776 rhashtable_destroy(&router->nexthop_ht);
11777 mlxsw_sp_rifs_fini(mlxsw_sp);
11778 rhashtable_destroy(&mlxsw_sp->router->crif_ht);
11779 mlxsw_sp_ipips_fini(mlxsw_sp);
11780 __mlxsw_sp_router_fini(mlxsw_sp);
11781 cancel_delayed_work_sync(&router->nh_grp_activity_dw);
11782 mutex_destroy(&router->lock);
11783 kfree(router);
11784 }
11785