]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
mlxsw: spectrum_router: Store NVE decapsulation configuration in router
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_router.c
CommitLineData
9948a064
JP
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
464dce18
IS
3
4#include <linux/kernel.h>
5#include <linux/types.h>
5e9c16cc
JP
6#include <linux/rhashtable.h>
7#include <linux/bitops.h>
8#include <linux/in6.h>
c723c735 9#include <linux/notifier.h>
df6dd79b 10#include <linux/inetdevice.h>
9db032bb 11#include <linux/netdevice.h>
03ea01e9 12#include <linux/if_bridge.h>
b5f3e0d4 13#include <linux/socket.h>
428b851f 14#include <linux/route.h>
eb789980 15#include <linux/gcd.h>
2db99378 16#include <linux/if_macvlan.h>
32fd4b49 17#include <linux/refcount.h>
fa73989f 18#include <linux/jhash.h>
053e92aa 19#include <linux/net_namespace.h>
c723c735 20#include <net/netevent.h>
6cf3c971
JP
21#include <net/neighbour.h>
22#include <net/arp.h>
b45f64d1 23#include <net/ip_fib.h>
583419fd 24#include <net/ip6_fib.h>
5481d73f 25#include <net/nexthop.h>
5d7bfd14 26#include <net/fib_rules.h>
6ddb7426 27#include <net/ip_tunnels.h>
57837885 28#include <net/l3mdev.h>
5ea1237f 29#include <net/addrconf.h>
d5eb89cf
AS
30#include <net/ndisc.h>
31#include <net/ipv6.h>
04b1d4e5 32#include <net/fib_notifier.h>
2db99378 33#include <net/switchdev.h>
464dce18
IS
34
35#include "spectrum.h"
36#include "core.h"
37#include "reg.h"
e0c0afd8
AS
38#include "spectrum_cnt.h"
39#include "spectrum_dpipe.h"
38ebc0f4 40#include "spectrum_ipip.h"
d42b0965
YG
41#include "spectrum_mr.h"
42#include "spectrum_mr_tcam.h"
e0c0afd8 43#include "spectrum_router.h"
803335ac 44#include "spectrum_span.h"
464dce18 45
2b52ce02 46struct mlxsw_sp_fib;
9011b677
IS
47struct mlxsw_sp_vr;
48struct mlxsw_sp_lpm_tree;
e4f3c1c1 49struct mlxsw_sp_rif_ops;
9011b677 50
4724ba56
IS
51struct mlxsw_sp_rif {
52 struct list_head nexthop_list;
53 struct list_head neigh_list;
73b8f493 54 struct net_device *dev; /* NULL for underlay RIF */
a1107487 55 struct mlxsw_sp_fid *fid;
4724ba56
IS
56 unsigned char addr[ETH_ALEN];
57 int mtu;
bf95233e 58 u16 rif_index;
6913229e 59 u16 vr_id;
e4f3c1c1
IS
60 const struct mlxsw_sp_rif_ops *ops;
61 struct mlxsw_sp *mlxsw_sp;
62
e0c0afd8
AS
63 unsigned int counter_ingress;
64 bool counter_ingress_valid;
65 unsigned int counter_egress;
66 bool counter_egress_valid;
4724ba56
IS
67};
68
e4f3c1c1
IS
69struct mlxsw_sp_rif_params {
70 struct net_device *dev;
71 union {
72 u16 system_port;
73 u16 lag_id;
74 };
75 u16 vid;
76 bool lag;
77};
78
4d93ceeb
IS
79struct mlxsw_sp_rif_subport {
80 struct mlxsw_sp_rif common;
32fd4b49 81 refcount_t ref_count;
4d93ceeb
IS
82 union {
83 u16 system_port;
84 u16 lag_id;
85 };
86 u16 vid;
87 bool lag;
88};
89
6ddb7426
PM
90struct mlxsw_sp_rif_ipip_lb {
91 struct mlxsw_sp_rif common;
92 struct mlxsw_sp_rif_ipip_lb_config lb_config;
93 u16 ul_vr_id; /* Reserved for Spectrum-2. */
25f844dd 94 u16 ul_rif_id; /* Reserved for Spectrum. */
6ddb7426
PM
95};
96
97struct mlxsw_sp_rif_params_ipip_lb {
98 struct mlxsw_sp_rif_params common;
99 struct mlxsw_sp_rif_ipip_lb_config lb_config;
100};
101
e4f3c1c1
IS
102struct mlxsw_sp_rif_ops {
103 enum mlxsw_sp_rif_type type;
104 size_t rif_size;
105
106 void (*setup)(struct mlxsw_sp_rif *rif,
107 const struct mlxsw_sp_rif_params *params);
108 int (*configure)(struct mlxsw_sp_rif *rif);
109 void (*deconfigure)(struct mlxsw_sp_rif *rif);
5f15e257
PM
110 struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif,
111 struct netlink_ext_ack *extack);
2db99378 112 void (*fdb_del)(struct mlxsw_sp_rif *rif, const char *mac);
e4f3c1c1
IS
113};
114
b69e1337
IS
115static struct mlxsw_sp_rif *
116mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
117 const struct net_device *dev);
32fd4b49 118static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif);
2b52ce02
IS
119static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree);
120static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
121 struct mlxsw_sp_lpm_tree *lpm_tree);
122static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
123 const struct mlxsw_sp_fib *fib,
124 u8 tree_id);
125static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
126 const struct mlxsw_sp_fib *fib);
127
e0c0afd8
AS
128static unsigned int *
129mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif,
130 enum mlxsw_sp_rif_counter_dir dir)
131{
132 switch (dir) {
133 case MLXSW_SP_RIF_COUNTER_EGRESS:
134 return &rif->counter_egress;
135 case MLXSW_SP_RIF_COUNTER_INGRESS:
136 return &rif->counter_ingress;
137 }
138 return NULL;
139}
140
141static bool
142mlxsw_sp_rif_counter_valid_get(struct mlxsw_sp_rif *rif,
143 enum mlxsw_sp_rif_counter_dir dir)
144{
145 switch (dir) {
146 case MLXSW_SP_RIF_COUNTER_EGRESS:
147 return rif->counter_egress_valid;
148 case MLXSW_SP_RIF_COUNTER_INGRESS:
149 return rif->counter_ingress_valid;
150 }
151 return false;
152}
153
154static void
155mlxsw_sp_rif_counter_valid_set(struct mlxsw_sp_rif *rif,
156 enum mlxsw_sp_rif_counter_dir dir,
157 bool valid)
158{
159 switch (dir) {
160 case MLXSW_SP_RIF_COUNTER_EGRESS:
161 rif->counter_egress_valid = valid;
162 break;
163 case MLXSW_SP_RIF_COUNTER_INGRESS:
164 rif->counter_ingress_valid = valid;
165 break;
166 }
167}
168
169static int mlxsw_sp_rif_counter_edit(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
170 unsigned int counter_index, bool enable,
171 enum mlxsw_sp_rif_counter_dir dir)
172{
173 char ritr_pl[MLXSW_REG_RITR_LEN];
174 bool is_egress = false;
175 int err;
176
177 if (dir == MLXSW_SP_RIF_COUNTER_EGRESS)
178 is_egress = true;
179 mlxsw_reg_ritr_rif_pack(ritr_pl, rif_index);
180 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
181 if (err)
182 return err;
183
184 mlxsw_reg_ritr_counter_pack(ritr_pl, counter_index, enable,
185 is_egress);
186 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
187}
188
189int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp *mlxsw_sp,
190 struct mlxsw_sp_rif *rif,
191 enum mlxsw_sp_rif_counter_dir dir, u64 *cnt)
192{
193 char ricnt_pl[MLXSW_REG_RICNT_LEN];
194 unsigned int *p_counter_index;
195 bool valid;
196 int err;
197
198 valid = mlxsw_sp_rif_counter_valid_get(rif, dir);
199 if (!valid)
200 return -EINVAL;
201
202 p_counter_index = mlxsw_sp_rif_p_counter_get(rif, dir);
203 if (!p_counter_index)
204 return -EINVAL;
205 mlxsw_reg_ricnt_pack(ricnt_pl, *p_counter_index,
206 MLXSW_REG_RICNT_OPCODE_NOP);
207 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ricnt), ricnt_pl);
208 if (err)
209 return err;
210 *cnt = mlxsw_reg_ricnt_good_unicast_packets_get(ricnt_pl);
211 return 0;
212}
213
214static int mlxsw_sp_rif_counter_clear(struct mlxsw_sp *mlxsw_sp,
215 unsigned int counter_index)
216{
217 char ricnt_pl[MLXSW_REG_RICNT_LEN];
218
219 mlxsw_reg_ricnt_pack(ricnt_pl, counter_index,
220 MLXSW_REG_RICNT_OPCODE_CLEAR);
221 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ricnt), ricnt_pl);
222}
223
224int mlxsw_sp_rif_counter_alloc(struct mlxsw_sp *mlxsw_sp,
225 struct mlxsw_sp_rif *rif,
226 enum mlxsw_sp_rif_counter_dir dir)
227{
228 unsigned int *p_counter_index;
229 int err;
230
231 p_counter_index = mlxsw_sp_rif_p_counter_get(rif, dir);
232 if (!p_counter_index)
233 return -EINVAL;
234 err = mlxsw_sp_counter_alloc(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_RIF,
235 p_counter_index);
236 if (err)
237 return err;
238
239 err = mlxsw_sp_rif_counter_clear(mlxsw_sp, *p_counter_index);
240 if (err)
241 goto err_counter_clear;
242
243 err = mlxsw_sp_rif_counter_edit(mlxsw_sp, rif->rif_index,
244 *p_counter_index, true, dir);
245 if (err)
246 goto err_counter_edit;
247 mlxsw_sp_rif_counter_valid_set(rif, dir, true);
248 return 0;
249
250err_counter_edit:
251err_counter_clear:
252 mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_RIF,
253 *p_counter_index);
254 return err;
255}
256
257void mlxsw_sp_rif_counter_free(struct mlxsw_sp *mlxsw_sp,
258 struct mlxsw_sp_rif *rif,
259 enum mlxsw_sp_rif_counter_dir dir)
260{
261 unsigned int *p_counter_index;
262
6b1206bb
AS
263 if (!mlxsw_sp_rif_counter_valid_get(rif, dir))
264 return;
265
e0c0afd8
AS
266 p_counter_index = mlxsw_sp_rif_p_counter_get(rif, dir);
267 if (WARN_ON(!p_counter_index))
268 return;
269 mlxsw_sp_rif_counter_edit(mlxsw_sp, rif->rif_index,
270 *p_counter_index, false, dir);
271 mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_RIF,
272 *p_counter_index);
273 mlxsw_sp_rif_counter_valid_set(rif, dir, false);
274}
275
e4f3c1c1
IS
276static void mlxsw_sp_rif_counters_alloc(struct mlxsw_sp_rif *rif)
277{
278 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
279 struct devlink *devlink;
280
281 devlink = priv_to_devlink(mlxsw_sp->core);
282 if (!devlink_dpipe_table_counter_enabled(devlink,
283 MLXSW_SP_DPIPE_TABLE_NAME_ERIF))
284 return;
285 mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS);
286}
287
288static void mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif *rif)
289{
290 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
291
292 mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS);
293}
294
7dcc18ad 295#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE + 1)
9011b677
IS
296
297struct mlxsw_sp_prefix_usage {
298 DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT);
299};
300
53342023
JP
301#define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \
302 for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
303
304static bool
305mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage *prefix_usage1,
306 struct mlxsw_sp_prefix_usage *prefix_usage2)
307{
308 return !memcmp(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1));
309}
310
6b75c480
JP
311static void
312mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage *prefix_usage1,
313 struct mlxsw_sp_prefix_usage *prefix_usage2)
314{
315 memcpy(prefix_usage1, prefix_usage2, sizeof(*prefix_usage1));
316}
317
5e9c16cc
JP
318static void
319mlxsw_sp_prefix_usage_set(struct mlxsw_sp_prefix_usage *prefix_usage,
320 unsigned char prefix_len)
321{
322 set_bit(prefix_len, prefix_usage->b);
323}
324
325static void
326mlxsw_sp_prefix_usage_clear(struct mlxsw_sp_prefix_usage *prefix_usage,
327 unsigned char prefix_len)
328{
329 clear_bit(prefix_len, prefix_usage->b);
330}
331
332struct mlxsw_sp_fib_key {
333 unsigned char addr[sizeof(struct in6_addr)];
334 unsigned char prefix_len;
335};
336
61c503f9
JP
337enum mlxsw_sp_fib_entry_type {
338 MLXSW_SP_FIB_ENTRY_TYPE_REMOTE,
339 MLXSW_SP_FIB_ENTRY_TYPE_LOCAL,
340 MLXSW_SP_FIB_ENTRY_TYPE_TRAP,
2810c3b2 341 MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE,
21151f64 342 MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE,
4607f6d2
PM
343
344 /* This is a special case of local delivery, where a packet should be
345 * decapsulated on reception. Note that there is no corresponding ENCAP,
346 * because that's a type of next hop, not of FIB entry. (There can be
347 * several next hops in a REMOTE entry, and some of them may be
348 * encapsulating entries.)
349 */
350 MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP,
0c69e0fc 351 MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP,
61c503f9
JP
352};
353
a7ff87ac 354struct mlxsw_sp_nexthop_group;
7c4a7ec8 355struct mlxsw_sp_fib_entry;
a7ff87ac 356
9aecce1c 357struct mlxsw_sp_fib_node {
7c4a7ec8 358 struct mlxsw_sp_fib_entry *fib_entry;
b45f64d1 359 struct list_head list;
9aecce1c 360 struct rhash_head ht_node;
76610ebb 361 struct mlxsw_sp_fib *fib;
5e9c16cc 362 struct mlxsw_sp_fib_key key;
9aecce1c
IS
363};
364
4607f6d2
PM
365struct mlxsw_sp_fib_entry_decap {
366 struct mlxsw_sp_ipip_entry *ipip_entry;
367 u32 tunnel_index;
368};
369
9aecce1c 370struct mlxsw_sp_fib_entry {
9aecce1c 371 struct mlxsw_sp_fib_node *fib_node;
61c503f9 372 enum mlxsw_sp_fib_entry_type type;
a7ff87ac
JP
373 struct list_head nexthop_group_node;
374 struct mlxsw_sp_nexthop_group *nh_group;
4607f6d2 375 struct mlxsw_sp_fib_entry_decap decap; /* Valid for decap entries. */
5e9c16cc
JP
376};
377
4f1c7f1f
IS
378struct mlxsw_sp_fib4_entry {
379 struct mlxsw_sp_fib_entry common;
380 u32 tb_id;
381 u32 prio;
382 u8 tos;
383 u8 type;
384};
385
428b851f
IS
386struct mlxsw_sp_fib6_entry {
387 struct mlxsw_sp_fib_entry common;
388 struct list_head rt6_list;
389 unsigned int nrt6;
390};
391
392struct mlxsw_sp_rt6 {
393 struct list_head list;
8d1c802b 394 struct fib6_info *rt;
428b851f
IS
395};
396
9011b677
IS
397struct mlxsw_sp_lpm_tree {
398 u8 id; /* tree ID */
399 unsigned int ref_count;
400 enum mlxsw_sp_l3proto proto;
2b52ce02 401 unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT];
9011b677
IS
402 struct mlxsw_sp_prefix_usage prefix_usage;
403};
404
5e9c16cc
JP
405struct mlxsw_sp_fib {
406 struct rhashtable ht;
9aecce1c 407 struct list_head node_list;
76610ebb
IS
408 struct mlxsw_sp_vr *vr;
409 struct mlxsw_sp_lpm_tree *lpm_tree;
76610ebb 410 enum mlxsw_sp_l3proto proto;
5e9c16cc
JP
411};
412
9011b677
IS
413struct mlxsw_sp_vr {
414 u16 id; /* virtual router ID */
415 u32 tb_id; /* kernel fib table id */
416 unsigned int rif_count;
417 struct mlxsw_sp_fib *fib4;
a3d9bc50 418 struct mlxsw_sp_fib *fib6;
9742f866 419 struct mlxsw_sp_mr_table *mr_table[MLXSW_SP_L3_PROTO_MAX];
a5040a90
ND
420 struct mlxsw_sp_rif *ul_rif;
421 refcount_t ul_rif_refcnt;
9011b677
IS
422};
423
9aecce1c 424static const struct rhashtable_params mlxsw_sp_fib_ht_params;
5e9c16cc 425
2b52ce02
IS
426static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp *mlxsw_sp,
427 struct mlxsw_sp_vr *vr,
76610ebb 428 enum mlxsw_sp_l3proto proto)
5e9c16cc 429{
2b52ce02 430 struct mlxsw_sp_lpm_tree *lpm_tree;
5e9c16cc
JP
431 struct mlxsw_sp_fib *fib;
432 int err;
433
2b52ce02 434 lpm_tree = mlxsw_sp->router->lpm.proto_trees[proto];
5e9c16cc
JP
435 fib = kzalloc(sizeof(*fib), GFP_KERNEL);
436 if (!fib)
437 return ERR_PTR(-ENOMEM);
438 err = rhashtable_init(&fib->ht, &mlxsw_sp_fib_ht_params);
439 if (err)
440 goto err_rhashtable_init;
9aecce1c 441 INIT_LIST_HEAD(&fib->node_list);
76610ebb
IS
442 fib->proto = proto;
443 fib->vr = vr;
2b52ce02
IS
444 fib->lpm_tree = lpm_tree;
445 mlxsw_sp_lpm_tree_hold(lpm_tree);
446 err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, lpm_tree->id);
447 if (err)
448 goto err_lpm_tree_bind;
5e9c16cc
JP
449 return fib;
450
2b52ce02
IS
451err_lpm_tree_bind:
452 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
5e9c16cc
JP
453err_rhashtable_init:
454 kfree(fib);
455 return ERR_PTR(err);
456}
457
2b52ce02
IS
458static void mlxsw_sp_fib_destroy(struct mlxsw_sp *mlxsw_sp,
459 struct mlxsw_sp_fib *fib)
5e9c16cc 460{
2b52ce02
IS
461 mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp, fib);
462 mlxsw_sp_lpm_tree_put(mlxsw_sp, fib->lpm_tree);
9aecce1c 463 WARN_ON(!list_empty(&fib->node_list));
5e9c16cc
JP
464 rhashtable_destroy(&fib->ht);
465 kfree(fib);
466}
467
53342023 468static struct mlxsw_sp_lpm_tree *
382dbb40 469mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp)
53342023
JP
470{
471 static struct mlxsw_sp_lpm_tree *lpm_tree;
472 int i;
473
9011b677
IS
474 for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
475 lpm_tree = &mlxsw_sp->router->lpm.trees[i];
382dbb40
IS
476 if (lpm_tree->ref_count == 0)
477 return lpm_tree;
53342023
JP
478 }
479 return NULL;
480}
481
482static int mlxsw_sp_lpm_tree_alloc(struct mlxsw_sp *mlxsw_sp,
483 struct mlxsw_sp_lpm_tree *lpm_tree)
484{
485 char ralta_pl[MLXSW_REG_RALTA_LEN];
486
1a9234e6
IS
487 mlxsw_reg_ralta_pack(ralta_pl, true,
488 (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
489 lpm_tree->id);
53342023
JP
490 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
491}
492
cc702670
IS
493static void mlxsw_sp_lpm_tree_free(struct mlxsw_sp *mlxsw_sp,
494 struct mlxsw_sp_lpm_tree *lpm_tree)
53342023
JP
495{
496 char ralta_pl[MLXSW_REG_RALTA_LEN];
497
1a9234e6
IS
498 mlxsw_reg_ralta_pack(ralta_pl, false,
499 (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
500 lpm_tree->id);
cc702670 501 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
53342023
JP
502}
503
504static int
505mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp *mlxsw_sp,
506 struct mlxsw_sp_prefix_usage *prefix_usage,
507 struct mlxsw_sp_lpm_tree *lpm_tree)
508{
509 char ralst_pl[MLXSW_REG_RALST_LEN];
510 u8 root_bin = 0;
511 u8 prefix;
512 u8 last_prefix = MLXSW_REG_RALST_BIN_NO_CHILD;
513
514 mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage)
515 root_bin = prefix;
516
517 mlxsw_reg_ralst_pack(ralst_pl, root_bin, lpm_tree->id);
518 mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) {
519 if (prefix == 0)
520 continue;
521 mlxsw_reg_ralst_bin_pack(ralst_pl, prefix, last_prefix,
522 MLXSW_REG_RALST_BIN_NO_CHILD);
523 last_prefix = prefix;
524 }
525 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl);
526}
527
528static struct mlxsw_sp_lpm_tree *
529mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
530 struct mlxsw_sp_prefix_usage *prefix_usage,
382dbb40 531 enum mlxsw_sp_l3proto proto)
53342023
JP
532{
533 struct mlxsw_sp_lpm_tree *lpm_tree;
534 int err;
535
382dbb40 536 lpm_tree = mlxsw_sp_lpm_tree_find_unused(mlxsw_sp);
53342023
JP
537 if (!lpm_tree)
538 return ERR_PTR(-EBUSY);
539 lpm_tree->proto = proto;
540 err = mlxsw_sp_lpm_tree_alloc(mlxsw_sp, lpm_tree);
541 if (err)
542 return ERR_PTR(err);
543
544 err = mlxsw_sp_lpm_tree_left_struct_set(mlxsw_sp, prefix_usage,
545 lpm_tree);
546 if (err)
547 goto err_left_struct_set;
2083d367
JP
548 memcpy(&lpm_tree->prefix_usage, prefix_usage,
549 sizeof(lpm_tree->prefix_usage));
2b52ce02
IS
550 memset(&lpm_tree->prefix_ref_count, 0,
551 sizeof(lpm_tree->prefix_ref_count));
552 lpm_tree->ref_count = 1;
53342023
JP
553 return lpm_tree;
554
555err_left_struct_set:
556 mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
557 return ERR_PTR(err);
558}
559
cc702670
IS
560static void mlxsw_sp_lpm_tree_destroy(struct mlxsw_sp *mlxsw_sp,
561 struct mlxsw_sp_lpm_tree *lpm_tree)
53342023 562{
cc702670 563 mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
53342023
JP
564}
565
566static struct mlxsw_sp_lpm_tree *
567mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
568 struct mlxsw_sp_prefix_usage *prefix_usage,
382dbb40 569 enum mlxsw_sp_l3proto proto)
53342023
JP
570{
571 struct mlxsw_sp_lpm_tree *lpm_tree;
572 int i;
573
9011b677
IS
574 for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
575 lpm_tree = &mlxsw_sp->router->lpm.trees[i];
8b99becd
JP
576 if (lpm_tree->ref_count != 0 &&
577 lpm_tree->proto == proto &&
53342023 578 mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage,
2b52ce02
IS
579 prefix_usage)) {
580 mlxsw_sp_lpm_tree_hold(lpm_tree);
fc922bb0 581 return lpm_tree;
2b52ce02 582 }
53342023 583 }
fc922bb0
IS
584 return mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage, proto);
585}
53342023 586
fc922bb0
IS
587static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree)
588{
53342023 589 lpm_tree->ref_count++;
53342023
JP
590}
591
cc702670
IS
592static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
593 struct mlxsw_sp_lpm_tree *lpm_tree)
53342023
JP
594{
595 if (--lpm_tree->ref_count == 0)
cc702670 596 mlxsw_sp_lpm_tree_destroy(mlxsw_sp, lpm_tree);
53342023
JP
597}
598
d7a60306 599#define MLXSW_SP_LPM_TREE_MIN 1 /* tree 0 is reserved */
8494ab06
IS
600
601static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
53342023 602{
2b52ce02 603 struct mlxsw_sp_prefix_usage req_prefix_usage = {{ 0 } };
53342023 604 struct mlxsw_sp_lpm_tree *lpm_tree;
8494ab06 605 u64 max_trees;
2b52ce02 606 int err, i;
53342023 607
8494ab06
IS
608 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LPM_TREES))
609 return -EIO;
610
611 max_trees = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LPM_TREES);
9011b677
IS
612 mlxsw_sp->router->lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN;
613 mlxsw_sp->router->lpm.trees = kcalloc(mlxsw_sp->router->lpm.tree_count,
8494ab06
IS
614 sizeof(struct mlxsw_sp_lpm_tree),
615 GFP_KERNEL);
9011b677 616 if (!mlxsw_sp->router->lpm.trees)
8494ab06
IS
617 return -ENOMEM;
618
9011b677
IS
619 for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
620 lpm_tree = &mlxsw_sp->router->lpm.trees[i];
53342023
JP
621 lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN;
622 }
8494ab06 623
2b52ce02
IS
624 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
625 MLXSW_SP_L3_PROTO_IPV4);
626 if (IS_ERR(lpm_tree)) {
627 err = PTR_ERR(lpm_tree);
628 goto err_ipv4_tree_get;
629 }
630 mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4] = lpm_tree;
631
632 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
633 MLXSW_SP_L3_PROTO_IPV6);
634 if (IS_ERR(lpm_tree)) {
635 err = PTR_ERR(lpm_tree);
636 goto err_ipv6_tree_get;
637 }
638 mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV6] = lpm_tree;
639
8494ab06 640 return 0;
2b52ce02
IS
641
642err_ipv6_tree_get:
643 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4];
644 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
645err_ipv4_tree_get:
646 kfree(mlxsw_sp->router->lpm.trees);
647 return err;
8494ab06
IS
648}
649
650static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp)
651{
2b52ce02
IS
652 struct mlxsw_sp_lpm_tree *lpm_tree;
653
654 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV6];
655 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
656
657 lpm_tree = mlxsw_sp->router->lpm.proto_trees[MLXSW_SP_L3_PROTO_IPV4];
658 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
659
9011b677 660 kfree(mlxsw_sp->router->lpm.trees);
53342023
JP
661}
662
76610ebb
IS
663static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr *vr)
664{
9742f866
YM
665 return !!vr->fib4 || !!vr->fib6 ||
666 !!vr->mr_table[MLXSW_SP_L3_PROTO_IPV4] ||
667 !!vr->mr_table[MLXSW_SP_L3_PROTO_IPV6];
76610ebb
IS
668}
669
6b75c480
JP
670static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp)
671{
672 struct mlxsw_sp_vr *vr;
673 int i;
674
c1a38311 675 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
9011b677 676 vr = &mlxsw_sp->router->vrs[i];
76610ebb 677 if (!mlxsw_sp_vr_is_used(vr))
6b75c480
JP
678 return vr;
679 }
680 return NULL;
681}
682
683static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
0adb214b 684 const struct mlxsw_sp_fib *fib, u8 tree_id)
6b75c480
JP
685{
686 char raltb_pl[MLXSW_REG_RALTB_LEN];
687
76610ebb
IS
688 mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
689 (enum mlxsw_reg_ralxx_protocol) fib->proto,
0adb214b 690 tree_id);
6b75c480
JP
691 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
692}
693
694static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
76610ebb 695 const struct mlxsw_sp_fib *fib)
6b75c480
JP
696{
697 char raltb_pl[MLXSW_REG_RALTB_LEN];
698
699 /* Bind to tree 0 which is default */
76610ebb
IS
700 mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
701 (enum mlxsw_reg_ralxx_protocol) fib->proto, 0);
6b75c480
JP
702 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
703}
704
705static u32 mlxsw_sp_fix_tb_id(u32 tb_id)
706{
7e50d435
YG
707 /* For our purpose, squash main, default and local tables into one */
708 if (tb_id == RT_TABLE_LOCAL || tb_id == RT_TABLE_DEFAULT)
6b75c480
JP
709 tb_id = RT_TABLE_MAIN;
710 return tb_id;
711}
712
713static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp,
76610ebb 714 u32 tb_id)
6b75c480
JP
715{
716 struct mlxsw_sp_vr *vr;
717 int i;
718
719 tb_id = mlxsw_sp_fix_tb_id(tb_id);
9497c042 720
c1a38311 721 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
9011b677 722 vr = &mlxsw_sp->router->vrs[i];
76610ebb 723 if (mlxsw_sp_vr_is_used(vr) && vr->tb_id == tb_id)
6b75c480
JP
724 return vr;
725 }
726 return NULL;
727}
728
88782f75
IS
729int mlxsw_sp_router_tb_id_vr_id(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
730 u16 *vr_id)
731{
732 struct mlxsw_sp_vr *vr;
733
734 vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id);
735 if (!vr)
736 return -ESRCH;
737 *vr_id = vr->id;
738
739 return 0;
740}
741
76610ebb
IS
742static struct mlxsw_sp_fib *mlxsw_sp_vr_fib(const struct mlxsw_sp_vr *vr,
743 enum mlxsw_sp_l3proto proto)
744{
745 switch (proto) {
746 case MLXSW_SP_L3_PROTO_IPV4:
747 return vr->fib4;
748 case MLXSW_SP_L3_PROTO_IPV6:
a3d9bc50 749 return vr->fib6;
76610ebb
IS
750 }
751 return NULL;
752}
753
6b75c480 754static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
f8fa9b4e
DA
755 u32 tb_id,
756 struct netlink_ext_ack *extack)
6b75c480 757{
9742f866 758 struct mlxsw_sp_mr_table *mr4_table, *mr6_table;
0f2d2b27
JP
759 struct mlxsw_sp_fib *fib4;
760 struct mlxsw_sp_fib *fib6;
6b75c480 761 struct mlxsw_sp_vr *vr;
a3d9bc50 762 int err;
6b75c480
JP
763
764 vr = mlxsw_sp_vr_find_unused(mlxsw_sp);
f8fa9b4e 765 if (!vr) {
6c677750 766 NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported virtual routers");
6b75c480 767 return ERR_PTR(-EBUSY);
f8fa9b4e 768 }
0f2d2b27
JP
769 fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
770 if (IS_ERR(fib4))
771 return ERR_CAST(fib4);
772 fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
773 if (IS_ERR(fib6)) {
774 err = PTR_ERR(fib6);
a3d9bc50
IS
775 goto err_fib6_create;
776 }
0f2d2b27
JP
777 mr4_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id,
778 MLXSW_SP_L3_PROTO_IPV4);
779 if (IS_ERR(mr4_table)) {
780 err = PTR_ERR(mr4_table);
9742f866 781 goto err_mr4_table_create;
d42b0965 782 }
9742f866
YM
783 mr6_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id,
784 MLXSW_SP_L3_PROTO_IPV6);
785 if (IS_ERR(mr6_table)) {
786 err = PTR_ERR(mr6_table);
787 goto err_mr6_table_create;
788 }
789
0f2d2b27
JP
790 vr->fib4 = fib4;
791 vr->fib6 = fib6;
9742f866
YM
792 vr->mr_table[MLXSW_SP_L3_PROTO_IPV4] = mr4_table;
793 vr->mr_table[MLXSW_SP_L3_PROTO_IPV6] = mr6_table;
6b75c480 794 vr->tb_id = tb_id;
6b75c480 795 return vr;
a3d9bc50 796
9742f866
YM
797err_mr6_table_create:
798 mlxsw_sp_mr_table_destroy(mr4_table);
799err_mr4_table_create:
0f2d2b27 800 mlxsw_sp_fib_destroy(mlxsw_sp, fib6);
a3d9bc50 801err_fib6_create:
0f2d2b27 802 mlxsw_sp_fib_destroy(mlxsw_sp, fib4);
a3d9bc50 803 return ERR_PTR(err);
6b75c480
JP
804}
805
2b52ce02
IS
806static void mlxsw_sp_vr_destroy(struct mlxsw_sp *mlxsw_sp,
807 struct mlxsw_sp_vr *vr)
6b75c480 808{
9742f866
YM
809 mlxsw_sp_mr_table_destroy(vr->mr_table[MLXSW_SP_L3_PROTO_IPV6]);
810 vr->mr_table[MLXSW_SP_L3_PROTO_IPV6] = NULL;
811 mlxsw_sp_mr_table_destroy(vr->mr_table[MLXSW_SP_L3_PROTO_IPV4]);
812 vr->mr_table[MLXSW_SP_L3_PROTO_IPV4] = NULL;
2b52ce02 813 mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib6);
a3d9bc50 814 vr->fib6 = NULL;
2b52ce02 815 mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib4);
76610ebb 816 vr->fib4 = NULL;
6b75c480
JP
817}
818
f8fa9b4e
DA
819static struct mlxsw_sp_vr *mlxsw_sp_vr_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
820 struct netlink_ext_ack *extack)
6b75c480
JP
821{
822 struct mlxsw_sp_vr *vr;
6b75c480
JP
823
824 tb_id = mlxsw_sp_fix_tb_id(tb_id);
76610ebb
IS
825 vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id);
826 if (!vr)
f8fa9b4e 827 vr = mlxsw_sp_vr_create(mlxsw_sp, tb_id, extack);
6b75c480
JP
828 return vr;
829}
830
2b52ce02 831static void mlxsw_sp_vr_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr)
6b75c480 832{
a3d9bc50 833 if (!vr->rif_count && list_empty(&vr->fib4->node_list) &&
d42b0965 834 list_empty(&vr->fib6->node_list) &&
9742f866
YM
835 mlxsw_sp_mr_table_empty(vr->mr_table[MLXSW_SP_L3_PROTO_IPV4]) &&
836 mlxsw_sp_mr_table_empty(vr->mr_table[MLXSW_SP_L3_PROTO_IPV6]))
2b52ce02 837 mlxsw_sp_vr_destroy(mlxsw_sp, vr);
6b75c480
JP
838}
839
fc922bb0
IS
840static bool
841mlxsw_sp_vr_lpm_tree_should_replace(struct mlxsw_sp_vr *vr,
842 enum mlxsw_sp_l3proto proto, u8 tree_id)
843{
844 struct mlxsw_sp_fib *fib = mlxsw_sp_vr_fib(vr, proto);
845
846 if (!mlxsw_sp_vr_is_used(vr))
847 return false;
2b52ce02 848 if (fib->lpm_tree->id == tree_id)
fc922bb0
IS
849 return true;
850 return false;
851}
852
853static int mlxsw_sp_vr_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
854 struct mlxsw_sp_fib *fib,
855 struct mlxsw_sp_lpm_tree *new_tree)
856{
857 struct mlxsw_sp_lpm_tree *old_tree = fib->lpm_tree;
858 int err;
859
fc922bb0
IS
860 fib->lpm_tree = new_tree;
861 mlxsw_sp_lpm_tree_hold(new_tree);
ed604c5d
IS
862 err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, new_tree->id);
863 if (err)
864 goto err_tree_bind;
fc922bb0
IS
865 mlxsw_sp_lpm_tree_put(mlxsw_sp, old_tree);
866 return 0;
ed604c5d
IS
867
868err_tree_bind:
869 mlxsw_sp_lpm_tree_put(mlxsw_sp, new_tree);
870 fib->lpm_tree = old_tree;
871 return err;
fc922bb0
IS
872}
873
874static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp,
875 struct mlxsw_sp_fib *fib,
876 struct mlxsw_sp_lpm_tree *new_tree)
877{
fc922bb0 878 enum mlxsw_sp_l3proto proto = fib->proto;
2b52ce02 879 struct mlxsw_sp_lpm_tree *old_tree;
fc922bb0
IS
880 u8 old_id, new_id = new_tree->id;
881 struct mlxsw_sp_vr *vr;
882 int i, err;
883
2b52ce02 884 old_tree = mlxsw_sp->router->lpm.proto_trees[proto];
fc922bb0
IS
885 old_id = old_tree->id;
886
887 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
888 vr = &mlxsw_sp->router->vrs[i];
889 if (!mlxsw_sp_vr_lpm_tree_should_replace(vr, proto, old_id))
890 continue;
891 err = mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp,
892 mlxsw_sp_vr_fib(vr, proto),
893 new_tree);
894 if (err)
895 goto err_tree_replace;
896 }
897
2b52ce02
IS
898 memcpy(new_tree->prefix_ref_count, old_tree->prefix_ref_count,
899 sizeof(new_tree->prefix_ref_count));
900 mlxsw_sp->router->lpm.proto_trees[proto] = new_tree;
901 mlxsw_sp_lpm_tree_put(mlxsw_sp, old_tree);
902
fc922bb0
IS
903 return 0;
904
905err_tree_replace:
906 for (i--; i >= 0; i--) {
907 if (!mlxsw_sp_vr_lpm_tree_should_replace(vr, proto, new_id))
908 continue;
909 mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp,
910 mlxsw_sp_vr_fib(vr, proto),
911 old_tree);
912 }
913 return err;
fc922bb0
IS
914}
915
9497c042 916static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
6b75c480
JP
917{
918 struct mlxsw_sp_vr *vr;
c1a38311 919 u64 max_vrs;
6b75c480
JP
920 int i;
921
c1a38311 922 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_VRS))
9497c042
NF
923 return -EIO;
924
c1a38311 925 max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS);
9011b677
IS
926 mlxsw_sp->router->vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr),
927 GFP_KERNEL);
928 if (!mlxsw_sp->router->vrs)
9497c042
NF
929 return -ENOMEM;
930
c1a38311 931 for (i = 0; i < max_vrs; i++) {
9011b677 932 vr = &mlxsw_sp->router->vrs[i];
6b75c480
JP
933 vr->id = i;
934 }
9497c042
NF
935
936 return 0;
937}
938
ac571de9
IS
939static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp);
940
9497c042
NF
941static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp)
942{
3057224e
IS
943 /* At this stage we're guaranteed not to have new incoming
944 * FIB notifications and the work queue is free from FIBs
945 * sitting on top of mlxsw netdevs. However, we can still
946 * have other FIBs queued. Flush the queue before flushing
947 * the device's tables. No need for locks, as we're the only
948 * writer.
949 */
950 mlxsw_core_flush_owq();
ac571de9 951 mlxsw_sp_router_fib_flush(mlxsw_sp);
9011b677 952 kfree(mlxsw_sp->router->vrs);
6b75c480
JP
953}
954
6ddb7426
PM
955static struct net_device *
956__mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev)
957{
958 struct ip_tunnel *tun = netdev_priv(ol_dev);
959 struct net *net = dev_net(ol_dev);
960
f24fbf4d 961 return dev_get_by_index_rcu(net, tun->parms.link);
6ddb7426
PM
962}
963
4cf04f3f 964u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev)
6ddb7426 965{
f24fbf4d
IS
966 struct net_device *d;
967 u32 tb_id;
6ddb7426 968
f24fbf4d
IS
969 rcu_read_lock();
970 d = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
6ddb7426 971 if (d)
f24fbf4d 972 tb_id = l3mdev_fib_table(d) ? : RT_TABLE_MAIN;
6ddb7426 973 else
f24fbf4d
IS
974 tb_id = RT_TABLE_MAIN;
975 rcu_read_unlock();
976
977 return tb_id;
6ddb7426
PM
978}
979
1012b9ac
PM
980static struct mlxsw_sp_rif *
981mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
f8fa9b4e
DA
982 const struct mlxsw_sp_rif_params *params,
983 struct netlink_ext_ack *extack);
1012b9ac
PM
984
985static struct mlxsw_sp_rif_ipip_lb *
986mlxsw_sp_ipip_ol_ipip_lb_create(struct mlxsw_sp *mlxsw_sp,
987 enum mlxsw_sp_ipip_type ipipt,
7e75af63
PM
988 struct net_device *ol_dev,
989 struct netlink_ext_ack *extack)
1012b9ac
PM
990{
991 struct mlxsw_sp_rif_params_ipip_lb lb_params;
992 const struct mlxsw_sp_ipip_ops *ipip_ops;
993 struct mlxsw_sp_rif *rif;
994
995 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipipt];
996 lb_params = (struct mlxsw_sp_rif_params_ipip_lb) {
997 .common.dev = ol_dev,
998 .common.lag = false,
999 .lb_config = ipip_ops->ol_loopback_config(mlxsw_sp, ol_dev),
1000 };
1001
7e75af63 1002 rif = mlxsw_sp_rif_create(mlxsw_sp, &lb_params.common, extack);
1012b9ac
PM
1003 if (IS_ERR(rif))
1004 return ERR_CAST(rif);
1005 return container_of(rif, struct mlxsw_sp_rif_ipip_lb, common);
1006}
1007
1008static struct mlxsw_sp_ipip_entry *
1009mlxsw_sp_ipip_entry_alloc(struct mlxsw_sp *mlxsw_sp,
1010 enum mlxsw_sp_ipip_type ipipt,
1011 struct net_device *ol_dev)
1012{
e437f3b6 1013 const struct mlxsw_sp_ipip_ops *ipip_ops;
1012b9ac
PM
1014 struct mlxsw_sp_ipip_entry *ipip_entry;
1015 struct mlxsw_sp_ipip_entry *ret = NULL;
1016
e437f3b6 1017 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipipt];
1012b9ac
PM
1018 ipip_entry = kzalloc(sizeof(*ipip_entry), GFP_KERNEL);
1019 if (!ipip_entry)
1020 return ERR_PTR(-ENOMEM);
1021
1022 ipip_entry->ol_lb = mlxsw_sp_ipip_ol_ipip_lb_create(mlxsw_sp, ipipt,
7e75af63 1023 ol_dev, NULL);
1012b9ac
PM
1024 if (IS_ERR(ipip_entry->ol_lb)) {
1025 ret = ERR_CAST(ipip_entry->ol_lb);
1026 goto err_ol_ipip_lb_create;
1027 }
1028
1029 ipip_entry->ipipt = ipipt;
1030 ipip_entry->ol_dev = ol_dev;
e437f3b6
PM
1031
1032 switch (ipip_ops->ul_proto) {
1033 case MLXSW_SP_L3_PROTO_IPV4:
1034 ipip_entry->parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
1035 break;
1036 case MLXSW_SP_L3_PROTO_IPV6:
1037 WARN_ON(1);
1038 break;
1039 }
1012b9ac
PM
1040
1041 return ipip_entry;
1042
1043err_ol_ipip_lb_create:
1044 kfree(ipip_entry);
1045 return ret;
1046}
1047
1048static void
4cccb737 1049mlxsw_sp_ipip_entry_dealloc(struct mlxsw_sp_ipip_entry *ipip_entry)
1012b9ac 1050{
1012b9ac
PM
1051 mlxsw_sp_rif_destroy(&ipip_entry->ol_lb->common);
1052 kfree(ipip_entry);
1053}
1054
1012b9ac
PM
1055static bool
1056mlxsw_sp_ipip_entry_saddr_matches(struct mlxsw_sp *mlxsw_sp,
1057 const enum mlxsw_sp_l3proto ul_proto,
1058 union mlxsw_sp_l3addr saddr,
1059 u32 ul_tb_id,
1060 struct mlxsw_sp_ipip_entry *ipip_entry)
1061{
1062 u32 tun_ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
1063 enum mlxsw_sp_ipip_type ipipt = ipip_entry->ipipt;
1064 union mlxsw_sp_l3addr tun_saddr;
1065
1066 if (mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto != ul_proto)
1067 return false;
1068
1069 tun_saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ipip_entry->ol_dev);
1070 return tun_ul_tb_id == ul_tb_id &&
1071 mlxsw_sp_l3addr_eq(&tun_saddr, &saddr);
1072}
1073
4607f6d2
PM
1074static int
1075mlxsw_sp_fib_entry_decap_init(struct mlxsw_sp *mlxsw_sp,
1076 struct mlxsw_sp_fib_entry *fib_entry,
1077 struct mlxsw_sp_ipip_entry *ipip_entry)
1078{
1079 u32 tunnel_index;
1080 int err;
1081
4b6b1869
JP
1082 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
1083 1, &tunnel_index);
4607f6d2
PM
1084 if (err)
1085 return err;
1086
1087 ipip_entry->decap_fib_entry = fib_entry;
1088 fib_entry->decap.ipip_entry = ipip_entry;
1089 fib_entry->decap.tunnel_index = tunnel_index;
1090 return 0;
1091}
1092
1093static void mlxsw_sp_fib_entry_decap_fini(struct mlxsw_sp *mlxsw_sp,
1094 struct mlxsw_sp_fib_entry *fib_entry)
1095{
1096 /* Unlink this node from the IPIP entry that it's the decap entry of. */
1097 fib_entry->decap.ipip_entry->decap_fib_entry = NULL;
1098 fib_entry->decap.ipip_entry = NULL;
4b6b1869 1099 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
0304c005 1100 1, fib_entry->decap.tunnel_index);
4607f6d2
PM
1101}
1102
1cc38fb1
PM
1103static struct mlxsw_sp_fib_node *
1104mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib *fib, const void *addr,
1105 size_t addr_len, unsigned char prefix_len);
4607f6d2
PM
1106static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
1107 struct mlxsw_sp_fib_entry *fib_entry);
1108
1109static void
1110mlxsw_sp_ipip_entry_demote_decap(struct mlxsw_sp *mlxsw_sp,
1111 struct mlxsw_sp_ipip_entry *ipip_entry)
1112{
1113 struct mlxsw_sp_fib_entry *fib_entry = ipip_entry->decap_fib_entry;
1114
1115 mlxsw_sp_fib_entry_decap_fini(mlxsw_sp, fib_entry);
1116 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
1117
1118 mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
1119}
1120
1cc38fb1
PM
1121static void
1122mlxsw_sp_ipip_entry_promote_decap(struct mlxsw_sp *mlxsw_sp,
1123 struct mlxsw_sp_ipip_entry *ipip_entry,
1124 struct mlxsw_sp_fib_entry *decap_fib_entry)
1125{
1126 if (mlxsw_sp_fib_entry_decap_init(mlxsw_sp, decap_fib_entry,
1127 ipip_entry))
1128 return;
1129 decap_fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
1130
1131 if (mlxsw_sp_fib_entry_update(mlxsw_sp, decap_fib_entry))
1132 mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
1133}
1134
0c69e0fc
IS
1135static struct mlxsw_sp_fib_entry *
1136mlxsw_sp_router_ip2me_fib_entry_find(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
1137 enum mlxsw_sp_l3proto proto,
1138 const union mlxsw_sp_l3addr *addr,
1139 enum mlxsw_sp_fib_entry_type type)
1140{
0c69e0fc
IS
1141 struct mlxsw_sp_fib_node *fib_node;
1142 unsigned char addr_prefix_len;
1143 struct mlxsw_sp_fib *fib;
1144 struct mlxsw_sp_vr *vr;
1145 const void *addrp;
1146 size_t addr_len;
1147 u32 addr4;
1148
1149 vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id);
1150 if (!vr)
1151 return NULL;
1152 fib = mlxsw_sp_vr_fib(vr, proto);
1153
1154 switch (proto) {
1155 case MLXSW_SP_L3_PROTO_IPV4:
1156 addr4 = be32_to_cpu(addr->addr4);
1157 addrp = &addr4;
1158 addr_len = 4;
1159 addr_prefix_len = 32;
1160 break;
1161 case MLXSW_SP_L3_PROTO_IPV6: /* fall through */
1162 default:
1163 WARN_ON(1);
1164 return NULL;
1165 }
1166
1167 fib_node = mlxsw_sp_fib_node_lookup(fib, addrp, addr_len,
1168 addr_prefix_len);
7c4a7ec8 1169 if (!fib_node || fib_node->fib_entry->type != type)
0c69e0fc
IS
1170 return NULL;
1171
7c4a7ec8 1172 return fib_node->fib_entry;
0c69e0fc
IS
1173}
1174
1cc38fb1
PM
1175/* Given an IPIP entry, find the corresponding decap route. */
1176static struct mlxsw_sp_fib_entry *
1177mlxsw_sp_ipip_entry_find_decap(struct mlxsw_sp *mlxsw_sp,
1178 struct mlxsw_sp_ipip_entry *ipip_entry)
1179{
1180 static struct mlxsw_sp_fib_node *fib_node;
1181 const struct mlxsw_sp_ipip_ops *ipip_ops;
1cc38fb1
PM
1182 unsigned char saddr_prefix_len;
1183 union mlxsw_sp_l3addr saddr;
1184 struct mlxsw_sp_fib *ul_fib;
1185 struct mlxsw_sp_vr *ul_vr;
1186 const void *saddrp;
1187 size_t saddr_len;
1188 u32 ul_tb_id;
1189 u32 saddr4;
1190
1191 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
1192
1193 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);
1194 ul_vr = mlxsw_sp_vr_find(mlxsw_sp, ul_tb_id);
1195 if (!ul_vr)
1196 return NULL;
1197
1198 ul_fib = mlxsw_sp_vr_fib(ul_vr, ipip_ops->ul_proto);
1199 saddr = mlxsw_sp_ipip_netdev_saddr(ipip_ops->ul_proto,
1200 ipip_entry->ol_dev);
1201
1202 switch (ipip_ops->ul_proto) {
1203 case MLXSW_SP_L3_PROTO_IPV4:
1204 saddr4 = be32_to_cpu(saddr.addr4);
1205 saddrp = &saddr4;
1206 saddr_len = 4;
1207 saddr_prefix_len = 32;
1208 break;
1209 case MLXSW_SP_L3_PROTO_IPV6:
1210 WARN_ON(1);
1211 return NULL;
1212 }
1213
1214 fib_node = mlxsw_sp_fib_node_lookup(ul_fib, saddrp, saddr_len,
1215 saddr_prefix_len);
7c4a7ec8
IS
1216 if (!fib_node ||
1217 fib_node->fib_entry->type != MLXSW_SP_FIB_ENTRY_TYPE_TRAP)
1cc38fb1
PM
1218 return NULL;
1219
7c4a7ec8 1220 return fib_node->fib_entry;
1cc38fb1
PM
1221}
1222
1012b9ac 1223static struct mlxsw_sp_ipip_entry *
4cccb737
PM
1224mlxsw_sp_ipip_entry_create(struct mlxsw_sp *mlxsw_sp,
1225 enum mlxsw_sp_ipip_type ipipt,
1226 struct net_device *ol_dev)
1012b9ac 1227{
1012b9ac 1228 struct mlxsw_sp_ipip_entry *ipip_entry;
1012b9ac
PM
1229
1230 ipip_entry = mlxsw_sp_ipip_entry_alloc(mlxsw_sp, ipipt, ol_dev);
1231 if (IS_ERR(ipip_entry))
1232 return ipip_entry;
1233
1234 list_add_tail(&ipip_entry->ipip_list_node,
1235 &mlxsw_sp->router->ipip_list);
1236
1012b9ac
PM
1237 return ipip_entry;
1238}
1239
1240static void
4cccb737
PM
1241mlxsw_sp_ipip_entry_destroy(struct mlxsw_sp *mlxsw_sp,
1242 struct mlxsw_sp_ipip_entry *ipip_entry)
1012b9ac 1243{
4cccb737
PM
1244 list_del(&ipip_entry->ipip_list_node);
1245 mlxsw_sp_ipip_entry_dealloc(ipip_entry);
1012b9ac
PM
1246}
1247
4607f6d2
PM
1248static bool
1249mlxsw_sp_ipip_entry_matches_decap(struct mlxsw_sp *mlxsw_sp,
1250 const struct net_device *ul_dev,
1251 enum mlxsw_sp_l3proto ul_proto,
1252 union mlxsw_sp_l3addr ul_dip,
1253 struct mlxsw_sp_ipip_entry *ipip_entry)
1254{
1255 u32 ul_tb_id = l3mdev_fib_table(ul_dev) ? : RT_TABLE_MAIN;
1256 enum mlxsw_sp_ipip_type ipipt = ipip_entry->ipipt;
4607f6d2
PM
1257
1258 if (mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto != ul_proto)
1259 return false;
1260
4607f6d2 1261 return mlxsw_sp_ipip_entry_saddr_matches(mlxsw_sp, ul_proto, ul_dip,
da93d291 1262 ul_tb_id, ipip_entry);
4607f6d2
PM
1263}
1264
1265/* Given decap parameters, find the corresponding IPIP entry. */
1266static struct mlxsw_sp_ipip_entry *
1267mlxsw_sp_ipip_entry_find_by_decap(struct mlxsw_sp *mlxsw_sp,
1268 const struct net_device *ul_dev,
1269 enum mlxsw_sp_l3proto ul_proto,
1270 union mlxsw_sp_l3addr ul_dip)
1271{
1272 struct mlxsw_sp_ipip_entry *ipip_entry;
1273
1274 list_for_each_entry(ipip_entry, &mlxsw_sp->router->ipip_list,
1275 ipip_list_node)
1276 if (mlxsw_sp_ipip_entry_matches_decap(mlxsw_sp, ul_dev,
1277 ul_proto, ul_dip,
1278 ipip_entry))
1279 return ipip_entry;
1280
1281 return NULL;
1282}
1283
6698c168
PM
1284static bool mlxsw_sp_netdev_ipip_type(const struct mlxsw_sp *mlxsw_sp,
1285 const struct net_device *dev,
1286 enum mlxsw_sp_ipip_type *p_type)
1287{
1288 struct mlxsw_sp_router *router = mlxsw_sp->router;
1289 const struct mlxsw_sp_ipip_ops *ipip_ops;
1290 enum mlxsw_sp_ipip_type ipipt;
1291
1292 for (ipipt = 0; ipipt < MLXSW_SP_IPIP_TYPE_MAX; ++ipipt) {
1293 ipip_ops = router->ipip_ops_arr[ipipt];
1294 if (dev->type == ipip_ops->dev_type) {
1295 if (p_type)
1296 *p_type = ipipt;
1297 return true;
1298 }
1299 }
1300 return false;
1301}
1302
796ec776
PM
1303bool mlxsw_sp_netdev_is_ipip_ol(const struct mlxsw_sp *mlxsw_sp,
1304 const struct net_device *dev)
0063587d
PM
1305{
1306 return mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, NULL);
1307}
1308
1309static struct mlxsw_sp_ipip_entry *
1310mlxsw_sp_ipip_entry_find_by_ol_dev(struct mlxsw_sp *mlxsw_sp,
1311 const struct net_device *ol_dev)
1312{
1313 struct mlxsw_sp_ipip_entry *ipip_entry;
1314
1315 list_for_each_entry(ipip_entry, &mlxsw_sp->router->ipip_list,
1316 ipip_list_node)
1317 if (ipip_entry->ol_dev == ol_dev)
1318 return ipip_entry;
1319
1320 return NULL;
1321}
1322
61481f2f
PM
1323static struct mlxsw_sp_ipip_entry *
1324mlxsw_sp_ipip_entry_find_by_ul_dev(const struct mlxsw_sp *mlxsw_sp,
1325 const struct net_device *ul_dev,
1326 struct mlxsw_sp_ipip_entry *start)
1327{
1328 struct mlxsw_sp_ipip_entry *ipip_entry;
1329
1330 ipip_entry = list_prepare_entry(start, &mlxsw_sp->router->ipip_list,
1331 ipip_list_node);
1332 list_for_each_entry_continue(ipip_entry, &mlxsw_sp->router->ipip_list,
1333 ipip_list_node) {
f24fbf4d
IS
1334 struct net_device *ol_dev = ipip_entry->ol_dev;
1335 struct net_device *ipip_ul_dev;
1336
1337 rcu_read_lock();
1338 ipip_ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
1339 rcu_read_unlock();
61481f2f
PM
1340
1341 if (ipip_ul_dev == ul_dev)
1342 return ipip_entry;
1343 }
1344
1345 return NULL;
1346}
1347
1348bool mlxsw_sp_netdev_is_ipip_ul(const struct mlxsw_sp *mlxsw_sp,
1349 const struct net_device *dev)
1350{
1351 return mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, dev, NULL);
1352}
1353
cafdb2a0
PM
1354static bool mlxsw_sp_netdevice_ipip_can_offload(struct mlxsw_sp *mlxsw_sp,
1355 const struct net_device *ol_dev,
1356 enum mlxsw_sp_ipip_type ipipt)
1357{
1358 const struct mlxsw_sp_ipip_ops *ops
1359 = mlxsw_sp->router->ipip_ops_arr[ipipt];
1360
1361 /* For deciding whether decap should be offloaded, we don't care about
1362 * overlay protocol, so ask whether either one is supported.
1363 */
1364 return ops->can_offload(mlxsw_sp, ol_dev, MLXSW_SP_L3_PROTO_IPV4) ||
1365 ops->can_offload(mlxsw_sp, ol_dev, MLXSW_SP_L3_PROTO_IPV6);
1366}
1367
796ec776
PM
1368static int mlxsw_sp_netdevice_ipip_ol_reg_event(struct mlxsw_sp *mlxsw_sp,
1369 struct net_device *ol_dev)
0063587d 1370{
0063587d 1371 struct mlxsw_sp_ipip_entry *ipip_entry;
af641713 1372 enum mlxsw_sp_l3proto ul_proto;
0063587d 1373 enum mlxsw_sp_ipip_type ipipt;
af641713
PM
1374 union mlxsw_sp_l3addr saddr;
1375 u32 ul_tb_id;
0063587d
PM
1376
1377 mlxsw_sp_netdev_ipip_type(mlxsw_sp, ol_dev, &ipipt);
cafdb2a0 1378 if (mlxsw_sp_netdevice_ipip_can_offload(mlxsw_sp, ol_dev, ipipt)) {
af641713
PM
1379 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ol_dev);
1380 ul_proto = mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto;
1381 saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ol_dev);
1382 if (!mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, ul_proto,
1383 saddr, ul_tb_id,
1384 NULL)) {
1385 ipip_entry = mlxsw_sp_ipip_entry_create(mlxsw_sp, ipipt,
1386 ol_dev);
1387 if (IS_ERR(ipip_entry))
1388 return PTR_ERR(ipip_entry);
1389 }
0063587d
PM
1390 }
1391
1392 return 0;
1393}
1394
796ec776
PM
1395static void mlxsw_sp_netdevice_ipip_ol_unreg_event(struct mlxsw_sp *mlxsw_sp,
1396 struct net_device *ol_dev)
0063587d
PM
1397{
1398 struct mlxsw_sp_ipip_entry *ipip_entry;
1399
1400 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1401 if (ipip_entry)
4cccb737 1402 mlxsw_sp_ipip_entry_destroy(mlxsw_sp, ipip_entry);
0063587d
PM
1403}
1404
47518ca5
PM
1405static void
1406mlxsw_sp_ipip_entry_ol_up_event(struct mlxsw_sp *mlxsw_sp,
1407 struct mlxsw_sp_ipip_entry *ipip_entry)
1408{
1409 struct mlxsw_sp_fib_entry *decap_fib_entry;
1410
1411 decap_fib_entry = mlxsw_sp_ipip_entry_find_decap(mlxsw_sp, ipip_entry);
1412 if (decap_fib_entry)
1413 mlxsw_sp_ipip_entry_promote_decap(mlxsw_sp, ipip_entry,
1414 decap_fib_entry);
1415}
1416
22b99058 1417static int
3c747500
ND
1418mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif, u16 ul_vr_id,
1419 u16 ul_rif_id, bool enable)
22b99058
PM
1420{
1421 struct mlxsw_sp_rif_ipip_lb_config lb_cf = lb_rif->lb_config;
1422 struct mlxsw_sp_rif *rif = &lb_rif->common;
1423 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
1424 char ritr_pl[MLXSW_REG_RITR_LEN];
1425 u32 saddr4;
1426
1427 switch (lb_cf.ul_protocol) {
1428 case MLXSW_SP_L3_PROTO_IPV4:
1429 saddr4 = be32_to_cpu(lb_cf.saddr.addr4);
1430 mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF,
1431 rif->rif_index, rif->vr_id, rif->dev->mtu);
1432 mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl, lb_cf.lb_ipipt,
1433 MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET,
3c747500 1434 ul_vr_id, ul_rif_id, saddr4, lb_cf.okey);
22b99058
PM
1435 break;
1436
1437 case MLXSW_SP_L3_PROTO_IPV6:
1438 return -EAFNOSUPPORT;
1439 }
1440
1441 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
1442}
1443
68c3cd92
PM
1444static int mlxsw_sp_netdevice_ipip_ol_update_mtu(struct mlxsw_sp *mlxsw_sp,
1445 struct net_device *ol_dev)
1446{
1447 struct mlxsw_sp_ipip_entry *ipip_entry;
1448 struct mlxsw_sp_rif_ipip_lb *lb_rif;
68c3cd92
PM
1449 int err = 0;
1450
1451 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1452 if (ipip_entry) {
1453 lb_rif = ipip_entry->ol_lb;
25f844dd
ND
1454 err = mlxsw_sp_rif_ipip_lb_op(lb_rif, lb_rif->ul_vr_id,
1455 lb_rif->ul_rif_id, true);
68c3cd92
PM
1456 if (err)
1457 goto out;
1458 lb_rif->common.mtu = ol_dev->mtu;
1459 }
1460
1461out:
1462 return err;
1463}
1464
6d4de445
PM
1465static void mlxsw_sp_netdevice_ipip_ol_up_event(struct mlxsw_sp *mlxsw_sp,
1466 struct net_device *ol_dev)
0063587d 1467{
0063587d
PM
1468 struct mlxsw_sp_ipip_entry *ipip_entry;
1469
1470 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
47518ca5
PM
1471 if (ipip_entry)
1472 mlxsw_sp_ipip_entry_ol_up_event(mlxsw_sp, ipip_entry);
0063587d
PM
1473}
1474
a3fe198e
PM
1475static void
1476mlxsw_sp_ipip_entry_ol_down_event(struct mlxsw_sp *mlxsw_sp,
1477 struct mlxsw_sp_ipip_entry *ipip_entry)
1478{
1479 if (ipip_entry->decap_fib_entry)
1480 mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
1481}
1482
796ec776
PM
1483static void mlxsw_sp_netdevice_ipip_ol_down_event(struct mlxsw_sp *mlxsw_sp,
1484 struct net_device *ol_dev)
0063587d
PM
1485{
1486 struct mlxsw_sp_ipip_entry *ipip_entry;
1487
1488 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
a3fe198e
PM
1489 if (ipip_entry)
1490 mlxsw_sp_ipip_entry_ol_down_event(mlxsw_sp, ipip_entry);
0063587d
PM
1491}
1492
09dbf629
PM
1493static void mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp *mlxsw_sp,
1494 struct mlxsw_sp_rif *old_rif,
1495 struct mlxsw_sp_rif *new_rif);
65a6121b
PM
1496static int
1497mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp *mlxsw_sp,
1498 struct mlxsw_sp_ipip_entry *ipip_entry,
0c5f1cd5 1499 bool keep_encap,
65a6121b
PM
1500 struct netlink_ext_ack *extack)
1501{
1502 struct mlxsw_sp_rif_ipip_lb *old_lb_rif = ipip_entry->ol_lb;
1503 struct mlxsw_sp_rif_ipip_lb *new_lb_rif;
1504
1505 new_lb_rif = mlxsw_sp_ipip_ol_ipip_lb_create(mlxsw_sp,
1506 ipip_entry->ipipt,
1507 ipip_entry->ol_dev,
1508 extack);
1509 if (IS_ERR(new_lb_rif))
1510 return PTR_ERR(new_lb_rif);
1511 ipip_entry->ol_lb = new_lb_rif;
0c5f1cd5 1512
09dbf629
PM
1513 if (keep_encap)
1514 mlxsw_sp_nexthop_rif_migrate(mlxsw_sp, &old_lb_rif->common,
1515 &new_lb_rif->common);
0c5f1cd5 1516
65a6121b 1517 mlxsw_sp_rif_destroy(&old_lb_rif->common);
f63ce4e5 1518
65a6121b
PM
1519 return 0;
1520}
1521
09dbf629
PM
1522static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp,
1523 struct mlxsw_sp_rif *rif);
1524
0c5f1cd5
PM
1525/**
1526 * Update the offload related to an IPIP entry. This always updates decap, and
1527 * in addition to that it also:
1528 * @recreate_loopback: recreates the associated loopback RIF
1529 * @keep_encap: updates next hops that use the tunnel netdevice. This is only
1530 * relevant when recreate_loopback is true.
1531 * @update_nexthops: updates next hops, keeping the current loopback RIF. This
1532 * is only relevant when recreate_loopback is false.
1533 */
65a6121b
PM
1534int __mlxsw_sp_ipip_entry_update_tunnel(struct mlxsw_sp *mlxsw_sp,
1535 struct mlxsw_sp_ipip_entry *ipip_entry,
0c5f1cd5
PM
1536 bool recreate_loopback,
1537 bool keep_encap,
1538 bool update_nexthops,
65a6121b
PM
1539 struct netlink_ext_ack *extack)
1540{
1541 int err;
f63ce4e5 1542
65a6121b
PM
1543 /* RIFs can't be edited, so to update loopback, we need to destroy and
1544 * recreate it. That creates a window of opportunity where RALUE and
1545 * RATR registers end up referencing a RIF that's already gone. RATRs
1546 * are handled in mlxsw_sp_ipip_entry_ol_lb_update(), and to take care
f63ce4e5
PM
1547 * of RALUE, demote the decap route back.
1548 */
1549 if (ipip_entry->decap_fib_entry)
1550 mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
1551
0c5f1cd5
PM
1552 if (recreate_loopback) {
1553 err = mlxsw_sp_ipip_entry_ol_lb_update(mlxsw_sp, ipip_entry,
1554 keep_encap, extack);
1555 if (err)
1556 return err;
1557 } else if (update_nexthops) {
1558 mlxsw_sp_nexthop_rif_update(mlxsw_sp,
1559 &ipip_entry->ol_lb->common);
1560 }
65a6121b
PM
1561
1562 if (ipip_entry->ol_dev->flags & IFF_UP)
1563 mlxsw_sp_ipip_entry_ol_up_event(mlxsw_sp, ipip_entry);
f63ce4e5
PM
1564
1565 return 0;
1566}
1567
65a6121b
PM
1568static int mlxsw_sp_netdevice_ipip_ol_vrf_event(struct mlxsw_sp *mlxsw_sp,
1569 struct net_device *ol_dev,
1570 struct netlink_ext_ack *extack)
1571{
1572 struct mlxsw_sp_ipip_entry *ipip_entry =
1573 mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1574
1575 if (!ipip_entry)
1576 return 0;
cab43d9c 1577
65a6121b 1578 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
0c5f1cd5 1579 true, false, false, extack);
65a6121b
PM
1580}
1581
61481f2f
PM
1582static int
1583mlxsw_sp_netdevice_ipip_ul_vrf_event(struct mlxsw_sp *mlxsw_sp,
1584 struct mlxsw_sp_ipip_entry *ipip_entry,
1585 struct net_device *ul_dev,
c5731cc5 1586 bool *demote_this,
61481f2f
PM
1587 struct netlink_ext_ack *extack)
1588{
c5731cc5
PM
1589 u32 ul_tb_id = l3mdev_fib_table(ul_dev) ? : RT_TABLE_MAIN;
1590 enum mlxsw_sp_l3proto ul_proto;
1591 union mlxsw_sp_l3addr saddr;
1592
1593 /* Moving underlay to a different VRF might cause local address
1594 * conflict, and the conflicting tunnels need to be demoted.
1595 */
1596 ul_proto = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt]->ul_proto;
1597 saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ipip_entry->ol_dev);
1598 if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, ul_proto,
1599 saddr, ul_tb_id,
1600 ipip_entry)) {
1601 *demote_this = true;
1602 return 0;
1603 }
1604
61481f2f
PM
1605 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
1606 true, true, false, extack);
1607}
1608
44b0fff1
PM
1609static int
1610mlxsw_sp_netdevice_ipip_ul_up_event(struct mlxsw_sp *mlxsw_sp,
1611 struct mlxsw_sp_ipip_entry *ipip_entry,
1612 struct net_device *ul_dev)
1613{
1614 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
1615 false, false, true, NULL);
1616}
1617
1618static int
1619mlxsw_sp_netdevice_ipip_ul_down_event(struct mlxsw_sp *mlxsw_sp,
1620 struct mlxsw_sp_ipip_entry *ipip_entry,
1621 struct net_device *ul_dev)
1622{
1623 /* A down underlay device causes encapsulated packets to not be
1624 * forwarded, but decap still works. So refresh next hops without
1625 * touching anything else.
1626 */
1627 return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
1628 false, false, true, NULL);
1629}
1630
4cf04f3f
PM
1631static int
1632mlxsw_sp_netdevice_ipip_ol_change_event(struct mlxsw_sp *mlxsw_sp,
1633 struct net_device *ol_dev,
1634 struct netlink_ext_ack *extack)
1635{
1636 const struct mlxsw_sp_ipip_ops *ipip_ops;
1637 struct mlxsw_sp_ipip_entry *ipip_entry;
1638 int err;
1639
1640 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
1641 if (!ipip_entry)
1642 /* A change might make a tunnel eligible for offloading, but
1643 * that is currently not implemented. What falls to slow path
1644 * stays there.
1645 */
1646 return 0;
1647
1648 /* A change might make a tunnel not eligible for offloading. */
1649 if (!mlxsw_sp_netdevice_ipip_can_offload(mlxsw_sp, ol_dev,
1650 ipip_entry->ipipt)) {
1651 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
1652 return 0;
1653 }
1654
1655 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
1656 err = ipip_ops->ol_netdev_change(mlxsw_sp, ipip_entry, extack);
1657 return err;
1658}
1659
af641713
PM
1660void mlxsw_sp_ipip_entry_demote_tunnel(struct mlxsw_sp *mlxsw_sp,
1661 struct mlxsw_sp_ipip_entry *ipip_entry)
1662{
1663 struct net_device *ol_dev = ipip_entry->ol_dev;
1664
1665 if (ol_dev->flags & IFF_UP)
1666 mlxsw_sp_ipip_entry_ol_down_event(mlxsw_sp, ipip_entry);
1667 mlxsw_sp_ipip_entry_destroy(mlxsw_sp, ipip_entry);
1668}
1669
1670/* The configuration where several tunnels have the same local address in the
1671 * same underlay table needs special treatment in the HW. That is currently not
1672 * implemented in the driver. This function finds and demotes the first tunnel
1673 * with a given source address, except the one passed in in the argument
1674 * `except'.
1675 */
1676bool
1677mlxsw_sp_ipip_demote_tunnel_by_saddr(struct mlxsw_sp *mlxsw_sp,
1678 enum mlxsw_sp_l3proto ul_proto,
1679 union mlxsw_sp_l3addr saddr,
1680 u32 ul_tb_id,
1681 const struct mlxsw_sp_ipip_entry *except)
1682{
1683 struct mlxsw_sp_ipip_entry *ipip_entry, *tmp;
1684
1685 list_for_each_entry_safe(ipip_entry, tmp, &mlxsw_sp->router->ipip_list,
1686 ipip_list_node) {
1687 if (ipip_entry != except &&
1688 mlxsw_sp_ipip_entry_saddr_matches(mlxsw_sp, ul_proto, saddr,
1689 ul_tb_id, ipip_entry)) {
1690 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
1691 return true;
1692 }
1693 }
1694
1695 return false;
1696}
1697
61481f2f
PM
1698static void mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(struct mlxsw_sp *mlxsw_sp,
1699 struct net_device *ul_dev)
1700{
1701 struct mlxsw_sp_ipip_entry *ipip_entry, *tmp;
1702
1703 list_for_each_entry_safe(ipip_entry, tmp, &mlxsw_sp->router->ipip_list,
1704 ipip_list_node) {
f24fbf4d
IS
1705 struct net_device *ol_dev = ipip_entry->ol_dev;
1706 struct net_device *ipip_ul_dev;
61481f2f 1707
f24fbf4d
IS
1708 rcu_read_lock();
1709 ipip_ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
1710 rcu_read_unlock();
61481f2f
PM
1711 if (ipip_ul_dev == ul_dev)
1712 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
1713 }
1714}
1715
7e75af63
PM
1716int mlxsw_sp_netdevice_ipip_ol_event(struct mlxsw_sp *mlxsw_sp,
1717 struct net_device *ol_dev,
1718 unsigned long event,
1719 struct netdev_notifier_info *info)
0063587d 1720{
7e75af63
PM
1721 struct netdev_notifier_changeupper_info *chup;
1722 struct netlink_ext_ack *extack;
1723
0063587d
PM
1724 switch (event) {
1725 case NETDEV_REGISTER:
796ec776 1726 return mlxsw_sp_netdevice_ipip_ol_reg_event(mlxsw_sp, ol_dev);
0063587d 1727 case NETDEV_UNREGISTER:
796ec776 1728 mlxsw_sp_netdevice_ipip_ol_unreg_event(mlxsw_sp, ol_dev);
0063587d
PM
1729 return 0;
1730 case NETDEV_UP:
6d4de445
PM
1731 mlxsw_sp_netdevice_ipip_ol_up_event(mlxsw_sp, ol_dev);
1732 return 0;
0063587d 1733 case NETDEV_DOWN:
796ec776 1734 mlxsw_sp_netdevice_ipip_ol_down_event(mlxsw_sp, ol_dev);
0063587d 1735 return 0;
f63ce4e5 1736 case NETDEV_CHANGEUPPER:
7e75af63
PM
1737 chup = container_of(info, typeof(*chup), info);
1738 extack = info->extack;
1739 if (netif_is_l3_master(chup->upper_dev))
796ec776 1740 return mlxsw_sp_netdevice_ipip_ol_vrf_event(mlxsw_sp,
7e75af63
PM
1741 ol_dev,
1742 extack);
f63ce4e5 1743 return 0;
4cf04f3f
PM
1744 case NETDEV_CHANGE:
1745 extack = info->extack;
1746 return mlxsw_sp_netdevice_ipip_ol_change_event(mlxsw_sp,
1747 ol_dev, extack);
68c3cd92
PM
1748 case NETDEV_CHANGEMTU:
1749 return mlxsw_sp_netdevice_ipip_ol_update_mtu(mlxsw_sp, ol_dev);
0063587d
PM
1750 }
1751 return 0;
1752}
1753
61481f2f
PM
1754static int
1755__mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
1756 struct mlxsw_sp_ipip_entry *ipip_entry,
1757 struct net_device *ul_dev,
c5731cc5 1758 bool *demote_this,
61481f2f
PM
1759 unsigned long event,
1760 struct netdev_notifier_info *info)
1761{
1762 struct netdev_notifier_changeupper_info *chup;
1763 struct netlink_ext_ack *extack;
1764
1765 switch (event) {
1766 case NETDEV_CHANGEUPPER:
1767 chup = container_of(info, typeof(*chup), info);
1768 extack = info->extack;
1769 if (netif_is_l3_master(chup->upper_dev))
1770 return mlxsw_sp_netdevice_ipip_ul_vrf_event(mlxsw_sp,
1771 ipip_entry,
1772 ul_dev,
c5731cc5 1773 demote_this,
61481f2f
PM
1774 extack);
1775 break;
44b0fff1
PM
1776
1777 case NETDEV_UP:
1778 return mlxsw_sp_netdevice_ipip_ul_up_event(mlxsw_sp, ipip_entry,
1779 ul_dev);
1780 case NETDEV_DOWN:
1781 return mlxsw_sp_netdevice_ipip_ul_down_event(mlxsw_sp,
1782 ipip_entry,
1783 ul_dev);
61481f2f
PM
1784 }
1785 return 0;
1786}
1787
1788int
1789mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
1790 struct net_device *ul_dev,
1791 unsigned long event,
1792 struct netdev_notifier_info *info)
1793{
1794 struct mlxsw_sp_ipip_entry *ipip_entry = NULL;
1795 int err;
1796
1797 while ((ipip_entry = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp,
1798 ul_dev,
1799 ipip_entry))) {
c5731cc5
PM
1800 struct mlxsw_sp_ipip_entry *prev;
1801 bool demote_this = false;
1802
61481f2f 1803 err = __mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, ipip_entry,
c5731cc5
PM
1804 ul_dev, &demote_this,
1805 event, info);
61481f2f
PM
1806 if (err) {
1807 mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(mlxsw_sp,
1808 ul_dev);
1809 return err;
1810 }
c5731cc5
PM
1811
1812 if (demote_this) {
1813 if (list_is_first(&ipip_entry->ipip_list_node,
1814 &mlxsw_sp->router->ipip_list))
1815 prev = NULL;
1816 else
1817 /* This can't be cached from previous iteration,
1818 * because that entry could be gone now.
1819 */
1820 prev = list_prev_entry(ipip_entry,
1821 ipip_list_node);
1822 mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry);
1823 ipip_entry = prev;
1824 }
61481f2f
PM
1825 }
1826
1827 return 0;
1828}
1829
0c69e0fc
IS
1830int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
1831 enum mlxsw_sp_l3proto ul_proto,
1832 const union mlxsw_sp_l3addr *ul_sip,
1833 u32 tunnel_index)
1834{
1835 enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
8e18d85e 1836 struct mlxsw_sp_router *router = mlxsw_sp->router;
0c69e0fc
IS
1837 struct mlxsw_sp_fib_entry *fib_entry;
1838 int err;
1839
8e18d85e
IS
1840 if (WARN_ON_ONCE(router->nve_decap_config.valid))
1841 return -EINVAL;
1842
1843 router->nve_decap_config.ul_tb_id = ul_tb_id;
1844 router->nve_decap_config.tunnel_index = tunnel_index;
1845 router->nve_decap_config.ul_proto = ul_proto;
1846 router->nve_decap_config.ul_sip = *ul_sip;
1847 router->nve_decap_config.valid = true;
1848
0c69e0fc
IS
1849 /* It is valid to create a tunnel with a local IP and only later
1850 * assign this IP address to a local interface
1851 */
1852 fib_entry = mlxsw_sp_router_ip2me_fib_entry_find(mlxsw_sp, ul_tb_id,
1853 ul_proto, ul_sip,
1854 type);
1855 if (!fib_entry)
1856 return 0;
1857
1858 fib_entry->decap.tunnel_index = tunnel_index;
1859 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP;
1860
1861 err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
1862 if (err)
1863 goto err_fib_entry_update;
1864
1865 return 0;
1866
1867err_fib_entry_update:
1868 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
1869 mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
1870 return err;
1871}
1872
1873void mlxsw_sp_router_nve_demote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
1874 enum mlxsw_sp_l3proto ul_proto,
1875 const union mlxsw_sp_l3addr *ul_sip)
1876{
1877 enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP;
8e18d85e 1878 struct mlxsw_sp_router *router = mlxsw_sp->router;
0c69e0fc
IS
1879 struct mlxsw_sp_fib_entry *fib_entry;
1880
8e18d85e
IS
1881 if (WARN_ON_ONCE(!router->nve_decap_config.valid))
1882 return;
1883
1884 router->nve_decap_config.valid = false;
1885
0c69e0fc
IS
1886 fib_entry = mlxsw_sp_router_ip2me_fib_entry_find(mlxsw_sp, ul_tb_id,
1887 ul_proto, ul_sip,
1888 type);
1889 if (!fib_entry)
1890 return;
1891
1892 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
1893 mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
1894}
1895
8e18d85e
IS
1896static bool mlxsw_sp_router_nve_is_decap(struct mlxsw_sp *mlxsw_sp,
1897 u32 ul_tb_id,
1898 enum mlxsw_sp_l3proto ul_proto,
1899 const union mlxsw_sp_l3addr *ul_sip)
1900{
1901 struct mlxsw_sp_router *router = mlxsw_sp->router;
1902
1903 return router->nve_decap_config.valid &&
1904 router->nve_decap_config.ul_tb_id == ul_tb_id &&
1905 router->nve_decap_config.ul_proto == ul_proto &&
1906 !memcmp(&router->nve_decap_config.ul_sip, ul_sip,
1907 sizeof(*ul_sip));
1908}
1909
6cf3c971 1910struct mlxsw_sp_neigh_key {
33b1341c 1911 struct neighbour *n;
6cf3c971
JP
1912};
1913
1914struct mlxsw_sp_neigh_entry {
9665b745 1915 struct list_head rif_list_node;
6cf3c971
JP
1916 struct rhash_head ht_node;
1917 struct mlxsw_sp_neigh_key key;
1918 u16 rif;
5c8802f1 1919 bool connected;
a6bf9e93 1920 unsigned char ha[ETH_ALEN];
a7ff87ac
JP
1921 struct list_head nexthop_list; /* list of nexthops using
1922 * this neigh entry
1923 */
b2157149 1924 struct list_head nexthop_neighs_list_node;
7cfcbc75
AS
1925 unsigned int counter_index;
1926 bool counter_valid;
6cf3c971
JP
1927};
1928
1929static const struct rhashtable_params mlxsw_sp_neigh_ht_params = {
1930 .key_offset = offsetof(struct mlxsw_sp_neigh_entry, key),
1931 .head_offset = offsetof(struct mlxsw_sp_neigh_entry, ht_node),
1932 .key_len = sizeof(struct mlxsw_sp_neigh_key),
1933};
1934
f17cc84d
AS
1935struct mlxsw_sp_neigh_entry *
1936mlxsw_sp_rif_neigh_next(struct mlxsw_sp_rif *rif,
1937 struct mlxsw_sp_neigh_entry *neigh_entry)
1938{
1939 if (!neigh_entry) {
1940 if (list_empty(&rif->neigh_list))
1941 return NULL;
1942 else
1943 return list_first_entry(&rif->neigh_list,
1944 typeof(*neigh_entry),
1945 rif_list_node);
1946 }
ec2437f4 1947 if (list_is_last(&neigh_entry->rif_list_node, &rif->neigh_list))
f17cc84d
AS
1948 return NULL;
1949 return list_next_entry(neigh_entry, rif_list_node);
1950}
1951
1952int mlxsw_sp_neigh_entry_type(struct mlxsw_sp_neigh_entry *neigh_entry)
1953{
1954 return neigh_entry->key.n->tbl->family;
1955}
1956
1957unsigned char *
1958mlxsw_sp_neigh_entry_ha(struct mlxsw_sp_neigh_entry *neigh_entry)
1959{
1960 return neigh_entry->ha;
1961}
1962
1963u32 mlxsw_sp_neigh4_entry_dip(struct mlxsw_sp_neigh_entry *neigh_entry)
1964{
1965 struct neighbour *n;
1966
1967 n = neigh_entry->key.n;
1968 return ntohl(*((__be32 *) n->primary_key));
1969}
1970
0250768c
AS
1971struct in6_addr *
1972mlxsw_sp_neigh6_entry_dip(struct mlxsw_sp_neigh_entry *neigh_entry)
1973{
1974 struct neighbour *n;
1975
1976 n = neigh_entry->key.n;
1977 return (struct in6_addr *) &n->primary_key;
1978}
1979
7cfcbc75
AS
1980int mlxsw_sp_neigh_counter_get(struct mlxsw_sp *mlxsw_sp,
1981 struct mlxsw_sp_neigh_entry *neigh_entry,
1982 u64 *p_counter)
1983{
1984 if (!neigh_entry->counter_valid)
1985 return -EINVAL;
1986
1987 return mlxsw_sp_flow_counter_get(mlxsw_sp, neigh_entry->counter_index,
1988 p_counter, NULL);
1989}
1990
6cf3c971 1991static struct mlxsw_sp_neigh_entry *
5c8802f1
IS
1992mlxsw_sp_neigh_entry_alloc(struct mlxsw_sp *mlxsw_sp, struct neighbour *n,
1993 u16 rif)
6cf3c971
JP
1994{
1995 struct mlxsw_sp_neigh_entry *neigh_entry;
1996
5c8802f1 1997 neigh_entry = kzalloc(sizeof(*neigh_entry), GFP_KERNEL);
6cf3c971
JP
1998 if (!neigh_entry)
1999 return NULL;
5c8802f1 2000
33b1341c 2001 neigh_entry->key.n = n;
6cf3c971 2002 neigh_entry->rif = rif;
a7ff87ac 2003 INIT_LIST_HEAD(&neigh_entry->nexthop_list);
5c8802f1 2004
6cf3c971
JP
2005 return neigh_entry;
2006}
2007
5c8802f1 2008static void mlxsw_sp_neigh_entry_free(struct mlxsw_sp_neigh_entry *neigh_entry)
6cf3c971
JP
2009{
2010 kfree(neigh_entry);
2011}
2012
5c8802f1
IS
2013static int
2014mlxsw_sp_neigh_entry_insert(struct mlxsw_sp *mlxsw_sp,
2015 struct mlxsw_sp_neigh_entry *neigh_entry)
6cf3c971 2016{
9011b677 2017 return rhashtable_insert_fast(&mlxsw_sp->router->neigh_ht,
5c8802f1
IS
2018 &neigh_entry->ht_node,
2019 mlxsw_sp_neigh_ht_params);
2020}
6cf3c971 2021
5c8802f1
IS
2022static void
2023mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp,
2024 struct mlxsw_sp_neigh_entry *neigh_entry)
2025{
9011b677 2026 rhashtable_remove_fast(&mlxsw_sp->router->neigh_ht,
5c8802f1
IS
2027 &neigh_entry->ht_node,
2028 mlxsw_sp_neigh_ht_params);
6cf3c971
JP
2029}
2030
7cfcbc75 2031static bool
1ed5574c
AS
2032mlxsw_sp_neigh_counter_should_alloc(struct mlxsw_sp *mlxsw_sp,
2033 struct mlxsw_sp_neigh_entry *neigh_entry)
7cfcbc75
AS
2034{
2035 struct devlink *devlink;
1ed5574c
AS
2036 const char *table_name;
2037
2038 switch (mlxsw_sp_neigh_entry_type(neigh_entry)) {
2039 case AF_INET:
2040 table_name = MLXSW_SP_DPIPE_TABLE_NAME_HOST4;
2041 break;
2042 case AF_INET6:
2043 table_name = MLXSW_SP_DPIPE_TABLE_NAME_HOST6;
2044 break;
2045 default:
2046 WARN_ON(1);
2047 return false;
2048 }
7cfcbc75
AS
2049
2050 devlink = priv_to_devlink(mlxsw_sp->core);
1ed5574c 2051 return devlink_dpipe_table_counter_enabled(devlink, table_name);
7cfcbc75
AS
2052}
2053
2054static void
2055mlxsw_sp_neigh_counter_alloc(struct mlxsw_sp *mlxsw_sp,
2056 struct mlxsw_sp_neigh_entry *neigh_entry)
2057{
1ed5574c 2058 if (!mlxsw_sp_neigh_counter_should_alloc(mlxsw_sp, neigh_entry))
7cfcbc75
AS
2059 return;
2060
2061 if (mlxsw_sp_flow_counter_alloc(mlxsw_sp, &neigh_entry->counter_index))
2062 return;
2063
2064 neigh_entry->counter_valid = true;
2065}
2066
2067static void
2068mlxsw_sp_neigh_counter_free(struct mlxsw_sp *mlxsw_sp,
2069 struct mlxsw_sp_neigh_entry *neigh_entry)
2070{
2071 if (!neigh_entry->counter_valid)
2072 return;
2073 mlxsw_sp_flow_counter_free(mlxsw_sp,
2074 neigh_entry->counter_index);
2075 neigh_entry->counter_valid = false;
2076}
2077
5c8802f1
IS
2078static struct mlxsw_sp_neigh_entry *
2079mlxsw_sp_neigh_entry_create(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
6cf3c971 2080{
6cf3c971 2081 struct mlxsw_sp_neigh_entry *neigh_entry;
bf95233e 2082 struct mlxsw_sp_rif *rif;
6cf3c971
JP
2083 int err;
2084
bf95233e
AS
2085 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, n->dev);
2086 if (!rif)
5c8802f1 2087 return ERR_PTR(-EINVAL);
6cf3c971 2088
bf95233e 2089 neigh_entry = mlxsw_sp_neigh_entry_alloc(mlxsw_sp, n, rif->rif_index);
6cf3c971 2090 if (!neigh_entry)
5c8802f1
IS
2091 return ERR_PTR(-ENOMEM);
2092
6cf3c971
JP
2093 err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
2094 if (err)
2095 goto err_neigh_entry_insert;
5c8802f1 2096
7cfcbc75 2097 mlxsw_sp_neigh_counter_alloc(mlxsw_sp, neigh_entry);
bf95233e 2098 list_add(&neigh_entry->rif_list_node, &rif->neigh_list);
9665b745 2099
5c8802f1 2100 return neigh_entry;
6cf3c971
JP
2101
2102err_neigh_entry_insert:
5c8802f1
IS
2103 mlxsw_sp_neigh_entry_free(neigh_entry);
2104 return ERR_PTR(err);
6cf3c971
JP
2105}
2106
5c8802f1
IS
2107static void
2108mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp *mlxsw_sp,
2109 struct mlxsw_sp_neigh_entry *neigh_entry)
6cf3c971 2110{
9665b745 2111 list_del(&neigh_entry->rif_list_node);
7cfcbc75 2112 mlxsw_sp_neigh_counter_free(mlxsw_sp, neigh_entry);
5c8802f1
IS
2113 mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
2114 mlxsw_sp_neigh_entry_free(neigh_entry);
2115}
6cf3c971 2116
5c8802f1
IS
2117static struct mlxsw_sp_neigh_entry *
2118mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
2119{
2120 struct mlxsw_sp_neigh_key key;
6cf3c971 2121
5c8802f1 2122 key.n = n;
9011b677 2123 return rhashtable_lookup_fast(&mlxsw_sp->router->neigh_ht,
5c8802f1 2124 &key, mlxsw_sp_neigh_ht_params);
6cf3c971
JP
2125}
2126
c723c735
YG
2127static void
2128mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp *mlxsw_sp)
2129{
a6c9b5d1 2130 unsigned long interval;
c723c735 2131
b5f3e0d4 2132#if IS_ENABLED(CONFIG_IPV6)
a6c9b5d1
AS
2133 interval = min_t(unsigned long,
2134 NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME),
2135 NEIGH_VAR(&nd_tbl.parms, DELAY_PROBE_TIME));
b5f3e0d4
IS
2136#else
2137 interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME);
2138#endif
9011b677 2139 mlxsw_sp->router->neighs_update.interval = jiffies_to_msecs(interval);
c723c735
YG
2140}
2141
2142static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
2143 char *rauhtd_pl,
2144 int ent_index)
2145{
2146 struct net_device *dev;
2147 struct neighbour *n;
2148 __be32 dipn;
2149 u32 dip;
2150 u16 rif;
2151
2152 mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip);
2153
5f9efffb 2154 if (!mlxsw_sp->router->rifs[rif]) {
c723c735
YG
2155 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
2156 return;
2157 }
2158
2159 dipn = htonl(dip);
5f9efffb 2160 dev = mlxsw_sp->router->rifs[rif]->dev;
c723c735 2161 n = neigh_lookup(&arp_tbl, &dipn, dev);
1ecdaea0 2162 if (!n)
c723c735 2163 return;
c723c735
YG
2164
2165 netdev_dbg(dev, "Updating neighbour with IP=%pI4h\n", &dip);
2166 neigh_event_send(n, NULL);
2167 neigh_release(n);
2168}
2169
df9a21f1 2170#if IS_ENABLED(CONFIG_IPV6)
60f040ca
AS
2171static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
2172 char *rauhtd_pl,
2173 int rec_index)
2174{
2175 struct net_device *dev;
2176 struct neighbour *n;
2177 struct in6_addr dip;
2178 u16 rif;
2179
2180 mlxsw_reg_rauhtd_ent_ipv6_unpack(rauhtd_pl, rec_index, &rif,
2181 (char *) &dip);
2182
2183 if (!mlxsw_sp->router->rifs[rif]) {
2184 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
2185 return;
2186 }
2187
2188 dev = mlxsw_sp->router->rifs[rif]->dev;
2189 n = neigh_lookup(&nd_tbl, &dip, dev);
1ecdaea0 2190 if (!n)
60f040ca 2191 return;
60f040ca
AS
2192
2193 netdev_dbg(dev, "Updating neighbour with IP=%pI6c\n", &dip);
2194 neigh_event_send(n, NULL);
2195 neigh_release(n);
2196}
b5f3e0d4
IS
2197#else
2198static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
2199 char *rauhtd_pl,
2200 int rec_index)
2201{
2202}
2203#endif
60f040ca 2204
c723c735
YG
2205static void mlxsw_sp_router_neigh_rec_ipv4_process(struct mlxsw_sp *mlxsw_sp,
2206 char *rauhtd_pl,
2207 int rec_index)
2208{
2209 u8 num_entries;
2210 int i;
2211
2212 num_entries = mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl,
2213 rec_index);
2214 /* Hardware starts counting at 0, so add 1. */
2215 num_entries++;
2216
2217 /* Each record consists of several neighbour entries. */
2218 for (i = 0; i < num_entries; i++) {
2219 int ent_index;
2220
2221 ent_index = rec_index * MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC + i;
2222 mlxsw_sp_router_neigh_ent_ipv4_process(mlxsw_sp, rauhtd_pl,
2223 ent_index);
2224 }
2225
2226}
2227
60f040ca
AS
2228static void mlxsw_sp_router_neigh_rec_ipv6_process(struct mlxsw_sp *mlxsw_sp,
2229 char *rauhtd_pl,
2230 int rec_index)
2231{
2232 /* One record contains one entry. */
2233 mlxsw_sp_router_neigh_ent_ipv6_process(mlxsw_sp, rauhtd_pl,
2234 rec_index);
2235}
2236
c723c735
YG
2237static void mlxsw_sp_router_neigh_rec_process(struct mlxsw_sp *mlxsw_sp,
2238 char *rauhtd_pl, int rec_index)
2239{
2240 switch (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl, rec_index)) {
2241 case MLXSW_REG_RAUHTD_TYPE_IPV4:
2242 mlxsw_sp_router_neigh_rec_ipv4_process(mlxsw_sp, rauhtd_pl,
2243 rec_index);
2244 break;
2245 case MLXSW_REG_RAUHTD_TYPE_IPV6:
60f040ca
AS
2246 mlxsw_sp_router_neigh_rec_ipv6_process(mlxsw_sp, rauhtd_pl,
2247 rec_index);
c723c735
YG
2248 break;
2249 }
2250}
2251
42cdb338
AS
2252static bool mlxsw_sp_router_rauhtd_is_full(char *rauhtd_pl)
2253{
2254 u8 num_rec, last_rec_index, num_entries;
2255
2256 num_rec = mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl);
2257 last_rec_index = num_rec - 1;
2258
2259 if (num_rec < MLXSW_REG_RAUHTD_REC_MAX_NUM)
2260 return false;
2261 if (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl, last_rec_index) ==
2262 MLXSW_REG_RAUHTD_TYPE_IPV6)
2263 return true;
2264
2265 num_entries = mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl,
2266 last_rec_index);
2267 if (++num_entries == MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC)
2268 return true;
2269 return false;
2270}
2271
60f040ca
AS
2272static int
2273__mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp,
2274 char *rauhtd_pl,
2275 enum mlxsw_reg_rauhtd_type type)
c723c735 2276{
60f040ca
AS
2277 int i, num_rec;
2278 int err;
c723c735
YG
2279
2280 /* Make sure the neighbour's netdev isn't removed in the
2281 * process.
2282 */
2283 rtnl_lock();
2284 do {
60f040ca 2285 mlxsw_reg_rauhtd_pack(rauhtd_pl, type);
c723c735
YG
2286 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(rauhtd),
2287 rauhtd_pl);
2288 if (err) {
7ff176f8 2289 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to dump neighbour table\n");
c723c735
YG
2290 break;
2291 }
2292 num_rec = mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl);
2293 for (i = 0; i < num_rec; i++)
2294 mlxsw_sp_router_neigh_rec_process(mlxsw_sp, rauhtd_pl,
2295 i);
42cdb338 2296 } while (mlxsw_sp_router_rauhtd_is_full(rauhtd_pl));
c723c735
YG
2297 rtnl_unlock();
2298
60f040ca
AS
2299 return err;
2300}
2301
2302static int mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp)
2303{
2304 enum mlxsw_reg_rauhtd_type type;
2305 char *rauhtd_pl;
2306 int err;
2307
2308 rauhtd_pl = kmalloc(MLXSW_REG_RAUHTD_LEN, GFP_KERNEL);
2309 if (!rauhtd_pl)
2310 return -ENOMEM;
2311
2312 type = MLXSW_REG_RAUHTD_TYPE_IPV4;
2313 err = __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp, rauhtd_pl, type);
2314 if (err)
2315 goto out;
2316
2317 type = MLXSW_REG_RAUHTD_TYPE_IPV6;
2318 err = __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp, rauhtd_pl, type);
2319out:
c723c735 2320 kfree(rauhtd_pl);
b2157149
YG
2321 return err;
2322}
2323
2324static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp)
2325{
2326 struct mlxsw_sp_neigh_entry *neigh_entry;
2327
2328 /* Take RTNL mutex here to prevent lists from changes */
2329 rtnl_lock();
9011b677 2330 list_for_each_entry(neigh_entry, &mlxsw_sp->router->nexthop_neighs_list,
8a0b7275 2331 nexthop_neighs_list_node)
b2157149
YG
2332 /* If this neigh have nexthops, make the kernel think this neigh
2333 * is active regardless of the traffic.
2334 */
8a0b7275 2335 neigh_event_send(neigh_entry->key.n, NULL);
b2157149
YG
2336 rtnl_unlock();
2337}
2338
2339static void
2340mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp *mlxsw_sp)
2341{
9011b677 2342 unsigned long interval = mlxsw_sp->router->neighs_update.interval;
b2157149 2343
9011b677 2344 mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw,
b2157149
YG
2345 msecs_to_jiffies(interval));
2346}
2347
2348static void mlxsw_sp_router_neighs_update_work(struct work_struct *work)
2349{
9011b677 2350 struct mlxsw_sp_router *router;
b2157149
YG
2351 int err;
2352
9011b677
IS
2353 router = container_of(work, struct mlxsw_sp_router,
2354 neighs_update.dw.work);
2355 err = mlxsw_sp_router_neighs_update_rauhtd(router->mlxsw_sp);
b2157149 2356 if (err)
9011b677 2357 dev_err(router->mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity");
b2157149 2358
9011b677 2359 mlxsw_sp_router_neighs_update_nh(router->mlxsw_sp);
b2157149 2360
9011b677 2361 mlxsw_sp_router_neighs_update_work_schedule(router->mlxsw_sp);
c723c735
YG
2362}
2363
0b2361d9
YG
2364static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work)
2365{
2366 struct mlxsw_sp_neigh_entry *neigh_entry;
9011b677 2367 struct mlxsw_sp_router *router;
0b2361d9 2368
9011b677
IS
2369 router = container_of(work, struct mlxsw_sp_router,
2370 nexthop_probe_dw.work);
0b2361d9
YG
2371 /* Iterate over nexthop neighbours, find those who are unresolved and
2372 * send arp on them. This solves the chicken-egg problem when
2373 * the nexthop wouldn't get offloaded until the neighbor is resolved
2374 * but it wouldn't get resolved ever in case traffic is flowing in HW
2375 * using different nexthop.
2376 *
2377 * Take RTNL mutex here to prevent lists from changes.
2378 */
2379 rtnl_lock();
9011b677 2380 list_for_each_entry(neigh_entry, &router->nexthop_neighs_list,
8a0b7275 2381 nexthop_neighs_list_node)
01b1aa35 2382 if (!neigh_entry->connected)
33b1341c 2383 neigh_event_send(neigh_entry->key.n, NULL);
0b2361d9
YG
2384 rtnl_unlock();
2385
9011b677 2386 mlxsw_core_schedule_dw(&router->nexthop_probe_dw,
0b2361d9
YG
2387 MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL);
2388}
2389
a7ff87ac
JP
2390static void
2391mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
2392 struct mlxsw_sp_neigh_entry *neigh_entry,
83d57826 2393 bool removing, bool dead);
a7ff87ac 2394
5c8802f1
IS
2395static enum mlxsw_reg_rauht_op mlxsw_sp_rauht_op(bool adding)
2396{
2397 return adding ? MLXSW_REG_RAUHT_OP_WRITE_ADD :
2398 MLXSW_REG_RAUHT_OP_WRITE_DELETE;
2399}
2400
a85e84e0 2401static int
5c8802f1
IS
2402mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp *mlxsw_sp,
2403 struct mlxsw_sp_neigh_entry *neigh_entry,
2404 enum mlxsw_reg_rauht_op op)
a6bf9e93 2405{
33b1341c 2406 struct neighbour *n = neigh_entry->key.n;
5c8802f1 2407 u32 dip = ntohl(*((__be32 *) n->primary_key));
a6bf9e93 2408 char rauht_pl[MLXSW_REG_RAUHT_LEN];
5c8802f1
IS
2409
2410 mlxsw_reg_rauht_pack4(rauht_pl, op, neigh_entry->rif, neigh_entry->ha,
2411 dip);
7cfcbc75
AS
2412 if (neigh_entry->counter_valid)
2413 mlxsw_reg_rauht_pack_counter(rauht_pl,
2414 neigh_entry->counter_index);
a85e84e0 2415 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
5c8802f1
IS
2416}
2417
a85e84e0 2418static int
d5eb89cf
AS
2419mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp *mlxsw_sp,
2420 struct mlxsw_sp_neigh_entry *neigh_entry,
2421 enum mlxsw_reg_rauht_op op)
2422{
2423 struct neighbour *n = neigh_entry->key.n;
2424 char rauht_pl[MLXSW_REG_RAUHT_LEN];
2425 const char *dip = n->primary_key;
2426
2427 mlxsw_reg_rauht_pack6(rauht_pl, op, neigh_entry->rif, neigh_entry->ha,
2428 dip);
7cfcbc75
AS
2429 if (neigh_entry->counter_valid)
2430 mlxsw_reg_rauht_pack_counter(rauht_pl,
2431 neigh_entry->counter_index);
a85e84e0 2432 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
d5eb89cf
AS
2433}
2434
1d1056d8 2435bool mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry *neigh_entry)
d5eb89cf 2436{
1d1056d8
AS
2437 struct neighbour *n = neigh_entry->key.n;
2438
d5eb89cf
AS
2439 /* Packets with a link-local destination address are trapped
2440 * after LPM lookup and never reach the neighbour table, so
2441 * there is no need to program such neighbours to the device.
2442 */
2443 if (ipv6_addr_type((struct in6_addr *) &n->primary_key) &
2444 IPV6_ADDR_LINKLOCAL)
2445 return true;
2446 return false;
2447}
2448
5c8802f1
IS
2449static void
2450mlxsw_sp_neigh_entry_update(struct mlxsw_sp *mlxsw_sp,
2451 struct mlxsw_sp_neigh_entry *neigh_entry,
2452 bool adding)
2453{
a85e84e0
IS
2454 enum mlxsw_reg_rauht_op op = mlxsw_sp_rauht_op(adding);
2455 int err;
2456
5c8802f1
IS
2457 if (!adding && !neigh_entry->connected)
2458 return;
2459 neigh_entry->connected = adding;
b5f3e0d4 2460 if (neigh_entry->key.n->tbl->family == AF_INET) {
a85e84e0
IS
2461 err = mlxsw_sp_router_neigh_entry_op4(mlxsw_sp, neigh_entry,
2462 op);
2463 if (err)
2464 return;
b5f3e0d4 2465 } else if (neigh_entry->key.n->tbl->family == AF_INET6) {
1d1056d8 2466 if (mlxsw_sp_neigh_ipv6_ignore(neigh_entry))
d5eb89cf 2467 return;
a85e84e0
IS
2468 err = mlxsw_sp_router_neigh_entry_op6(mlxsw_sp, neigh_entry,
2469 op);
2470 if (err)
2471 return;
d5eb89cf 2472 } else {
5c8802f1 2473 WARN_ON_ONCE(1);
caf345a1 2474 return;
d5eb89cf 2475 }
caf345a1
IS
2476
2477 if (adding)
2478 neigh_entry->key.n->flags |= NTF_OFFLOADED;
2479 else
2480 neigh_entry->key.n->flags &= ~NTF_OFFLOADED;
5c8802f1
IS
2481}
2482
a481d713
AS
2483void
2484mlxsw_sp_neigh_entry_counter_update(struct mlxsw_sp *mlxsw_sp,
2485 struct mlxsw_sp_neigh_entry *neigh_entry,
2486 bool adding)
2487{
2488 if (adding)
2489 mlxsw_sp_neigh_counter_alloc(mlxsw_sp, neigh_entry);
2490 else
2491 mlxsw_sp_neigh_counter_free(mlxsw_sp, neigh_entry);
2492 mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, true);
2493}
2494
ceb8881d 2495struct mlxsw_sp_netevent_work {
5c8802f1
IS
2496 struct work_struct work;
2497 struct mlxsw_sp *mlxsw_sp;
2498 struct neighbour *n;
2499};
2500
2501static void mlxsw_sp_router_neigh_event_work(struct work_struct *work)
2502{
ceb8881d
IS
2503 struct mlxsw_sp_netevent_work *net_work =
2504 container_of(work, struct mlxsw_sp_netevent_work, work);
2505 struct mlxsw_sp *mlxsw_sp = net_work->mlxsw_sp;
5c8802f1 2506 struct mlxsw_sp_neigh_entry *neigh_entry;
ceb8881d 2507 struct neighbour *n = net_work->n;
5c8802f1 2508 unsigned char ha[ETH_ALEN];
a6bf9e93 2509 bool entry_connected;
93a87e5e 2510 u8 nud_state, dead;
a6bf9e93 2511
5c8802f1
IS
2512 /* If these parameters are changed after we release the lock,
2513 * then we are guaranteed to receive another event letting us
2514 * know about it.
2515 */
a6bf9e93 2516 read_lock_bh(&n->lock);
5c8802f1 2517 memcpy(ha, n->ha, ETH_ALEN);
a6bf9e93 2518 nud_state = n->nud_state;
93a87e5e 2519 dead = n->dead;
a6bf9e93
YG
2520 read_unlock_bh(&n->lock);
2521
5c8802f1 2522 rtnl_lock();
803335ac
PM
2523 mlxsw_sp_span_respin(mlxsw_sp);
2524
93a87e5e 2525 entry_connected = nud_state & NUD_VALID && !dead;
5c8802f1
IS
2526 neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
2527 if (!entry_connected && !neigh_entry)
2528 goto out;
2529 if (!neigh_entry) {
2530 neigh_entry = mlxsw_sp_neigh_entry_create(mlxsw_sp, n);
2531 if (IS_ERR(neigh_entry))
2532 goto out;
a6bf9e93
YG
2533 }
2534
5c8802f1
IS
2535 memcpy(neigh_entry->ha, ha, ETH_ALEN);
2536 mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, entry_connected);
83d57826
IS
2537 mlxsw_sp_nexthop_neigh_update(mlxsw_sp, neigh_entry, !entry_connected,
2538 dead);
5c8802f1
IS
2539
2540 if (!neigh_entry->connected && list_empty(&neigh_entry->nexthop_list))
2541 mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
2542
2543out:
2544 rtnl_unlock();
a6bf9e93 2545 neigh_release(n);
ceb8881d 2546 kfree(net_work);
a6bf9e93
YG
2547}
2548
28678f07
IS
2549static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp);
2550
2551static void mlxsw_sp_router_mp_hash_event_work(struct work_struct *work)
2552{
2553 struct mlxsw_sp_netevent_work *net_work =
2554 container_of(work, struct mlxsw_sp_netevent_work, work);
2555 struct mlxsw_sp *mlxsw_sp = net_work->mlxsw_sp;
2556
2557 mlxsw_sp_mp_hash_init(mlxsw_sp);
2558 kfree(net_work);
2559}
2560
64953423
PM
2561static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp);
2562
2563static void mlxsw_sp_router_update_priority_work(struct work_struct *work)
2564{
2565 struct mlxsw_sp_netevent_work *net_work =
2566 container_of(work, struct mlxsw_sp_netevent_work, work);
2567 struct mlxsw_sp *mlxsw_sp = net_work->mlxsw_sp;
2568
2569 __mlxsw_sp_router_init(mlxsw_sp);
2570 kfree(net_work);
2571}
2572
1f65a33f
PM
2573static int mlxsw_sp_router_schedule_work(struct net *net,
2574 struct notifier_block *nb,
2575 void (*cb)(struct work_struct *))
2576{
2577 struct mlxsw_sp_netevent_work *net_work;
2578 struct mlxsw_sp_router *router;
2579
053e92aa
JP
2580 router = container_of(nb, struct mlxsw_sp_router, netevent_nb);
2581 if (!net_eq(net, mlxsw_sp_net(router->mlxsw_sp)))
1f65a33f
PM
2582 return NOTIFY_DONE;
2583
2584 net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
2585 if (!net_work)
2586 return NOTIFY_BAD;
2587
1f65a33f
PM
2588 INIT_WORK(&net_work->work, cb);
2589 net_work->mlxsw_sp = router->mlxsw_sp;
2590 mlxsw_core_schedule_work(&net_work->work);
2591 return NOTIFY_DONE;
2592}
2593
28678f07 2594static int mlxsw_sp_router_netevent_event(struct notifier_block *nb,
48fac885 2595 unsigned long event, void *ptr)
c723c735 2596{
ceb8881d 2597 struct mlxsw_sp_netevent_work *net_work;
c723c735
YG
2598 struct mlxsw_sp_port *mlxsw_sp_port;
2599 struct mlxsw_sp *mlxsw_sp;
2600 unsigned long interval;
2601 struct neigh_parms *p;
a6bf9e93 2602 struct neighbour *n;
c723c735
YG
2603
2604 switch (event) {
2605 case NETEVENT_DELAY_PROBE_TIME_UPDATE:
2606 p = ptr;
2607
2608 /* We don't care about changes in the default table. */
b5f3e0d4
IS
2609 if (!p->dev || (p->tbl->family != AF_INET &&
2610 p->tbl->family != AF_INET6))
c723c735
YG
2611 return NOTIFY_DONE;
2612
2613 /* We are in atomic context and can't take RTNL mutex,
2614 * so use RCU variant to walk the device chain.
2615 */
2616 mlxsw_sp_port = mlxsw_sp_port_lower_dev_hold(p->dev);
2617 if (!mlxsw_sp_port)
2618 return NOTIFY_DONE;
2619
2620 mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
2621 interval = jiffies_to_msecs(NEIGH_VAR(p, DELAY_PROBE_TIME));
9011b677 2622 mlxsw_sp->router->neighs_update.interval = interval;
c723c735
YG
2623
2624 mlxsw_sp_port_dev_put(mlxsw_sp_port);
2625 break;
a6bf9e93
YG
2626 case NETEVENT_NEIGH_UPDATE:
2627 n = ptr;
a6bf9e93 2628
b5f3e0d4 2629 if (n->tbl->family != AF_INET && n->tbl->family != AF_INET6)
a6bf9e93
YG
2630 return NOTIFY_DONE;
2631
5c8802f1 2632 mlxsw_sp_port = mlxsw_sp_port_lower_dev_hold(n->dev);
a6bf9e93
YG
2633 if (!mlxsw_sp_port)
2634 return NOTIFY_DONE;
2635
ceb8881d
IS
2636 net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC);
2637 if (!net_work) {
a6bf9e93 2638 mlxsw_sp_port_dev_put(mlxsw_sp_port);
5c8802f1 2639 return NOTIFY_BAD;
a6bf9e93 2640 }
5c8802f1 2641
ceb8881d
IS
2642 INIT_WORK(&net_work->work, mlxsw_sp_router_neigh_event_work);
2643 net_work->mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
2644 net_work->n = n;
a6bf9e93
YG
2645
2646 /* Take a reference to ensure the neighbour won't be
2647 * destructed until we drop the reference in delayed
2648 * work.
2649 */
2650 neigh_clone(n);
ceb8881d 2651 mlxsw_core_schedule_work(&net_work->work);
5c8802f1 2652 mlxsw_sp_port_dev_put(mlxsw_sp_port);
a6bf9e93 2653 break;
3192dac6 2654 case NETEVENT_IPV4_MPATH_HASH_UPDATE:
5e18b9c5 2655 case NETEVENT_IPV6_MPATH_HASH_UPDATE:
1f65a33f
PM
2656 return mlxsw_sp_router_schedule_work(ptr, nb,
2657 mlxsw_sp_router_mp_hash_event_work);
28678f07 2658
64953423
PM
2659 case NETEVENT_IPV4_FWD_UPDATE_PRIORITY_UPDATE:
2660 return mlxsw_sp_router_schedule_work(ptr, nb,
2661 mlxsw_sp_router_update_priority_work);
c723c735
YG
2662 }
2663
2664 return NOTIFY_DONE;
2665}
2666
6cf3c971
JP
2667static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
2668{
c723c735
YG
2669 int err;
2670
9011b677 2671 err = rhashtable_init(&mlxsw_sp->router->neigh_ht,
c723c735
YG
2672 &mlxsw_sp_neigh_ht_params);
2673 if (err)
2674 return err;
2675
2676 /* Initialize the polling interval according to the default
2677 * table.
2678 */
2679 mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp);
2680
0b2361d9 2681 /* Create the delayed works for the activity_update */
9011b677 2682 INIT_DELAYED_WORK(&mlxsw_sp->router->neighs_update.dw,
c723c735 2683 mlxsw_sp_router_neighs_update_work);
9011b677 2684 INIT_DELAYED_WORK(&mlxsw_sp->router->nexthop_probe_dw,
0b2361d9 2685 mlxsw_sp_router_probe_unresolved_nexthops);
9011b677
IS
2686 mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw, 0);
2687 mlxsw_core_schedule_dw(&mlxsw_sp->router->nexthop_probe_dw, 0);
c723c735 2688 return 0;
6cf3c971
JP
2689}
2690
2691static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)
2692{
9011b677
IS
2693 cancel_delayed_work_sync(&mlxsw_sp->router->neighs_update.dw);
2694 cancel_delayed_work_sync(&mlxsw_sp->router->nexthop_probe_dw);
2695 rhashtable_destroy(&mlxsw_sp->router->neigh_ht);
6cf3c971
JP
2696}
2697
9665b745 2698static void mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
bf95233e 2699 struct mlxsw_sp_rif *rif)
9665b745
IS
2700{
2701 struct mlxsw_sp_neigh_entry *neigh_entry, *tmp;
2702
bf95233e 2703 list_for_each_entry_safe(neigh_entry, tmp, &rif->neigh_list,
8ba6b30e
PM
2704 rif_list_node) {
2705 mlxsw_sp_neigh_entry_update(mlxsw_sp, neigh_entry, false);
9665b745 2706 mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
8ba6b30e 2707 }
9665b745
IS
2708}
2709
35225e47
PM
2710enum mlxsw_sp_nexthop_type {
2711 MLXSW_SP_NEXTHOP_TYPE_ETH,
1012b9ac 2712 MLXSW_SP_NEXTHOP_TYPE_IPIP,
35225e47
PM
2713};
2714
c53b8e1b
IS
2715struct mlxsw_sp_nexthop_key {
2716 struct fib_nh *fib_nh;
2717};
2718
a7ff87ac
JP
2719struct mlxsw_sp_nexthop {
2720 struct list_head neigh_list_node; /* member of neigh entry list */
9665b745 2721 struct list_head rif_list_node;
dbe4598c 2722 struct list_head router_list_node;
a7ff87ac
JP
2723 struct mlxsw_sp_nexthop_group *nh_grp; /* pointer back to the group
2724 * this belongs to
2725 */
c53b8e1b
IS
2726 struct rhash_head ht_node;
2727 struct mlxsw_sp_nexthop_key key;
58adf2c4 2728 unsigned char gw_addr[sizeof(struct in6_addr)];
e6f3b379 2729 int ifindex;
408bd946 2730 int nh_weight;
eb789980
IS
2731 int norm_nh_weight;
2732 int num_adj_entries;
bf95233e 2733 struct mlxsw_sp_rif *rif;
a7ff87ac
JP
2734 u8 should_offload:1, /* set indicates this neigh is connected and
2735 * should be put to KVD linear area of this group.
2736 */
2737 offloaded:1, /* set in case the neigh is actually put into
2738 * KVD linear area of this group.
2739 */
2740 update:1; /* set indicates that MAC of this neigh should be
2741 * updated in HW
2742 */
35225e47
PM
2743 enum mlxsw_sp_nexthop_type type;
2744 union {
2745 struct mlxsw_sp_neigh_entry *neigh_entry;
1012b9ac 2746 struct mlxsw_sp_ipip_entry *ipip_entry;
35225e47 2747 };
a5390278
AS
2748 unsigned int counter_index;
2749 bool counter_valid;
a7ff87ac
JP
2750};
2751
2752struct mlxsw_sp_nexthop_group {
ba31d366 2753 void *priv;
e9ad5e7d 2754 struct rhash_head ht_node;
a7ff87ac 2755 struct list_head fib_list; /* list of fib entries that use this group */
58adf2c4 2756 struct neigh_table *neigh_tbl;
b3e8d1eb
IS
2757 u8 adj_index_valid:1,
2758 gateway:1; /* routes using the group use a gateway */
a7ff87ac
JP
2759 u32 adj_index;
2760 u16 ecmp_size;
2761 u16 count;
eb789980 2762 int sum_norm_weight;
a7ff87ac 2763 struct mlxsw_sp_nexthop nexthops[0];
bf95233e 2764#define nh_rif nexthops[0].rif
a7ff87ac
JP
2765};
2766
427e652a
AS
2767void mlxsw_sp_nexthop_counter_alloc(struct mlxsw_sp *mlxsw_sp,
2768 struct mlxsw_sp_nexthop *nh)
a5390278
AS
2769{
2770 struct devlink *devlink;
2771
2772 devlink = priv_to_devlink(mlxsw_sp->core);
2773 if (!devlink_dpipe_table_counter_enabled(devlink,
2774 MLXSW_SP_DPIPE_TABLE_NAME_ADJ))
2775 return;
2776
2777 if (mlxsw_sp_flow_counter_alloc(mlxsw_sp, &nh->counter_index))
2778 return;
2779
2780 nh->counter_valid = true;
2781}
2782
427e652a
AS
2783void mlxsw_sp_nexthop_counter_free(struct mlxsw_sp *mlxsw_sp,
2784 struct mlxsw_sp_nexthop *nh)
a5390278
AS
2785{
2786 if (!nh->counter_valid)
2787 return;
2788 mlxsw_sp_flow_counter_free(mlxsw_sp, nh->counter_index);
2789 nh->counter_valid = false;
2790}
2791
2792int mlxsw_sp_nexthop_counter_get(struct mlxsw_sp *mlxsw_sp,
2793 struct mlxsw_sp_nexthop *nh, u64 *p_counter)
2794{
2795 if (!nh->counter_valid)
2796 return -EINVAL;
2797
2798 return mlxsw_sp_flow_counter_get(mlxsw_sp, nh->counter_index,
2799 p_counter, NULL);
2800}
2801
c556cd28
AS
2802struct mlxsw_sp_nexthop *mlxsw_sp_nexthop_next(struct mlxsw_sp_router *router,
2803 struct mlxsw_sp_nexthop *nh)
2804{
2805 if (!nh) {
2806 if (list_empty(&router->nexthop_list))
2807 return NULL;
2808 else
2809 return list_first_entry(&router->nexthop_list,
2810 typeof(*nh), router_list_node);
2811 }
2812 if (list_is_last(&nh->router_list_node, &router->nexthop_list))
2813 return NULL;
2814 return list_next_entry(nh, router_list_node);
2815}
2816
2817bool mlxsw_sp_nexthop_offload(struct mlxsw_sp_nexthop *nh)
2818{
2819 return nh->offloaded;
2820}
2821
2822unsigned char *mlxsw_sp_nexthop_ha(struct mlxsw_sp_nexthop *nh)
2823{
2824 if (!nh->offloaded)
2825 return NULL;
2826 return nh->neigh_entry->ha;
2827}
2828
2829int mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop *nh, u32 *p_adj_index,
e69cd9d7 2830 u32 *p_adj_size, u32 *p_adj_hash_index)
c556cd28
AS
2831{
2832 struct mlxsw_sp_nexthop_group *nh_grp = nh->nh_grp;
2833 u32 adj_hash_index = 0;
2834 int i;
2835
2836 if (!nh->offloaded || !nh_grp->adj_index_valid)
2837 return -EINVAL;
2838
2839 *p_adj_index = nh_grp->adj_index;
e69cd9d7 2840 *p_adj_size = nh_grp->ecmp_size;
c556cd28
AS
2841
2842 for (i = 0; i < nh_grp->count; i++) {
2843 struct mlxsw_sp_nexthop *nh_iter = &nh_grp->nexthops[i];
2844
2845 if (nh_iter == nh)
2846 break;
2847 if (nh_iter->offloaded)
eb789980 2848 adj_hash_index += nh_iter->num_adj_entries;
c556cd28
AS
2849 }
2850
2851 *p_adj_hash_index = adj_hash_index;
2852 return 0;
2853}
2854
2855struct mlxsw_sp_rif *mlxsw_sp_nexthop_rif(struct mlxsw_sp_nexthop *nh)
2856{
2857 return nh->rif;
2858}
2859
2860bool mlxsw_sp_nexthop_group_has_ipip(struct mlxsw_sp_nexthop *nh)
2861{
2862 struct mlxsw_sp_nexthop_group *nh_grp = nh->nh_grp;
2863 int i;
2864
2865 for (i = 0; i < nh_grp->count; i++) {
2866 struct mlxsw_sp_nexthop *nh_iter = &nh_grp->nexthops[i];
2867
2868 if (nh_iter->type == MLXSW_SP_NEXTHOP_TYPE_IPIP)
2869 return true;
2870 }
2871 return false;
2872}
2873
ba31d366
AS
2874static struct fib_info *
2875mlxsw_sp_nexthop4_group_fi(const struct mlxsw_sp_nexthop_group *nh_grp)
2876{
2877 return nh_grp->priv;
2878}
2879
2880struct mlxsw_sp_nexthop_group_cmp_arg {
e6f3b379
AS
2881 enum mlxsw_sp_l3proto proto;
2882 union {
2883 struct fib_info *fi;
2884 struct mlxsw_sp_fib6_entry *fib6_entry;
2885 };
ba31d366
AS
2886};
2887
e6f3b379
AS
2888static bool
2889mlxsw_sp_nexthop6_group_has_nexthop(const struct mlxsw_sp_nexthop_group *nh_grp,
3743d88a
IS
2890 const struct in6_addr *gw, int ifindex,
2891 int weight)
e6f3b379
AS
2892{
2893 int i;
2894
2895 for (i = 0; i < nh_grp->count; i++) {
2896 const struct mlxsw_sp_nexthop *nh;
2897
2898 nh = &nh_grp->nexthops[i];
3743d88a 2899 if (nh->ifindex == ifindex && nh->nh_weight == weight &&
e6f3b379
AS
2900 ipv6_addr_equal(gw, (struct in6_addr *) nh->gw_addr))
2901 return true;
2902 }
2903
2904 return false;
2905}
2906
2907static bool
2908mlxsw_sp_nexthop6_group_cmp(const struct mlxsw_sp_nexthop_group *nh_grp,
2909 const struct mlxsw_sp_fib6_entry *fib6_entry)
2910{
2911 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
2912
2913 if (nh_grp->count != fib6_entry->nrt6)
2914 return false;
2915
2916 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
1cf844c7 2917 struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
e6f3b379 2918 struct in6_addr *gw;
3743d88a 2919 int ifindex, weight;
e6f3b379 2920
ad1601ae
DA
2921 ifindex = fib6_nh->fib_nh_dev->ifindex;
2922 weight = fib6_nh->fib_nh_weight;
2923 gw = &fib6_nh->fib_nh_gw6;
3743d88a
IS
2924 if (!mlxsw_sp_nexthop6_group_has_nexthop(nh_grp, gw, ifindex,
2925 weight))
e6f3b379
AS
2926 return false;
2927 }
2928
2929 return true;
2930}
2931
ba31d366
AS
2932static int
2933mlxsw_sp_nexthop_group_cmp(struct rhashtable_compare_arg *arg, const void *ptr)
2934{
2935 const struct mlxsw_sp_nexthop_group_cmp_arg *cmp_arg = arg->key;
2936 const struct mlxsw_sp_nexthop_group *nh_grp = ptr;
2937
e6f3b379
AS
2938 switch (cmp_arg->proto) {
2939 case MLXSW_SP_L3_PROTO_IPV4:
2940 return cmp_arg->fi != mlxsw_sp_nexthop4_group_fi(nh_grp);
2941 case MLXSW_SP_L3_PROTO_IPV6:
2942 return !mlxsw_sp_nexthop6_group_cmp(nh_grp,
2943 cmp_arg->fib6_entry);
2944 default:
2945 WARN_ON(1);
2946 return 1;
2947 }
2948}
2949
2950static int
2951mlxsw_sp_nexthop_group_type(const struct mlxsw_sp_nexthop_group *nh_grp)
2952{
2953 return nh_grp->neigh_tbl->family;
ba31d366
AS
2954}
2955
2956static u32 mlxsw_sp_nexthop_group_hash_obj(const void *data, u32 len, u32 seed)
2957{
2958 const struct mlxsw_sp_nexthop_group *nh_grp = data;
e6f3b379
AS
2959 const struct mlxsw_sp_nexthop *nh;
2960 struct fib_info *fi;
2961 unsigned int val;
2962 int i;
ba31d366 2963
e6f3b379
AS
2964 switch (mlxsw_sp_nexthop_group_type(nh_grp)) {
2965 case AF_INET:
2966 fi = mlxsw_sp_nexthop4_group_fi(nh_grp);
2967 return jhash(&fi, sizeof(fi), seed);
2968 case AF_INET6:
2969 val = nh_grp->count;
2970 for (i = 0; i < nh_grp->count; i++) {
2971 nh = &nh_grp->nexthops[i];
fc25996e 2972 val ^= jhash(&nh->ifindex, sizeof(nh->ifindex), seed);
e6f3b379
AS
2973 }
2974 return jhash(&val, sizeof(val), seed);
2975 default:
2976 WARN_ON(1);
2977 return 0;
2978 }
2979}
2980
2981static u32
2982mlxsw_sp_nexthop6_group_hash(struct mlxsw_sp_fib6_entry *fib6_entry, u32 seed)
2983{
2984 unsigned int val = fib6_entry->nrt6;
2985 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
2986 struct net_device *dev;
2987
2988 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
1cf844c7 2989 dev = mlxsw_sp_rt6->rt->fib6_nh->fib_nh_dev;
fc25996e 2990 val ^= jhash(&dev->ifindex, sizeof(dev->ifindex), seed);
e6f3b379
AS
2991 }
2992
2993 return jhash(&val, sizeof(val), seed);
ba31d366
AS
2994}
2995
2996static u32
2997mlxsw_sp_nexthop_group_hash(const void *data, u32 len, u32 seed)
2998{
2999 const struct mlxsw_sp_nexthop_group_cmp_arg *cmp_arg = data;
3000
e6f3b379
AS
3001 switch (cmp_arg->proto) {
3002 case MLXSW_SP_L3_PROTO_IPV4:
3003 return jhash(&cmp_arg->fi, sizeof(cmp_arg->fi), seed);
3004 case MLXSW_SP_L3_PROTO_IPV6:
3005 return mlxsw_sp_nexthop6_group_hash(cmp_arg->fib6_entry, seed);
3006 default:
3007 WARN_ON(1);
3008 return 0;
3009 }
ba31d366
AS
3010}
3011
e9ad5e7d 3012static const struct rhashtable_params mlxsw_sp_nexthop_group_ht_params = {
e9ad5e7d 3013 .head_offset = offsetof(struct mlxsw_sp_nexthop_group, ht_node),
ba31d366
AS
3014 .hashfn = mlxsw_sp_nexthop_group_hash,
3015 .obj_hashfn = mlxsw_sp_nexthop_group_hash_obj,
3016 .obj_cmpfn = mlxsw_sp_nexthop_group_cmp,
e9ad5e7d
IS
3017};
3018
3019static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp,
3020 struct mlxsw_sp_nexthop_group *nh_grp)
3021{
e6f3b379
AS
3022 if (mlxsw_sp_nexthop_group_type(nh_grp) == AF_INET6 &&
3023 !nh_grp->gateway)
3024 return 0;
3025
9011b677 3026 return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_group_ht,
e9ad5e7d
IS
3027 &nh_grp->ht_node,
3028 mlxsw_sp_nexthop_group_ht_params);
3029}
3030
3031static void mlxsw_sp_nexthop_group_remove(struct mlxsw_sp *mlxsw_sp,
3032 struct mlxsw_sp_nexthop_group *nh_grp)
3033{
e6f3b379
AS
3034 if (mlxsw_sp_nexthop_group_type(nh_grp) == AF_INET6 &&
3035 !nh_grp->gateway)
3036 return;
3037
9011b677 3038 rhashtable_remove_fast(&mlxsw_sp->router->nexthop_group_ht,
e9ad5e7d
IS
3039 &nh_grp->ht_node,
3040 mlxsw_sp_nexthop_group_ht_params);
3041}
3042
3043static struct mlxsw_sp_nexthop_group *
ba31d366
AS
3044mlxsw_sp_nexthop4_group_lookup(struct mlxsw_sp *mlxsw_sp,
3045 struct fib_info *fi)
e9ad5e7d 3046{
ba31d366
AS
3047 struct mlxsw_sp_nexthop_group_cmp_arg cmp_arg;
3048
e6f3b379 3049 cmp_arg.proto = MLXSW_SP_L3_PROTO_IPV4;
ba31d366
AS
3050 cmp_arg.fi = fi;
3051 return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht,
3052 &cmp_arg,
e9ad5e7d
IS
3053 mlxsw_sp_nexthop_group_ht_params);
3054}
3055
e6f3b379
AS
3056static struct mlxsw_sp_nexthop_group *
3057mlxsw_sp_nexthop6_group_lookup(struct mlxsw_sp *mlxsw_sp,
3058 struct mlxsw_sp_fib6_entry *fib6_entry)
3059{
3060 struct mlxsw_sp_nexthop_group_cmp_arg cmp_arg;
3061
3062 cmp_arg.proto = MLXSW_SP_L3_PROTO_IPV6;
3063 cmp_arg.fib6_entry = fib6_entry;
3064 return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht,
3065 &cmp_arg,
3066 mlxsw_sp_nexthop_group_ht_params);
3067}
3068
c53b8e1b
IS
3069static const struct rhashtable_params mlxsw_sp_nexthop_ht_params = {
3070 .key_offset = offsetof(struct mlxsw_sp_nexthop, key),
3071 .head_offset = offsetof(struct mlxsw_sp_nexthop, ht_node),
3072 .key_len = sizeof(struct mlxsw_sp_nexthop_key),
3073};
3074
3075static int mlxsw_sp_nexthop_insert(struct mlxsw_sp *mlxsw_sp,
3076 struct mlxsw_sp_nexthop *nh)
3077{
9011b677 3078 return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_ht,
c53b8e1b
IS
3079 &nh->ht_node, mlxsw_sp_nexthop_ht_params);
3080}
3081
3082static void mlxsw_sp_nexthop_remove(struct mlxsw_sp *mlxsw_sp,
3083 struct mlxsw_sp_nexthop *nh)
3084{
9011b677 3085 rhashtable_remove_fast(&mlxsw_sp->router->nexthop_ht, &nh->ht_node,
c53b8e1b
IS
3086 mlxsw_sp_nexthop_ht_params);
3087}
3088
ad178c8e
IS
3089static struct mlxsw_sp_nexthop *
3090mlxsw_sp_nexthop_lookup(struct mlxsw_sp *mlxsw_sp,
3091 struct mlxsw_sp_nexthop_key key)
3092{
9011b677 3093 return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_ht, &key,
ad178c8e
IS
3094 mlxsw_sp_nexthop_ht_params);
3095}
3096
a7ff87ac 3097static int mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp *mlxsw_sp,
76610ebb 3098 const struct mlxsw_sp_fib *fib,
a7ff87ac
JP
3099 u32 adj_index, u16 ecmp_size,
3100 u32 new_adj_index,
3101 u16 new_ecmp_size)
3102{
3103 char raleu_pl[MLXSW_REG_RALEU_LEN];
3104
1a9234e6 3105 mlxsw_reg_raleu_pack(raleu_pl,
76610ebb
IS
3106 (enum mlxsw_reg_ralxx_protocol) fib->proto,
3107 fib->vr->id, adj_index, ecmp_size, new_adj_index,
1a9234e6 3108 new_ecmp_size);
a7ff87ac
JP
3109 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raleu), raleu_pl);
3110}
3111
3112static int mlxsw_sp_adj_index_mass_update(struct mlxsw_sp *mlxsw_sp,
3113 struct mlxsw_sp_nexthop_group *nh_grp,
3114 u32 old_adj_index, u16 old_ecmp_size)
3115{
3116 struct mlxsw_sp_fib_entry *fib_entry;
76610ebb 3117 struct mlxsw_sp_fib *fib = NULL;
a7ff87ac
JP
3118 int err;
3119
3120 list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) {
76610ebb 3121 if (fib == fib_entry->fib_node->fib)
a7ff87ac 3122 continue;
76610ebb
IS
3123 fib = fib_entry->fib_node->fib;
3124 err = mlxsw_sp_adj_index_mass_update_vr(mlxsw_sp, fib,
a7ff87ac
JP
3125 old_adj_index,
3126 old_ecmp_size,
3127 nh_grp->adj_index,
3128 nh_grp->ecmp_size);
3129 if (err)
3130 return err;
3131 }
3132 return 0;
3133}
3134
eb789980
IS
3135static int __mlxsw_sp_nexthop_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
3136 struct mlxsw_sp_nexthop *nh)
a7ff87ac
JP
3137{
3138 struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry;
3139 char ratr_pl[MLXSW_REG_RATR_LEN];
3140
3141 mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY,
89e41982
PM
3142 true, MLXSW_REG_RATR_TYPE_ETHERNET,
3143 adj_index, neigh_entry->rif);
a7ff87ac 3144 mlxsw_reg_ratr_eth_entry_pack(ratr_pl, neigh_entry->ha);
a5390278
AS
3145 if (nh->counter_valid)
3146 mlxsw_reg_ratr_counter_pack(ratr_pl, nh->counter_index, true);
3147 else
3148 mlxsw_reg_ratr_counter_pack(ratr_pl, 0, false);
3149
a7ff87ac
JP
3150 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
3151}
3152
eb789980
IS
3153int mlxsw_sp_nexthop_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
3154 struct mlxsw_sp_nexthop *nh)
3155{
3156 int i;
3157
3158 for (i = 0; i < nh->num_adj_entries; i++) {
3159 int err;
3160
3161 err = __mlxsw_sp_nexthop_update(mlxsw_sp, adj_index + i, nh);
3162 if (err)
3163 return err;
3164 }
3165
3166 return 0;
3167}
3168
3169static int __mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp *mlxsw_sp,
3170 u32 adj_index,
3171 struct mlxsw_sp_nexthop *nh)
1012b9ac
PM
3172{
3173 const struct mlxsw_sp_ipip_ops *ipip_ops;
3174
3175 ipip_ops = mlxsw_sp->router->ipip_ops_arr[nh->ipip_entry->ipipt];
3176 return ipip_ops->nexthop_update(mlxsw_sp, adj_index, nh->ipip_entry);
3177}
3178
eb789980
IS
3179static int mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp *mlxsw_sp,
3180 u32 adj_index,
3181 struct mlxsw_sp_nexthop *nh)
3182{
3183 int i;
3184
3185 for (i = 0; i < nh->num_adj_entries; i++) {
3186 int err;
3187
3188 err = __mlxsw_sp_nexthop_ipip_update(mlxsw_sp, adj_index + i,
3189 nh);
3190 if (err)
3191 return err;
3192 }
3193
3194 return 0;
3195}
3196
a7ff87ac 3197static int
35225e47
PM
3198mlxsw_sp_nexthop_group_update(struct mlxsw_sp *mlxsw_sp,
3199 struct mlxsw_sp_nexthop_group *nh_grp,
3200 bool reallocate)
a7ff87ac
JP
3201{
3202 u32 adj_index = nh_grp->adj_index; /* base */
3203 struct mlxsw_sp_nexthop *nh;
3204 int i;
3205 int err;
3206
3207 for (i = 0; i < nh_grp->count; i++) {
3208 nh = &nh_grp->nexthops[i];
3209
3210 if (!nh->should_offload) {
3211 nh->offloaded = 0;
3212 continue;
3213 }
3214
a59b7e02 3215 if (nh->update || reallocate) {
35225e47
PM
3216 switch (nh->type) {
3217 case MLXSW_SP_NEXTHOP_TYPE_ETH:
a5390278 3218 err = mlxsw_sp_nexthop_update
35225e47
PM
3219 (mlxsw_sp, adj_index, nh);
3220 break;
1012b9ac
PM
3221 case MLXSW_SP_NEXTHOP_TYPE_IPIP:
3222 err = mlxsw_sp_nexthop_ipip_update
3223 (mlxsw_sp, adj_index, nh);
3224 break;
35225e47 3225 }
a7ff87ac
JP
3226 if (err)
3227 return err;
3228 nh->update = 0;
3229 nh->offloaded = 1;
3230 }
eb789980 3231 adj_index += nh->num_adj_entries;
a7ff87ac
JP
3232 }
3233 return 0;
3234}
3235
a7ff87ac
JP
3236static int
3237mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp *mlxsw_sp,
3238 struct mlxsw_sp_nexthop_group *nh_grp)
3239{
3240 struct mlxsw_sp_fib_entry *fib_entry;
3241 int err;
3242
3243 list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) {
3244 err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
3245 if (err)
3246 return err;
3247 }
3248 return 0;
3249}
3250
425a08c6
IS
3251static void mlxsw_sp_adj_grp_size_round_up(u16 *p_adj_grp_size)
3252{
3253 /* Valid sizes for an adjacency group are:
3254 * 1-64, 512, 1024, 2048 and 4096.
3255 */
3256 if (*p_adj_grp_size <= 64)
3257 return;
3258 else if (*p_adj_grp_size <= 512)
3259 *p_adj_grp_size = 512;
3260 else if (*p_adj_grp_size <= 1024)
3261 *p_adj_grp_size = 1024;
3262 else if (*p_adj_grp_size <= 2048)
3263 *p_adj_grp_size = 2048;
3264 else
3265 *p_adj_grp_size = 4096;
3266}
3267
3268static void mlxsw_sp_adj_grp_size_round_down(u16 *p_adj_grp_size,
3269 unsigned int alloc_size)
3270{
3271 if (alloc_size >= 4096)
3272 *p_adj_grp_size = 4096;
3273 else if (alloc_size >= 2048)
3274 *p_adj_grp_size = 2048;
3275 else if (alloc_size >= 1024)
3276 *p_adj_grp_size = 1024;
3277 else if (alloc_size >= 512)
3278 *p_adj_grp_size = 512;
3279}
3280
3281static int mlxsw_sp_fix_adj_grp_size(struct mlxsw_sp *mlxsw_sp,
3282 u16 *p_adj_grp_size)
3283{
3284 unsigned int alloc_size;
3285 int err;
3286
3287 /* Round up the requested group size to the next size supported
3288 * by the device and make sure the request can be satisfied.
3289 */
3290 mlxsw_sp_adj_grp_size_round_up(p_adj_grp_size);
4b6b1869
JP
3291 err = mlxsw_sp_kvdl_alloc_count_query(mlxsw_sp,
3292 MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
3293 *p_adj_grp_size, &alloc_size);
425a08c6
IS
3294 if (err)
3295 return err;
3296 /* It is possible the allocation results in more allocated
3297 * entries than requested. Try to use as much of them as
3298 * possible.
3299 */
3300 mlxsw_sp_adj_grp_size_round_down(p_adj_grp_size, alloc_size);
3301
3302 return 0;
3303}
3304
eb789980
IS
3305static void
3306mlxsw_sp_nexthop_group_normalize(struct mlxsw_sp_nexthop_group *nh_grp)
3307{
3308 int i, g = 0, sum_norm_weight = 0;
3309 struct mlxsw_sp_nexthop *nh;
3310
3311 for (i = 0; i < nh_grp->count; i++) {
3312 nh = &nh_grp->nexthops[i];
3313
3314 if (!nh->should_offload)
3315 continue;
3316 if (g > 0)
3317 g = gcd(nh->nh_weight, g);
3318 else
3319 g = nh->nh_weight;
3320 }
3321
3322 for (i = 0; i < nh_grp->count; i++) {
3323 nh = &nh_grp->nexthops[i];
3324
3325 if (!nh->should_offload)
3326 continue;
3327 nh->norm_nh_weight = nh->nh_weight / g;
3328 sum_norm_weight += nh->norm_nh_weight;
3329 }
3330
3331 nh_grp->sum_norm_weight = sum_norm_weight;
3332}
3333
3334static void
3335mlxsw_sp_nexthop_group_rebalance(struct mlxsw_sp_nexthop_group *nh_grp)
3336{
3337 int total = nh_grp->sum_norm_weight;
3338 u16 ecmp_size = nh_grp->ecmp_size;
3339 int i, weight = 0, lower_bound = 0;
3340
3341 for (i = 0; i < nh_grp->count; i++) {
3342 struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
3343 int upper_bound;
3344
3345 if (!nh->should_offload)
3346 continue;
3347 weight += nh->norm_nh_weight;
3348 upper_bound = DIV_ROUND_CLOSEST(ecmp_size * weight, total);
3349 nh->num_adj_entries = upper_bound - lower_bound;
3350 lower_bound = upper_bound;
3351 }
3352}
3353
8c5a5b9b
IS
3354static struct mlxsw_sp_nexthop *
3355mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp,
3356 const struct mlxsw_sp_rt6 *mlxsw_sp_rt6);
3357
3358static void
3359mlxsw_sp_nexthop4_group_offload_refresh(struct mlxsw_sp *mlxsw_sp,
3360 struct mlxsw_sp_nexthop_group *nh_grp)
3361{
3362 int i;
3363
3364 for (i = 0; i < nh_grp->count; i++) {
3365 struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
3366
3367 if (nh->offloaded)
3368 nh->key.fib_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
3369 else
3370 nh->key.fib_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
3371 }
3372}
3373
3374static void
3375__mlxsw_sp_nexthop6_group_offload_refresh(struct mlxsw_sp_nexthop_group *nh_grp,
3376 struct mlxsw_sp_fib6_entry *fib6_entry)
3377{
3378 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
3379
3380 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
3381 struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
3382 struct mlxsw_sp_nexthop *nh;
3383
3384 nh = mlxsw_sp_rt6_nexthop(nh_grp, mlxsw_sp_rt6);
3385 if (nh && nh->offloaded)
3386 fib6_nh->fib_nh_flags |= RTNH_F_OFFLOAD;
3387 else
3388 fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
3389 }
3390}
3391
3392static void
3393mlxsw_sp_nexthop6_group_offload_refresh(struct mlxsw_sp *mlxsw_sp,
3394 struct mlxsw_sp_nexthop_group *nh_grp)
3395{
3396 struct mlxsw_sp_fib6_entry *fib6_entry;
3397
3398 /* Unfortunately, in IPv6 the route and the nexthop are described by
3399 * the same struct, so we need to iterate over all the routes using the
3400 * nexthop group and set / clear the offload indication for them.
3401 */
3402 list_for_each_entry(fib6_entry, &nh_grp->fib_list,
3403 common.nexthop_group_node)
3404 __mlxsw_sp_nexthop6_group_offload_refresh(nh_grp, fib6_entry);
3405}
3406
3407static void
3408mlxsw_sp_nexthop_group_offload_refresh(struct mlxsw_sp *mlxsw_sp,
3409 struct mlxsw_sp_nexthop_group *nh_grp)
3410{
3411 switch (mlxsw_sp_nexthop_group_type(nh_grp)) {
3412 case AF_INET:
3413 mlxsw_sp_nexthop4_group_offload_refresh(mlxsw_sp, nh_grp);
3414 break;
3415 case AF_INET6:
3416 mlxsw_sp_nexthop6_group_offload_refresh(mlxsw_sp, nh_grp);
3417 break;
3418 }
3419}
3420
a7ff87ac
JP
3421static void
3422mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
3423 struct mlxsw_sp_nexthop_group *nh_grp)
3424{
eb789980 3425 u16 ecmp_size, old_ecmp_size;
a7ff87ac
JP
3426 struct mlxsw_sp_nexthop *nh;
3427 bool offload_change = false;
3428 u32 adj_index;
a7ff87ac
JP
3429 bool old_adj_index_valid;
3430 u32 old_adj_index;
a7ff87ac
JP
3431 int i;
3432 int err;
3433
b3e8d1eb
IS
3434 if (!nh_grp->gateway) {
3435 mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
3436 return;
3437 }
3438
a7ff87ac
JP
3439 for (i = 0; i < nh_grp->count; i++) {
3440 nh = &nh_grp->nexthops[i];
3441
56b8a9ed 3442 if (nh->should_offload != nh->offloaded) {
a7ff87ac
JP
3443 offload_change = true;
3444 if (nh->should_offload)
3445 nh->update = 1;
3446 }
a7ff87ac
JP
3447 }
3448 if (!offload_change) {
3449 /* Nothing was added or removed, so no need to reallocate. Just
3450 * update MAC on existing adjacency indexes.
3451 */
35225e47 3452 err = mlxsw_sp_nexthop_group_update(mlxsw_sp, nh_grp, false);
a7ff87ac
JP
3453 if (err) {
3454 dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
3455 goto set_trap;
3456 }
3457 return;
3458 }
eb789980
IS
3459 mlxsw_sp_nexthop_group_normalize(nh_grp);
3460 if (!nh_grp->sum_norm_weight)
a7ff87ac
JP
3461 /* No neigh of this group is connected so we just set
3462 * the trap and let everthing flow through kernel.
3463 */
3464 goto set_trap;
3465
eb789980 3466 ecmp_size = nh_grp->sum_norm_weight;
425a08c6
IS
3467 err = mlxsw_sp_fix_adj_grp_size(mlxsw_sp, &ecmp_size);
3468 if (err)
3469 /* No valid allocation size available. */
3470 goto set_trap;
3471
4b6b1869
JP
3472 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
3473 ecmp_size, &adj_index);
13124443 3474 if (err) {
a7ff87ac
JP
3475 /* We ran out of KVD linear space, just set the
3476 * trap and let everything flow through kernel.
3477 */
3478 dev_warn(mlxsw_sp->bus_info->dev, "Failed to allocate KVD linear area for nexthop group.\n");
3479 goto set_trap;
3480 }
a7ff87ac
JP
3481 old_adj_index_valid = nh_grp->adj_index_valid;
3482 old_adj_index = nh_grp->adj_index;
3483 old_ecmp_size = nh_grp->ecmp_size;
3484 nh_grp->adj_index_valid = 1;
3485 nh_grp->adj_index = adj_index;
3486 nh_grp->ecmp_size = ecmp_size;
eb789980 3487 mlxsw_sp_nexthop_group_rebalance(nh_grp);
35225e47 3488 err = mlxsw_sp_nexthop_group_update(mlxsw_sp, nh_grp, true);
a7ff87ac
JP
3489 if (err) {
3490 dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
3491 goto set_trap;
3492 }
3493
8c5a5b9b
IS
3494 mlxsw_sp_nexthop_group_offload_refresh(mlxsw_sp, nh_grp);
3495
a7ff87ac
JP
3496 if (!old_adj_index_valid) {
3497 /* The trap was set for fib entries, so we have to call
3498 * fib entry update to unset it and use adjacency index.
3499 */
3500 err = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
3501 if (err) {
3502 dev_warn(mlxsw_sp->bus_info->dev, "Failed to add adjacency index to fib entries.\n");
3503 goto set_trap;
3504 }
3505 return;
3506 }
3507
3508 err = mlxsw_sp_adj_index_mass_update(mlxsw_sp, nh_grp,
3509 old_adj_index, old_ecmp_size);
4b6b1869 3510 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
0304c005 3511 old_ecmp_size, old_adj_index);
a7ff87ac
JP
3512 if (err) {
3513 dev_warn(mlxsw_sp->bus_info->dev, "Failed to mass-update adjacency index for nexthop group.\n");
3514 goto set_trap;
3515 }
77d964e6 3516
a7ff87ac
JP
3517 return;
3518
3519set_trap:
3520 old_adj_index_valid = nh_grp->adj_index_valid;
3521 nh_grp->adj_index_valid = 0;
3522 for (i = 0; i < nh_grp->count; i++) {
3523 nh = &nh_grp->nexthops[i];
3524 nh->offloaded = 0;
3525 }
3526 err = mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
3527 if (err)
3528 dev_warn(mlxsw_sp->bus_info->dev, "Failed to set traps for fib entries.\n");
8c5a5b9b 3529 mlxsw_sp_nexthop_group_offload_refresh(mlxsw_sp, nh_grp);
a7ff87ac 3530 if (old_adj_index_valid)
4b6b1869 3531 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ,
0304c005 3532 nh_grp->ecmp_size, nh_grp->adj_index);
a7ff87ac
JP
3533}
3534
3535static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop *nh,
3536 bool removing)
3537{
213666a3 3538 if (!removing)
a7ff87ac 3539 nh->should_offload = 1;
8764a826 3540 else
a7ff87ac
JP
3541 nh->should_offload = 0;
3542 nh->update = 1;
3543}
3544
83d57826
IS
3545static int
3546mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp *mlxsw_sp,
3547 struct mlxsw_sp_neigh_entry *neigh_entry)
3548{
3549 struct neighbour *n, *old_n = neigh_entry->key.n;
3550 struct mlxsw_sp_nexthop *nh;
3551 bool entry_connected;
3552 u8 nud_state, dead;
3553 int err;
3554
3555 nh = list_first_entry(&neigh_entry->nexthop_list,
3556 struct mlxsw_sp_nexthop, neigh_list_node);
3557
3558 n = neigh_lookup(nh->nh_grp->neigh_tbl, &nh->gw_addr, nh->rif->dev);
3559 if (!n) {
3560 n = neigh_create(nh->nh_grp->neigh_tbl, &nh->gw_addr,
3561 nh->rif->dev);
3562 if (IS_ERR(n))
3563 return PTR_ERR(n);
3564 neigh_event_send(n, NULL);
3565 }
3566
3567 mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
3568 neigh_entry->key.n = n;
3569 err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
3570 if (err)
3571 goto err_neigh_entry_insert;
3572
3573 read_lock_bh(&n->lock);
3574 nud_state = n->nud_state;
3575 dead = n->dead;
3576 read_unlock_bh(&n->lock);
3577 entry_connected = nud_state & NUD_VALID && !dead;
3578
3579 list_for_each_entry(nh, &neigh_entry->nexthop_list,
3580 neigh_list_node) {
3581 neigh_release(old_n);
3582 neigh_clone(n);
3583 __mlxsw_sp_nexthop_neigh_update(nh, !entry_connected);
3584 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
3585 }
3586
3587 neigh_release(n);
3588
3589 return 0;
3590
3591err_neigh_entry_insert:
3592 neigh_entry->key.n = old_n;
3593 mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
3594 neigh_release(n);
3595 return err;
3596}
3597
a7ff87ac
JP
3598static void
3599mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp,
3600 struct mlxsw_sp_neigh_entry *neigh_entry,
83d57826 3601 bool removing, bool dead)
a7ff87ac
JP
3602{
3603 struct mlxsw_sp_nexthop *nh;
3604
83d57826
IS
3605 if (list_empty(&neigh_entry->nexthop_list))
3606 return;
3607
3608 if (dead) {
3609 int err;
3610
3611 err = mlxsw_sp_nexthop_dead_neigh_replace(mlxsw_sp,
3612 neigh_entry);
3613 if (err)
3614 dev_err(mlxsw_sp->bus_info->dev, "Failed to replace dead neigh\n");
3615 return;
3616 }
3617
a7ff87ac
JP
3618 list_for_each_entry(nh, &neigh_entry->nexthop_list,
3619 neigh_list_node) {
3620 __mlxsw_sp_nexthop_neigh_update(nh, removing);
3621 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
3622 }
a7ff87ac
JP
3623}
3624
9665b745 3625static void mlxsw_sp_nexthop_rif_init(struct mlxsw_sp_nexthop *nh,
bf95233e 3626 struct mlxsw_sp_rif *rif)
9665b745 3627{
bf95233e 3628 if (nh->rif)
9665b745
IS
3629 return;
3630
bf95233e
AS
3631 nh->rif = rif;
3632 list_add(&nh->rif_list_node, &rif->nexthop_list);
9665b745
IS
3633}
3634
3635static void mlxsw_sp_nexthop_rif_fini(struct mlxsw_sp_nexthop *nh)
3636{
bf95233e 3637 if (!nh->rif)
9665b745
IS
3638 return;
3639
3640 list_del(&nh->rif_list_node);
bf95233e 3641 nh->rif = NULL;
9665b745
IS
3642}
3643
a8c97014
IS
3644static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp,
3645 struct mlxsw_sp_nexthop *nh)
a7ff87ac
JP
3646{
3647 struct mlxsw_sp_neigh_entry *neigh_entry;
a7ff87ac 3648 struct neighbour *n;
93a87e5e 3649 u8 nud_state, dead;
c53b8e1b
IS
3650 int err;
3651
ad178c8e 3652 if (!nh->nh_grp->gateway || nh->neigh_entry)
b8399a1e
IS
3653 return 0;
3654
33b1341c 3655 /* Take a reference of neigh here ensuring that neigh would
8de3c178 3656 * not be destructed before the nexthop entry is finished.
33b1341c 3657 * The reference is taken either in neigh_lookup() or
fd76d910 3658 * in neigh_create() in case n is not found.
33b1341c 3659 */
58adf2c4 3660 n = neigh_lookup(nh->nh_grp->neigh_tbl, &nh->gw_addr, nh->rif->dev);
33b1341c 3661 if (!n) {
58adf2c4
IS
3662 n = neigh_create(nh->nh_grp->neigh_tbl, &nh->gw_addr,
3663 nh->rif->dev);
a8c97014
IS
3664 if (IS_ERR(n))
3665 return PTR_ERR(n);
a7ff87ac 3666 neigh_event_send(n, NULL);
33b1341c
JP
3667 }
3668 neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
3669 if (!neigh_entry) {
5c8802f1
IS
3670 neigh_entry = mlxsw_sp_neigh_entry_create(mlxsw_sp, n);
3671 if (IS_ERR(neigh_entry)) {
c53b8e1b
IS
3672 err = -EINVAL;
3673 goto err_neigh_entry_create;
5c8802f1 3674 }
a7ff87ac 3675 }
b2157149
YG
3676
3677 /* If that is the first nexthop connected to that neigh, add to
3678 * nexthop_neighs_list
3679 */
3680 if (list_empty(&neigh_entry->nexthop_list))
3681 list_add_tail(&neigh_entry->nexthop_neighs_list_node,
9011b677 3682 &mlxsw_sp->router->nexthop_neighs_list);
b2157149 3683
a7ff87ac
JP
3684 nh->neigh_entry = neigh_entry;
3685 list_add_tail(&nh->neigh_list_node, &neigh_entry->nexthop_list);
3686 read_lock_bh(&n->lock);
3687 nud_state = n->nud_state;
93a87e5e 3688 dead = n->dead;
a7ff87ac 3689 read_unlock_bh(&n->lock);
93a87e5e 3690 __mlxsw_sp_nexthop_neigh_update(nh, !(nud_state & NUD_VALID && !dead));
a7ff87ac
JP
3691
3692 return 0;
c53b8e1b
IS
3693
3694err_neigh_entry_create:
3695 neigh_release(n);
c53b8e1b 3696 return err;
a7ff87ac
JP
3697}
3698
a8c97014
IS
3699static void mlxsw_sp_nexthop_neigh_fini(struct mlxsw_sp *mlxsw_sp,
3700 struct mlxsw_sp_nexthop *nh)
a7ff87ac
JP
3701{
3702 struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry;
a8c97014 3703 struct neighbour *n;
a7ff87ac 3704
b8399a1e 3705 if (!neigh_entry)
a8c97014
IS
3706 return;
3707 n = neigh_entry->key.n;
b8399a1e 3708
58312125 3709 __mlxsw_sp_nexthop_neigh_update(nh, true);
a7ff87ac 3710 list_del(&nh->neigh_list_node);
e58be79e 3711 nh->neigh_entry = NULL;
b2157149
YG
3712
3713 /* If that is the last nexthop connected to that neigh, remove from
3714 * nexthop_neighs_list
3715 */
e58be79e
IS
3716 if (list_empty(&neigh_entry->nexthop_list))
3717 list_del(&neigh_entry->nexthop_neighs_list_node);
b2157149 3718
5c8802f1
IS
3719 if (!neigh_entry->connected && list_empty(&neigh_entry->nexthop_list))
3720 mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
3721
3722 neigh_release(n);
a8c97014 3723}
c53b8e1b 3724
44b0fff1
PM
3725static bool mlxsw_sp_ipip_netdev_ul_up(struct net_device *ol_dev)
3726{
f24fbf4d
IS
3727 struct net_device *ul_dev;
3728 bool is_up;
3729
3730 rcu_read_lock();
3731 ul_dev = __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev);
3732 is_up = ul_dev ? (ul_dev->flags & IFF_UP) : true;
3733 rcu_read_unlock();
44b0fff1 3734
f24fbf4d 3735 return is_up;
44b0fff1
PM
3736}
3737
d97cda5f
PM
3738static void mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp *mlxsw_sp,
3739 struct mlxsw_sp_nexthop *nh,
3740 struct mlxsw_sp_ipip_entry *ipip_entry)
1012b9ac 3741{
44b0fff1
PM
3742 bool removing;
3743
1012b9ac 3744 if (!nh->nh_grp->gateway || nh->ipip_entry)
d97cda5f 3745 return;
1012b9ac 3746
d97cda5f
PM
3747 nh->ipip_entry = ipip_entry;
3748 removing = !mlxsw_sp_ipip_netdev_ul_up(ipip_entry->ol_dev);
44b0fff1 3749 __mlxsw_sp_nexthop_neigh_update(nh, removing);
d97cda5f 3750 mlxsw_sp_nexthop_rif_init(nh, &ipip_entry->ol_lb->common);
1012b9ac
PM
3751}
3752
3753static void mlxsw_sp_nexthop_ipip_fini(struct mlxsw_sp *mlxsw_sp,
3754 struct mlxsw_sp_nexthop *nh)
3755{
3756 struct mlxsw_sp_ipip_entry *ipip_entry = nh->ipip_entry;
3757
3758 if (!ipip_entry)
3759 return;
3760
3761 __mlxsw_sp_nexthop_neigh_update(nh, true);
1012b9ac
PM
3762 nh->ipip_entry = NULL;
3763}
3764
3765static bool mlxsw_sp_nexthop4_ipip_type(const struct mlxsw_sp *mlxsw_sp,
3766 const struct fib_nh *fib_nh,
3767 enum mlxsw_sp_ipip_type *p_ipipt)
3768{
b75ed8b1 3769 struct net_device *dev = fib_nh->fib_nh_dev;
1012b9ac
PM
3770
3771 return dev &&
3772 fib_nh->nh_parent->fib_type == RTN_UNICAST &&
3773 mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, p_ipipt);
3774}
3775
35225e47
PM
3776static void mlxsw_sp_nexthop_type_fini(struct mlxsw_sp *mlxsw_sp,
3777 struct mlxsw_sp_nexthop *nh)
3778{
3779 switch (nh->type) {
3780 case MLXSW_SP_NEXTHOP_TYPE_ETH:
3781 mlxsw_sp_nexthop_neigh_fini(mlxsw_sp, nh);
3782 mlxsw_sp_nexthop_rif_fini(nh);
3783 break;
1012b9ac 3784 case MLXSW_SP_NEXTHOP_TYPE_IPIP:
de0f43c0 3785 mlxsw_sp_nexthop_rif_fini(nh);
1012b9ac
PM
3786 mlxsw_sp_nexthop_ipip_fini(mlxsw_sp, nh);
3787 break;
35225e47
PM
3788 }
3789}
3790
3791static int mlxsw_sp_nexthop4_type_init(struct mlxsw_sp *mlxsw_sp,
3792 struct mlxsw_sp_nexthop *nh,
3793 struct fib_nh *fib_nh)
3794{
d97cda5f 3795 const struct mlxsw_sp_ipip_ops *ipip_ops;
b75ed8b1 3796 struct net_device *dev = fib_nh->fib_nh_dev;
d97cda5f 3797 struct mlxsw_sp_ipip_entry *ipip_entry;
35225e47
PM
3798 struct mlxsw_sp_rif *rif;
3799 int err;
3800
d97cda5f
PM
3801 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, dev);
3802 if (ipip_entry) {
3803 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
3804 if (ipip_ops->can_offload(mlxsw_sp, dev,
3805 MLXSW_SP_L3_PROTO_IPV4)) {
3806 nh->type = MLXSW_SP_NEXTHOP_TYPE_IPIP;
3807 mlxsw_sp_nexthop_ipip_init(mlxsw_sp, nh, ipip_entry);
3808 return 0;
3809 }
1012b9ac
PM
3810 }
3811
35225e47
PM
3812 nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH;
3813 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
3814 if (!rif)
3815 return 0;
3816
3817 mlxsw_sp_nexthop_rif_init(nh, rif);
3818 err = mlxsw_sp_nexthop_neigh_init(mlxsw_sp, nh);
3819 if (err)
3820 goto err_neigh_init;
3821
3822 return 0;
3823
3824err_neigh_init:
3825 mlxsw_sp_nexthop_rif_fini(nh);
3826 return err;
3827}
3828
3829static void mlxsw_sp_nexthop4_type_fini(struct mlxsw_sp *mlxsw_sp,
3830 struct mlxsw_sp_nexthop *nh)
3831{
3832 mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh);
3833}
3834
0e6ea2a4
IS
3835static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp,
3836 struct mlxsw_sp_nexthop_group *nh_grp,
3837 struct mlxsw_sp_nexthop *nh,
3838 struct fib_nh *fib_nh)
a8c97014 3839{
b75ed8b1 3840 struct net_device *dev = fib_nh->fib_nh_dev;
df6dd79b 3841 struct in_device *in_dev;
a8c97014
IS
3842 int err;
3843
3844 nh->nh_grp = nh_grp;
3845 nh->key.fib_nh = fib_nh;
408bd946 3846#ifdef CONFIG_IP_ROUTE_MULTIPATH
b75ed8b1 3847 nh->nh_weight = fib_nh->fib_nh_weight;
408bd946
IS
3848#else
3849 nh->nh_weight = 1;
3850#endif
b75ed8b1 3851 memcpy(&nh->gw_addr, &fib_nh->fib_nh_gw4, sizeof(fib_nh->fib_nh_gw4));
a8c97014
IS
3852 err = mlxsw_sp_nexthop_insert(mlxsw_sp, nh);
3853 if (err)
3854 return err;
3855
a5390278 3856 mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
dbe4598c
AS
3857 list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
3858
97989ee0
IS
3859 if (!dev)
3860 return 0;
3861
c43ef228
IS
3862 rcu_read_lock();
3863 in_dev = __in_dev_get_rcu(dev);
df6dd79b 3864 if (in_dev && IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
c43ef228
IS
3865 fib_nh->fib_nh_flags & RTNH_F_LINKDOWN) {
3866 rcu_read_unlock();
df6dd79b 3867 return 0;
c43ef228
IS
3868 }
3869 rcu_read_unlock();
df6dd79b 3870
35225e47 3871 err = mlxsw_sp_nexthop4_type_init(mlxsw_sp, nh, fib_nh);
a8c97014
IS
3872 if (err)
3873 goto err_nexthop_neigh_init;
3874
3875 return 0;
3876
3877err_nexthop_neigh_init:
3878 mlxsw_sp_nexthop_remove(mlxsw_sp, nh);
3879 return err;
3880}
3881
0e6ea2a4
IS
3882static void mlxsw_sp_nexthop4_fini(struct mlxsw_sp *mlxsw_sp,
3883 struct mlxsw_sp_nexthop *nh)
a8c97014 3884{
35225e47 3885 mlxsw_sp_nexthop4_type_fini(mlxsw_sp, nh);
dbe4598c 3886 list_del(&nh->router_list_node);
a5390278 3887 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
c53b8e1b 3888 mlxsw_sp_nexthop_remove(mlxsw_sp, nh);
a7ff87ac
JP
3889}
3890
0e6ea2a4
IS
3891static void mlxsw_sp_nexthop4_event(struct mlxsw_sp *mlxsw_sp,
3892 unsigned long event, struct fib_nh *fib_nh)
ad178c8e
IS
3893{
3894 struct mlxsw_sp_nexthop_key key;
3895 struct mlxsw_sp_nexthop *nh;
ad178c8e 3896
9011b677 3897 if (mlxsw_sp->router->aborted)
ad178c8e
IS
3898 return;
3899
3900 key.fib_nh = fib_nh;
3901 nh = mlxsw_sp_nexthop_lookup(mlxsw_sp, key);
b6a1d871 3902 if (!nh)
ad178c8e
IS
3903 return;
3904
ad178c8e
IS
3905 switch (event) {
3906 case FIB_EVENT_NH_ADD:
35225e47 3907 mlxsw_sp_nexthop4_type_init(mlxsw_sp, nh, fib_nh);
ad178c8e
IS
3908 break;
3909 case FIB_EVENT_NH_DEL:
35225e47 3910 mlxsw_sp_nexthop4_type_fini(mlxsw_sp, nh);
ad178c8e
IS
3911 break;
3912 }
3913
3914 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
3915}
3916
0c5f1cd5
PM
3917static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp,
3918 struct mlxsw_sp_rif *rif)
3919{
3920 struct mlxsw_sp_nexthop *nh;
44b0fff1 3921 bool removing;
0c5f1cd5
PM
3922
3923 list_for_each_entry(nh, &rif->nexthop_list, rif_list_node) {
44b0fff1
PM
3924 switch (nh->type) {
3925 case MLXSW_SP_NEXTHOP_TYPE_ETH:
3926 removing = false;
3927 break;
3928 case MLXSW_SP_NEXTHOP_TYPE_IPIP:
3929 removing = !mlxsw_sp_ipip_netdev_ul_up(rif->dev);
3930 break;
3931 default:
3932 WARN_ON(1);
3933 continue;
3934 }
3935
3936 __mlxsw_sp_nexthop_neigh_update(nh, removing);
0c5f1cd5
PM
3937 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
3938 }
3939}
3940
09dbf629
PM
3941static void mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp *mlxsw_sp,
3942 struct mlxsw_sp_rif *old_rif,
3943 struct mlxsw_sp_rif *new_rif)
3944{
3945 struct mlxsw_sp_nexthop *nh;
3946
3947 list_splice_init(&old_rif->nexthop_list, &new_rif->nexthop_list);
3948 list_for_each_entry(nh, &new_rif->nexthop_list, rif_list_node)
3949 nh->rif = new_rif;
3950 mlxsw_sp_nexthop_rif_update(mlxsw_sp, new_rif);
3951}
3952
9665b745 3953static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
bf95233e 3954 struct mlxsw_sp_rif *rif)
9665b745
IS
3955{
3956 struct mlxsw_sp_nexthop *nh, *tmp;
3957
bf95233e 3958 list_for_each_entry_safe(nh, tmp, &rif->nexthop_list, rif_list_node) {
35225e47 3959 mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh);
9665b745
IS
3960 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
3961 }
3962}
3963
9b01451a 3964static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp *mlxsw_sp,
5481d73f 3965 struct fib_info *fi)
9b01451a 3966{
5481d73f
DA
3967 const struct fib_nh *nh = fib_info_nh(fi, 0);
3968
3969 return nh->fib_nh_scope == RT_SCOPE_LINK ||
3970 mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, nh, NULL);
9b01451a
PM
3971}
3972
a7ff87ac 3973static struct mlxsw_sp_nexthop_group *
0e6ea2a4 3974mlxsw_sp_nexthop4_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi)
a7ff87ac 3975{
5481d73f 3976 unsigned int nhs = fib_info_num_path(fi);
a7ff87ac
JP
3977 struct mlxsw_sp_nexthop_group *nh_grp;
3978 struct mlxsw_sp_nexthop *nh;
3979 struct fib_nh *fib_nh;
a7ff87ac
JP
3980 int i;
3981 int err;
3982
5481d73f 3983 nh_grp = kzalloc(struct_size(nh_grp, nexthops, nhs), GFP_KERNEL);
a7ff87ac
JP
3984 if (!nh_grp)
3985 return ERR_PTR(-ENOMEM);
ba31d366 3986 nh_grp->priv = fi;
a7ff87ac 3987 INIT_LIST_HEAD(&nh_grp->fib_list);
58adf2c4
IS
3988 nh_grp->neigh_tbl = &arp_tbl;
3989
9b01451a 3990 nh_grp->gateway = mlxsw_sp_fi_is_gateway(mlxsw_sp, fi);
5481d73f 3991 nh_grp->count = nhs;
7387dbbc 3992 fib_info_hold(fi);
a7ff87ac
JP
3993 for (i = 0; i < nh_grp->count; i++) {
3994 nh = &nh_grp->nexthops[i];
5481d73f 3995 fib_nh = fib_info_nh(fi, i);
0e6ea2a4 3996 err = mlxsw_sp_nexthop4_init(mlxsw_sp, nh_grp, nh, fib_nh);
a7ff87ac 3997 if (err)
0e6ea2a4 3998 goto err_nexthop4_init;
a7ff87ac 3999 }
e9ad5e7d
IS
4000 err = mlxsw_sp_nexthop_group_insert(mlxsw_sp, nh_grp);
4001 if (err)
4002 goto err_nexthop_group_insert;
a7ff87ac
JP
4003 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
4004 return nh_grp;
4005
e9ad5e7d 4006err_nexthop_group_insert:
0e6ea2a4 4007err_nexthop4_init:
df6dd79b
IS
4008 for (i--; i >= 0; i--) {
4009 nh = &nh_grp->nexthops[i];
0e6ea2a4 4010 mlxsw_sp_nexthop4_fini(mlxsw_sp, nh);
df6dd79b 4011 }
ba31d366 4012 fib_info_put(fi);
a7ff87ac
JP
4013 kfree(nh_grp);
4014 return ERR_PTR(err);
4015}
4016
4017static void
0e6ea2a4
IS
4018mlxsw_sp_nexthop4_group_destroy(struct mlxsw_sp *mlxsw_sp,
4019 struct mlxsw_sp_nexthop_group *nh_grp)
a7ff87ac
JP
4020{
4021 struct mlxsw_sp_nexthop *nh;
4022 int i;
4023
e9ad5e7d 4024 mlxsw_sp_nexthop_group_remove(mlxsw_sp, nh_grp);
a7ff87ac
JP
4025 for (i = 0; i < nh_grp->count; i++) {
4026 nh = &nh_grp->nexthops[i];
0e6ea2a4 4027 mlxsw_sp_nexthop4_fini(mlxsw_sp, nh);
a7ff87ac 4028 }
58312125
IS
4029 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
4030 WARN_ON_ONCE(nh_grp->adj_index_valid);
ba31d366 4031 fib_info_put(mlxsw_sp_nexthop4_group_fi(nh_grp));
a7ff87ac
JP
4032 kfree(nh_grp);
4033}
4034
0e6ea2a4
IS
4035static int mlxsw_sp_nexthop4_group_get(struct mlxsw_sp *mlxsw_sp,
4036 struct mlxsw_sp_fib_entry *fib_entry,
4037 struct fib_info *fi)
a7ff87ac
JP
4038{
4039 struct mlxsw_sp_nexthop_group *nh_grp;
4040
ba31d366 4041 nh_grp = mlxsw_sp_nexthop4_group_lookup(mlxsw_sp, fi);
a7ff87ac 4042 if (!nh_grp) {
0e6ea2a4 4043 nh_grp = mlxsw_sp_nexthop4_group_create(mlxsw_sp, fi);
a7ff87ac
JP
4044 if (IS_ERR(nh_grp))
4045 return PTR_ERR(nh_grp);
4046 }
4047 list_add_tail(&fib_entry->nexthop_group_node, &nh_grp->fib_list);
4048 fib_entry->nh_group = nh_grp;
4049 return 0;
4050}
4051
0e6ea2a4
IS
4052static void mlxsw_sp_nexthop4_group_put(struct mlxsw_sp *mlxsw_sp,
4053 struct mlxsw_sp_fib_entry *fib_entry)
a7ff87ac
JP
4054{
4055 struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
4056
4057 list_del(&fib_entry->nexthop_group_node);
4058 if (!list_empty(&nh_grp->fib_list))
4059 return;
0e6ea2a4 4060 mlxsw_sp_nexthop4_group_destroy(mlxsw_sp, nh_grp);
a7ff87ac
JP
4061}
4062
4f1c7f1f
IS
4063static bool
4064mlxsw_sp_fib4_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry)
4065{
4066 struct mlxsw_sp_fib4_entry *fib4_entry;
4067
4068 fib4_entry = container_of(fib_entry, struct mlxsw_sp_fib4_entry,
4069 common);
4070 return !fib4_entry->tos;
4071}
4072
013b20f9
IS
4073static bool
4074mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry)
4075{
4076 struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group;
4077
4f1c7f1f
IS
4078 switch (fib_entry->fib_node->fib->proto) {
4079 case MLXSW_SP_L3_PROTO_IPV4:
4080 if (!mlxsw_sp_fib4_entry_should_offload(fib_entry))
4081 return false;
4082 break;
4083 case MLXSW_SP_L3_PROTO_IPV6:
4084 break;
4085 }
9aecce1c 4086
013b20f9
IS
4087 switch (fib_entry->type) {
4088 case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE:
4089 return !!nh_group->adj_index_valid;
4090 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
70ad3506 4091 return !!nh_group->nh_rif;
2810c3b2 4092 case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE:
4607f6d2 4093 case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
0c69e0fc 4094 case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP:
4607f6d2 4095 return true;
013b20f9
IS
4096 default:
4097 return false;
4098 }
4099}
4100
428b851f
IS
4101static struct mlxsw_sp_nexthop *
4102mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp,
4103 const struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
4104{
4105 int i;
4106
4107 for (i = 0; i < nh_grp->count; i++) {
4108 struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
8d1c802b 4109 struct fib6_info *rt = mlxsw_sp_rt6->rt;
428b851f 4110
1cf844c7 4111 if (nh->rif && nh->rif->dev == rt->fib6_nh->fib_nh_dev &&
428b851f 4112 ipv6_addr_equal((const struct in6_addr *) &nh->gw_addr,
1cf844c7 4113 &rt->fib6_nh->fib_nh_gw6))
428b851f
IS
4114 return nh;
4115 continue;
4116 }
4117
4118 return NULL;
4119}
4120
3984d1a8 4121static void
ee5a0448
IS
4122mlxsw_sp_fib4_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
4123 struct mlxsw_sp_fib_entry *fib_entry)
3984d1a8 4124{
ee5a0448
IS
4125 struct fib_info *fi = mlxsw_sp_nexthop4_group_fi(fib_entry->nh_group);
4126 u32 *p_dst = (u32 *) fib_entry->fib_node->key.addr;
4127 int dst_len = fib_entry->fib_node->key.prefix_len;
4128 struct mlxsw_sp_fib4_entry *fib4_entry;
4129 struct fib_rt_info fri;
4130 bool should_offload;
3984d1a8 4131
ee5a0448
IS
4132 should_offload = mlxsw_sp_fib_entry_should_offload(fib_entry);
4133 fib4_entry = container_of(fib_entry, struct mlxsw_sp_fib4_entry,
4134 common);
4135 fri.fi = fi;
4136 fri.tb_id = fib4_entry->tb_id;
4137 fri.dst = cpu_to_be32(*p_dst);
4138 fri.dst_len = dst_len;
4139 fri.tos = fib4_entry->tos;
4140 fri.type = fib4_entry->type;
4141 fri.offload = should_offload;
4142 fri.trap = !should_offload;
4143 fib_alias_hw_flags_set(mlxsw_sp_net(mlxsw_sp), &fri);
3984d1a8
IS
4144}
4145
4146static void
ee5a0448
IS
4147mlxsw_sp_fib4_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
4148 struct mlxsw_sp_fib_entry *fib_entry)
3984d1a8 4149{
ee5a0448
IS
4150 struct fib_info *fi = mlxsw_sp_nexthop4_group_fi(fib_entry->nh_group);
4151 u32 *p_dst = (u32 *) fib_entry->fib_node->key.addr;
4152 int dst_len = fib_entry->fib_node->key.prefix_len;
4153 struct mlxsw_sp_fib4_entry *fib4_entry;
4154 struct fib_rt_info fri;
3984d1a8 4155
ee5a0448
IS
4156 fib4_entry = container_of(fib_entry, struct mlxsw_sp_fib4_entry,
4157 common);
4158 fri.fi = fi;
4159 fri.tb_id = fib4_entry->tb_id;
4160 fri.dst = cpu_to_be32(*p_dst);
4161 fri.dst_len = dst_len;
4162 fri.tos = fib4_entry->tos;
4163 fri.type = fib4_entry->type;
4164 fri.offload = false;
4165 fri.trap = false;
4166 fib_alias_hw_flags_set(mlxsw_sp_net(mlxsw_sp), &fri);
3984d1a8
IS
4167}
4168
428b851f 4169static void
ee5a0448
IS
4170mlxsw_sp_fib6_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
4171 struct mlxsw_sp_fib_entry *fib_entry)
428b851f
IS
4172{
4173 struct mlxsw_sp_fib6_entry *fib6_entry;
4174 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
ee5a0448
IS
4175 bool should_offload;
4176
4177 should_offload = mlxsw_sp_fib_entry_should_offload(fib_entry);
428b851f 4178
ee5a0448
IS
4179 /* In IPv6 a multipath route is represented using multiple routes, so
4180 * we need to set the flags on all of them.
4181 */
428b851f
IS
4182 fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry,
4183 common);
ee5a0448
IS
4184 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list)
4185 fib6_info_hw_flags_set(mlxsw_sp_rt6->rt, should_offload,
4186 !should_offload);
428b851f
IS
4187}
4188
4189static void
ee5a0448
IS
4190mlxsw_sp_fib6_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
4191 struct mlxsw_sp_fib_entry *fib_entry)
428b851f
IS
4192{
4193 struct mlxsw_sp_fib6_entry *fib6_entry;
4194 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
4195
4196 fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry,
4197 common);
ee5a0448
IS
4198 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list)
4199 fib6_info_hw_flags_set(mlxsw_sp_rt6->rt, false, false);
428b851f
IS
4200}
4201
ee5a0448
IS
4202static void
4203mlxsw_sp_fib_entry_hw_flags_set(struct mlxsw_sp *mlxsw_sp,
4204 struct mlxsw_sp_fib_entry *fib_entry)
013b20f9 4205{
76610ebb 4206 switch (fib_entry->fib_node->fib->proto) {
013b20f9 4207 case MLXSW_SP_L3_PROTO_IPV4:
ee5a0448 4208 mlxsw_sp_fib4_entry_hw_flags_set(mlxsw_sp, fib_entry);
013b20f9
IS
4209 break;
4210 case MLXSW_SP_L3_PROTO_IPV6:
ee5a0448 4211 mlxsw_sp_fib6_entry_hw_flags_set(mlxsw_sp, fib_entry);
428b851f 4212 break;
013b20f9
IS
4213 }
4214}
4215
4216static void
ee5a0448
IS
4217mlxsw_sp_fib_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
4218 struct mlxsw_sp_fib_entry *fib_entry)
013b20f9 4219{
76610ebb 4220 switch (fib_entry->fib_node->fib->proto) {
013b20f9 4221 case MLXSW_SP_L3_PROTO_IPV4:
ee5a0448 4222 mlxsw_sp_fib4_entry_hw_flags_clear(mlxsw_sp, fib_entry);
013b20f9
IS
4223 break;
4224 case MLXSW_SP_L3_PROTO_IPV6:
ee5a0448 4225 mlxsw_sp_fib6_entry_hw_flags_clear(mlxsw_sp, fib_entry);
428b851f 4226 break;
013b20f9 4227 }
013b20f9
IS
4228}
4229
4230static void
ee5a0448
IS
4231mlxsw_sp_fib_entry_hw_flags_refresh(struct mlxsw_sp *mlxsw_sp,
4232 struct mlxsw_sp_fib_entry *fib_entry,
4233 enum mlxsw_reg_ralue_op op)
013b20f9
IS
4234{
4235 switch (op) {
013b20f9 4236 case MLXSW_REG_RALUE_OP_WRITE_WRITE:
ee5a0448
IS
4237 mlxsw_sp_fib_entry_hw_flags_set(mlxsw_sp, fib_entry);
4238 break;
4239 case MLXSW_REG_RALUE_OP_WRITE_DELETE:
4240 mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, fib_entry);
4241 break;
013b20f9 4242 default:
ee5a0448 4243 break;
013b20f9
IS
4244 }
4245}
4246
9dbf4d76
IS
4247static void
4248mlxsw_sp_fib_entry_ralue_pack(char *ralue_pl,
4249 const struct mlxsw_sp_fib_entry *fib_entry,
4250 enum mlxsw_reg_ralue_op op)
a7ff87ac 4251{
76610ebb 4252 struct mlxsw_sp_fib *fib = fib_entry->fib_node->fib;
9dbf4d76
IS
4253 enum mlxsw_reg_ralxx_protocol proto;
4254 u32 *p_dip;
4255
4256 proto = (enum mlxsw_reg_ralxx_protocol) fib->proto;
4257
4258 switch (fib->proto) {
4259 case MLXSW_SP_L3_PROTO_IPV4:
4260 p_dip = (u32 *) fib_entry->fib_node->key.addr;
4261 mlxsw_reg_ralue_pack4(ralue_pl, proto, op, fib->vr->id,
4262 fib_entry->fib_node->key.prefix_len,
4263 *p_dip);
4264 break;
4265 case MLXSW_SP_L3_PROTO_IPV6:
4266 mlxsw_reg_ralue_pack6(ralue_pl, proto, op, fib->vr->id,
4267 fib_entry->fib_node->key.prefix_len,
4268 fib_entry->fib_node->key.addr);
4269 break;
4270 }
4271}
4272
0c3cbbf9
AC
4273static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index)
4274{
0c3cbbf9
AC
4275 enum mlxsw_reg_ratr_trap_action trap_action;
4276 char ratr_pl[MLXSW_REG_RATR_LEN];
983db619
IS
4277 int err;
4278
4279 if (mlxsw_sp->router->adj_discard_index_valid)
4280 return 0;
4281
4282 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
4283 &mlxsw_sp->router->adj_discard_index);
4284 if (err)
4285 return err;
0c3cbbf9
AC
4286
4287 trap_action = MLXSW_REG_RATR_TRAP_ACTION_DISCARD_ERRORS;
4288 mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, true,
ed43cff0
AC
4289 MLXSW_REG_RATR_TYPE_ETHERNET,
4290 mlxsw_sp->router->adj_discard_index, rif_index);
0c3cbbf9 4291 mlxsw_reg_ratr_trap_action_set(ratr_pl, trap_action);
983db619
IS
4292 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl);
4293 if (err)
4294 goto err_ratr_write;
4295
4296 mlxsw_sp->router->adj_discard_index_valid = true;
4297
4298 return 0;
4299
4300err_ratr_write:
4301 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
4302 mlxsw_sp->router->adj_discard_index);
4303 return err;
0c3cbbf9
AC
4304}
4305
9dbf4d76
IS
4306static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp,
4307 struct mlxsw_sp_fib_entry *fib_entry,
4308 enum mlxsw_reg_ralue_op op)
4309{
0c3cbbf9 4310 struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group;
9dbf4d76 4311 char ralue_pl[MLXSW_REG_RALUE_LEN];
a7ff87ac
JP
4312 enum mlxsw_reg_ralue_trap_action trap_action;
4313 u16 trap_id = 0;
4314 u32 adjacency_index = 0;
4315 u16 ecmp_size = 0;
0c3cbbf9 4316 int err;
a7ff87ac
JP
4317
4318 /* In case the nexthop group adjacency index is valid, use it
4319 * with provided ECMP size. Otherwise, setup trap and pass
4320 * traffic to kernel.
4321 */
4b411477 4322 if (mlxsw_sp_fib_entry_should_offload(fib_entry)) {
a7ff87ac
JP
4323 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
4324 adjacency_index = fib_entry->nh_group->adj_index;
4325 ecmp_size = fib_entry->nh_group->ecmp_size;
0c3cbbf9
AC
4326 } else if (!nh_group->adj_index_valid && nh_group->count &&
4327 nh_group->nh_rif) {
4328 err = mlxsw_sp_adj_discard_write(mlxsw_sp,
4329 nh_group->nh_rif->rif_index);
4330 if (err)
4331 return err;
4332 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
4333 adjacency_index = mlxsw_sp->router->adj_discard_index;
4334 ecmp_size = 1;
a7ff87ac
JP
4335 } else {
4336 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
4337 trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
4338 }
4339
9dbf4d76 4340 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
a7ff87ac
JP
4341 mlxsw_reg_ralue_act_remote_pack(ralue_pl, trap_action, trap_id,
4342 adjacency_index, ecmp_size);
4343 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
4344}
4345
9dbf4d76
IS
4346static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp *mlxsw_sp,
4347 struct mlxsw_sp_fib_entry *fib_entry,
4348 enum mlxsw_reg_ralue_op op)
61c503f9 4349{
bf95233e 4350 struct mlxsw_sp_rif *rif = fib_entry->nh_group->nh_rif;
70ad3506 4351 enum mlxsw_reg_ralue_trap_action trap_action;
61c503f9 4352 char ralue_pl[MLXSW_REG_RALUE_LEN];
70ad3506 4353 u16 trap_id = 0;
bf95233e 4354 u16 rif_index = 0;
70ad3506
IS
4355
4356 if (mlxsw_sp_fib_entry_should_offload(fib_entry)) {
4357 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP;
bf95233e 4358 rif_index = rif->rif_index;
70ad3506
IS
4359 } else {
4360 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
4361 trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
4362 }
61c503f9 4363
9dbf4d76 4364 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
bf95233e
AS
4365 mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id,
4366 rif_index);
61c503f9
JP
4367 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
4368}
4369
9dbf4d76
IS
4370static int mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp *mlxsw_sp,
4371 struct mlxsw_sp_fib_entry *fib_entry,
4372 enum mlxsw_reg_ralue_op op)
61c503f9
JP
4373{
4374 char ralue_pl[MLXSW_REG_RALUE_LEN];
61c503f9 4375
9dbf4d76 4376 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
61c503f9
JP
4377 mlxsw_reg_ralue_act_ip2me_pack(ralue_pl);
4378 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
4379}
4380
2810c3b2
IS
4381static int mlxsw_sp_fib_entry_op_blackhole(struct mlxsw_sp *mlxsw_sp,
4382 struct mlxsw_sp_fib_entry *fib_entry,
4383 enum mlxsw_reg_ralue_op op)
4384{
4385 enum mlxsw_reg_ralue_trap_action trap_action;
4386 char ralue_pl[MLXSW_REG_RALUE_LEN];
4387
4388 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_DISCARD_ERROR;
4389 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
4390 mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, 0, 0);
4391 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
4392}
4393
21151f64
AC
4394static int
4395mlxsw_sp_fib_entry_op_unreachable(struct mlxsw_sp *mlxsw_sp,
4396 struct mlxsw_sp_fib_entry *fib_entry,
4397 enum mlxsw_reg_ralue_op op)
4398{
4399 enum mlxsw_reg_ralue_trap_action trap_action;
4400 char ralue_pl[MLXSW_REG_RALUE_LEN];
4401 u16 trap_id;
4402
4403 trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
4404 trap_id = MLXSW_TRAP_ID_RTR_INGRESS1;
4405
4406 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
4407 mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id, 0);
4408 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
4409}
4410
4607f6d2
PM
4411static int
4412mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp,
4413 struct mlxsw_sp_fib_entry *fib_entry,
4414 enum mlxsw_reg_ralue_op op)
4415{
4416 struct mlxsw_sp_ipip_entry *ipip_entry = fib_entry->decap.ipip_entry;
4417 const struct mlxsw_sp_ipip_ops *ipip_ops;
4418
4419 if (WARN_ON(!ipip_entry))
4420 return -EINVAL;
4421
4422 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
4423 return ipip_ops->fib_entry_op(mlxsw_sp, ipip_entry, op,
4424 fib_entry->decap.tunnel_index);
4425}
4426
0c69e0fc
IS
4427static int mlxsw_sp_fib_entry_op_nve_decap(struct mlxsw_sp *mlxsw_sp,
4428 struct mlxsw_sp_fib_entry *fib_entry,
4429 enum mlxsw_reg_ralue_op op)
4430{
4431 char ralue_pl[MLXSW_REG_RALUE_LEN];
4432
4433 mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
4434 mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl,
4435 fib_entry->decap.tunnel_index);
4436 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
4437}
4438
9dbf4d76
IS
4439static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
4440 struct mlxsw_sp_fib_entry *fib_entry,
4441 enum mlxsw_reg_ralue_op op)
61c503f9
JP
4442{
4443 switch (fib_entry->type) {
4444 case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE:
9dbf4d76 4445 return mlxsw_sp_fib_entry_op_remote(mlxsw_sp, fib_entry, op);
61c503f9 4446 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
9dbf4d76 4447 return mlxsw_sp_fib_entry_op_local(mlxsw_sp, fib_entry, op);
61c503f9 4448 case MLXSW_SP_FIB_ENTRY_TYPE_TRAP:
9dbf4d76 4449 return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, fib_entry, op);
2810c3b2
IS
4450 case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE:
4451 return mlxsw_sp_fib_entry_op_blackhole(mlxsw_sp, fib_entry, op);
21151f64
AC
4452 case MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE:
4453 return mlxsw_sp_fib_entry_op_unreachable(mlxsw_sp, fib_entry,
4454 op);
4607f6d2
PM
4455 case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
4456 return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp,
4457 fib_entry, op);
0c69e0fc
IS
4458 case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP:
4459 return mlxsw_sp_fib_entry_op_nve_decap(mlxsw_sp, fib_entry, op);
61c503f9
JP
4460 }
4461 return -EINVAL;
4462}
4463
4464static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
4465 struct mlxsw_sp_fib_entry *fib_entry,
4466 enum mlxsw_reg_ralue_op op)
4467{
9dbf4d76 4468 int err = __mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, op);
013b20f9 4469
ee5a0448
IS
4470 if (err)
4471 return err;
4472
4473 mlxsw_sp_fib_entry_hw_flags_refresh(mlxsw_sp, fib_entry, op);
9dbf4d76 4474
013b20f9 4475 return err;
61c503f9
JP
4476}
4477
4478static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
4479 struct mlxsw_sp_fib_entry *fib_entry)
4480{
7146da31
JP
4481 return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
4482 MLXSW_REG_RALUE_OP_WRITE_WRITE);
61c503f9
JP
4483}
4484
4485static int mlxsw_sp_fib_entry_del(struct mlxsw_sp *mlxsw_sp,
4486 struct mlxsw_sp_fib_entry *fib_entry)
4487{
4488 return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
4489 MLXSW_REG_RALUE_OP_WRITE_DELETE);
4490}
4491
61c503f9 4492static int
013b20f9
IS
4493mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
4494 const struct fib_entry_notifier_info *fen_info,
4495 struct mlxsw_sp_fib_entry *fib_entry)
61c503f9 4496{
5481d73f 4497 struct net_device *dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev;
4607f6d2 4498 union mlxsw_sp_l3addr dip = { .addr4 = htonl(fen_info->dst) };
8e18d85e 4499 struct mlxsw_sp_router *router = mlxsw_sp->router;
4cf178d7 4500 u32 tb_id = mlxsw_sp_fix_tb_id(fen_info->tb_id);
4607f6d2 4501 struct mlxsw_sp_ipip_entry *ipip_entry;
b45f64d1 4502 struct fib_info *fi = fen_info->fi;
61c503f9 4503
97989ee0 4504 switch (fen_info->type) {
97989ee0 4505 case RTN_LOCAL:
4607f6d2
PM
4506 ipip_entry = mlxsw_sp_ipip_entry_find_by_decap(mlxsw_sp, dev,
4507 MLXSW_SP_L3_PROTO_IPV4, dip);
57c77ce4 4508 if (ipip_entry && ipip_entry->ol_dev->flags & IFF_UP) {
4607f6d2
PM
4509 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;
4510 return mlxsw_sp_fib_entry_decap_init(mlxsw_sp,
4511 fib_entry,
4512 ipip_entry);
4513 }
8e18d85e
IS
4514 if (mlxsw_sp_router_nve_is_decap(mlxsw_sp, tb_id,
4515 MLXSW_SP_L3_PROTO_IPV4,
4516 &dip)) {
4517 u32 tunnel_index;
4cf178d7 4518
8e18d85e
IS
4519 tunnel_index = router->nve_decap_config.tunnel_index;
4520 fib_entry->decap.tunnel_index = tunnel_index;
4cf178d7
IS
4521 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP;
4522 return 0;
4523 }
4607f6d2
PM
4524 /* fall through */
4525 case RTN_BROADCAST:
61c503f9
JP
4526 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
4527 return 0;
2810c3b2
IS
4528 case RTN_BLACKHOLE:
4529 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE;
4530 return 0;
97989ee0 4531 case RTN_UNREACHABLE: /* fall through */
97989ee0
IS
4532 case RTN_PROHIBIT:
4533 /* Packets hitting these routes need to be trapped, but
4534 * can do so with a lower priority than packets directed
4535 * at the host, so use action type local instead of trap.
4536 */
21151f64 4537 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE;
97989ee0
IS
4538 return 0;
4539 case RTN_UNICAST:
9b01451a 4540 if (mlxsw_sp_fi_is_gateway(mlxsw_sp, fi))
97989ee0 4541 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
9b01451a
PM
4542 else
4543 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
97989ee0
IS
4544 return 0;
4545 default:
4546 return -EINVAL;
4547 }
a7ff87ac
JP
4548}
4549
0705297e
IS
4550static void
4551mlxsw_sp_fib4_entry_type_unset(struct mlxsw_sp *mlxsw_sp,
4552 struct mlxsw_sp_fib_entry *fib_entry)
4553{
4554 switch (fib_entry->type) {
4555 case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
4556 mlxsw_sp_fib_entry_decap_fini(mlxsw_sp, fib_entry);
4557 break;
4558 default:
4559 break;
4560 }
4561}
4562
4f1c7f1f 4563static struct mlxsw_sp_fib4_entry *
9aecce1c
IS
4564mlxsw_sp_fib4_entry_create(struct mlxsw_sp *mlxsw_sp,
4565 struct mlxsw_sp_fib_node *fib_node,
4566 const struct fib_entry_notifier_info *fen_info)
61c503f9 4567{
4f1c7f1f 4568 struct mlxsw_sp_fib4_entry *fib4_entry;
61c503f9 4569 struct mlxsw_sp_fib_entry *fib_entry;
61c503f9
JP
4570 int err;
4571
4f1c7f1f
IS
4572 fib4_entry = kzalloc(sizeof(*fib4_entry), GFP_KERNEL);
4573 if (!fib4_entry)
4574 return ERR_PTR(-ENOMEM);
4575 fib_entry = &fib4_entry->common;
61c503f9 4576
013b20f9 4577 err = mlxsw_sp_fib4_entry_type_set(mlxsw_sp, fen_info, fib_entry);
61c503f9 4578 if (err)
013b20f9 4579 goto err_fib4_entry_type_set;
61c503f9 4580
0e6ea2a4 4581 err = mlxsw_sp_nexthop4_group_get(mlxsw_sp, fib_entry, fen_info->fi);
b8399a1e 4582 if (err)
0e6ea2a4 4583 goto err_nexthop4_group_get;
b8399a1e 4584
4f1c7f1f
IS
4585 fib4_entry->prio = fen_info->fi->fib_priority;
4586 fib4_entry->tb_id = fen_info->tb_id;
4587 fib4_entry->type = fen_info->type;
4588 fib4_entry->tos = fen_info->tos;
9aecce1c
IS
4589
4590 fib_entry->fib_node = fib_node;
4591
4f1c7f1f 4592 return fib4_entry;
5b004412 4593
0e6ea2a4 4594err_nexthop4_group_get:
0705297e 4595 mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, fib_entry);
013b20f9 4596err_fib4_entry_type_set:
4f1c7f1f 4597 kfree(fib4_entry);
5b004412
JP
4598 return ERR_PTR(err);
4599}
4600
9aecce1c 4601static void mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp *mlxsw_sp,
4f1c7f1f 4602 struct mlxsw_sp_fib4_entry *fib4_entry)
9aecce1c 4603{
0e6ea2a4 4604 mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
0705297e 4605 mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, &fib4_entry->common);
4f1c7f1f 4606 kfree(fib4_entry);
9aecce1c
IS
4607}
4608
4f1c7f1f 4609static struct mlxsw_sp_fib4_entry *
9aecce1c
IS
4610mlxsw_sp_fib4_entry_lookup(struct mlxsw_sp *mlxsw_sp,
4611 const struct fib_entry_notifier_info *fen_info)
5b004412 4612{
4f1c7f1f 4613 struct mlxsw_sp_fib4_entry *fib4_entry;
9aecce1c 4614 struct mlxsw_sp_fib_node *fib_node;
160e22aa
IS
4615 struct mlxsw_sp_fib *fib;
4616 struct mlxsw_sp_vr *vr;
4617
4618 vr = mlxsw_sp_vr_find(mlxsw_sp, fen_info->tb_id);
4619 if (!vr)
4620 return NULL;
4621 fib = mlxsw_sp_vr_fib(vr, MLXSW_SP_L3_PROTO_IPV4);
5b004412 4622
160e22aa
IS
4623 fib_node = mlxsw_sp_fib_node_lookup(fib, &fen_info->dst,
4624 sizeof(fen_info->dst),
4625 fen_info->dst_len);
4626 if (!fib_node)
9aecce1c
IS
4627 return NULL;
4628
7c4a7ec8
IS
4629 fib4_entry = container_of(fib_node->fib_entry,
4630 struct mlxsw_sp_fib4_entry, common);
4631 if (fib4_entry->tb_id == fen_info->tb_id &&
4632 fib4_entry->tos == fen_info->tos &&
4633 fib4_entry->type == fen_info->type &&
4634 mlxsw_sp_nexthop4_group_fi(fib4_entry->common.nh_group) ==
4635 fen_info->fi)
4636 return fib4_entry;
9aecce1c
IS
4637
4638 return NULL;
4639}
4640
4641static const struct rhashtable_params mlxsw_sp_fib_ht_params = {
4642 .key_offset = offsetof(struct mlxsw_sp_fib_node, key),
4643 .head_offset = offsetof(struct mlxsw_sp_fib_node, ht_node),
4644 .key_len = sizeof(struct mlxsw_sp_fib_key),
4645 .automatic_shrinking = true,
4646};
4647
4648static int mlxsw_sp_fib_node_insert(struct mlxsw_sp_fib *fib,
4649 struct mlxsw_sp_fib_node *fib_node)
4650{
4651 return rhashtable_insert_fast(&fib->ht, &fib_node->ht_node,
4652 mlxsw_sp_fib_ht_params);
4653}
4654
4655static void mlxsw_sp_fib_node_remove(struct mlxsw_sp_fib *fib,
4656 struct mlxsw_sp_fib_node *fib_node)
4657{
4658 rhashtable_remove_fast(&fib->ht, &fib_node->ht_node,
4659 mlxsw_sp_fib_ht_params);
4660}
4661
4662static struct mlxsw_sp_fib_node *
4663mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib *fib, const void *addr,
4664 size_t addr_len, unsigned char prefix_len)
4665{
4666 struct mlxsw_sp_fib_key key;
4667
4668 memset(&key, 0, sizeof(key));
4669 memcpy(key.addr, addr, addr_len);
4670 key.prefix_len = prefix_len;
4671 return rhashtable_lookup_fast(&fib->ht, &key, mlxsw_sp_fib_ht_params);
4672}
4673
4674static struct mlxsw_sp_fib_node *
76610ebb 4675mlxsw_sp_fib_node_create(struct mlxsw_sp_fib *fib, const void *addr,
9aecce1c
IS
4676 size_t addr_len, unsigned char prefix_len)
4677{
4678 struct mlxsw_sp_fib_node *fib_node;
4679
4680 fib_node = kzalloc(sizeof(*fib_node), GFP_KERNEL);
4681 if (!fib_node)
5b004412
JP
4682 return NULL;
4683
76610ebb 4684 list_add(&fib_node->list, &fib->node_list);
9aecce1c
IS
4685 memcpy(fib_node->key.addr, addr, addr_len);
4686 fib_node->key.prefix_len = prefix_len;
9aecce1c
IS
4687
4688 return fib_node;
4689}
4690
4691static void mlxsw_sp_fib_node_destroy(struct mlxsw_sp_fib_node *fib_node)
4692{
9aecce1c 4693 list_del(&fib_node->list);
9aecce1c
IS
4694 kfree(fib_node);
4695}
4696
fc922bb0 4697static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp *mlxsw_sp,
fc922bb0
IS
4698 struct mlxsw_sp_fib_node *fib_node)
4699{
2b52ce02 4700 struct mlxsw_sp_prefix_usage req_prefix_usage;
3aad95df 4701 struct mlxsw_sp_fib *fib = fib_node->fib;
fc922bb0
IS
4702 struct mlxsw_sp_lpm_tree *lpm_tree;
4703 int err;
4704
2b52ce02
IS
4705 lpm_tree = mlxsw_sp->router->lpm.proto_trees[fib->proto];
4706 if (lpm_tree->prefix_ref_count[fib_node->key.prefix_len] != 0)
4707 goto out;
fc922bb0 4708
2b52ce02
IS
4709 mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &lpm_tree->prefix_usage);
4710 mlxsw_sp_prefix_usage_set(&req_prefix_usage, fib_node->key.prefix_len);
fc922bb0
IS
4711 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
4712 fib->proto);
4713 if (IS_ERR(lpm_tree))
4714 return PTR_ERR(lpm_tree);
4715
fc922bb0
IS
4716 err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
4717 if (err)
2b52ce02 4718 goto err_lpm_tree_replace;
fc922bb0 4719
2b52ce02
IS
4720out:
4721 lpm_tree->prefix_ref_count[fib_node->key.prefix_len]++;
fc922bb0 4722 return 0;
2b52ce02
IS
4723
4724err_lpm_tree_replace:
4725 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
4726 return err;
fc922bb0
IS
4727}
4728
4729static void mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp *mlxsw_sp,
3aad95df 4730 struct mlxsw_sp_fib_node *fib_node)
fc922bb0 4731{
2b52ce02
IS
4732 struct mlxsw_sp_lpm_tree *lpm_tree = fib_node->fib->lpm_tree;
4733 struct mlxsw_sp_prefix_usage req_prefix_usage;
3aad95df 4734 struct mlxsw_sp_fib *fib = fib_node->fib;
2b52ce02 4735 int err;
3aad95df 4736
2b52ce02 4737 if (--lpm_tree->prefix_ref_count[fib_node->key.prefix_len] != 0)
fc922bb0 4738 return;
2b52ce02
IS
4739 /* Try to construct a new LPM tree from the current prefix usage
4740 * minus the unused one. If we fail, continue using the old one.
4fd00312 4741 */
2b52ce02
IS
4742 mlxsw_sp_prefix_usage_cpy(&req_prefix_usage, &lpm_tree->prefix_usage);
4743 mlxsw_sp_prefix_usage_clear(&req_prefix_usage,
4744 fib_node->key.prefix_len);
4745 lpm_tree = mlxsw_sp_lpm_tree_get(mlxsw_sp, &req_prefix_usage,
4746 fib->proto);
4747 if (IS_ERR(lpm_tree))
4748 return;
9aecce1c 4749
2b52ce02
IS
4750 err = mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp, fib, lpm_tree);
4751 if (err)
4752 goto err_lpm_tree_replace;
9aecce1c 4753
2b52ce02 4754 return;
9aecce1c 4755
2b52ce02
IS
4756err_lpm_tree_replace:
4757 mlxsw_sp_lpm_tree_put(mlxsw_sp, lpm_tree);
5b004412
JP
4758}
4759
76610ebb
IS
4760static int mlxsw_sp_fib_node_init(struct mlxsw_sp *mlxsw_sp,
4761 struct mlxsw_sp_fib_node *fib_node,
4762 struct mlxsw_sp_fib *fib)
4763{
76610ebb
IS
4764 int err;
4765
4766 err = mlxsw_sp_fib_node_insert(fib, fib_node);
4767 if (err)
4768 return err;
4769 fib_node->fib = fib;
4770
3aad95df 4771 err = mlxsw_sp_fib_lpm_tree_link(mlxsw_sp, fib_node);
fc922bb0
IS
4772 if (err)
4773 goto err_fib_lpm_tree_link;
76610ebb 4774
76610ebb
IS
4775 return 0;
4776
fc922bb0 4777err_fib_lpm_tree_link:
76610ebb
IS
4778 fib_node->fib = NULL;
4779 mlxsw_sp_fib_node_remove(fib, fib_node);
4780 return err;
4781}
4782
4783static void mlxsw_sp_fib_node_fini(struct mlxsw_sp *mlxsw_sp,
4784 struct mlxsw_sp_fib_node *fib_node)
4785{
76610ebb
IS
4786 struct mlxsw_sp_fib *fib = fib_node->fib;
4787
3aad95df 4788 mlxsw_sp_fib_lpm_tree_unlink(mlxsw_sp, fib_node);
76610ebb
IS
4789 fib_node->fib = NULL;
4790 mlxsw_sp_fib_node_remove(fib, fib_node);
4791}
4792
9aecce1c 4793static struct mlxsw_sp_fib_node *
731ea1ca
IS
4794mlxsw_sp_fib_node_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id, const void *addr,
4795 size_t addr_len, unsigned char prefix_len,
4796 enum mlxsw_sp_l3proto proto)
5b004412 4797{
9aecce1c 4798 struct mlxsw_sp_fib_node *fib_node;
76610ebb 4799 struct mlxsw_sp_fib *fib;
9aecce1c
IS
4800 struct mlxsw_sp_vr *vr;
4801 int err;
4802
f8fa9b4e 4803 vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id, NULL);
9aecce1c
IS
4804 if (IS_ERR(vr))
4805 return ERR_CAST(vr);
731ea1ca 4806 fib = mlxsw_sp_vr_fib(vr, proto);
9aecce1c 4807
731ea1ca 4808 fib_node = mlxsw_sp_fib_node_lookup(fib, addr, addr_len, prefix_len);
9aecce1c
IS
4809 if (fib_node)
4810 return fib_node;
5b004412 4811
731ea1ca 4812 fib_node = mlxsw_sp_fib_node_create(fib, addr, addr_len, prefix_len);
9aecce1c
IS
4813 if (!fib_node) {
4814 err = -ENOMEM;
4815 goto err_fib_node_create;
5b004412 4816 }
9aecce1c 4817
76610ebb
IS
4818 err = mlxsw_sp_fib_node_init(mlxsw_sp, fib_node, fib);
4819 if (err)
4820 goto err_fib_node_init;
4821
9aecce1c
IS
4822 return fib_node;
4823
76610ebb
IS
4824err_fib_node_init:
4825 mlxsw_sp_fib_node_destroy(fib_node);
9aecce1c 4826err_fib_node_create:
2b52ce02 4827 mlxsw_sp_vr_put(mlxsw_sp, vr);
9aecce1c 4828 return ERR_PTR(err);
5b004412
JP
4829}
4830
731ea1ca
IS
4831static void mlxsw_sp_fib_node_put(struct mlxsw_sp *mlxsw_sp,
4832 struct mlxsw_sp_fib_node *fib_node)
5b004412 4833{
76610ebb 4834 struct mlxsw_sp_vr *vr = fib_node->fib->vr;
5b004412 4835
7c4a7ec8 4836 if (fib_node->fib_entry)
9aecce1c 4837 return;
76610ebb 4838 mlxsw_sp_fib_node_fini(mlxsw_sp, fib_node);
9aecce1c 4839 mlxsw_sp_fib_node_destroy(fib_node);
2b52ce02 4840 mlxsw_sp_vr_put(mlxsw_sp, vr);
61c503f9
JP
4841}
4842
b04720ae
IS
4843static int mlxsw_sp_fib_node_entry_link(struct mlxsw_sp *mlxsw_sp,
4844 struct mlxsw_sp_fib_entry *fib_entry)
9aecce1c 4845{
b04720ae 4846 struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
9aecce1c
IS
4847 int err;
4848
7c4a7ec8 4849 fib_node->fib_entry = fib_entry;
9aecce1c 4850
7c4a7ec8 4851 err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
9aecce1c 4852 if (err)
7c4a7ec8 4853 goto err_fib_entry_update;
9aecce1c 4854
9aecce1c
IS
4855 return 0;
4856
7c4a7ec8
IS
4857err_fib_entry_update:
4858 fib_node->fib_entry = NULL;
9aecce1c
IS
4859 return err;
4860}
4861
4862static void
b04720ae
IS
4863mlxsw_sp_fib_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
4864 struct mlxsw_sp_fib_entry *fib_entry)
9aecce1c 4865{
7c4a7ec8 4866 struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
599cf8f9 4867
7c4a7ec8
IS
4868 mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry);
4869 fib_node->fib_entry = NULL;
599cf8f9
IS
4870}
4871
0508ff89
IS
4872static bool mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry *fib4_entry)
4873{
4874 struct mlxsw_sp_fib_node *fib_node = fib4_entry->common.fib_node;
4875 struct mlxsw_sp_fib4_entry *fib4_replaced;
4876
4877 if (!fib_node->fib_entry)
4878 return true;
4879
4880 fib4_replaced = container_of(fib_node->fib_entry,
4881 struct mlxsw_sp_fib4_entry, common);
4882 if (fib4_entry->tb_id == RT_TABLE_MAIN &&
4883 fib4_replaced->tb_id == RT_TABLE_LOCAL)
4884 return false;
4885
4886 return true;
4887}
4888
9aecce1c 4889static int
b6a1d871
IS
4890mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
4891 const struct fib_entry_notifier_info *fen_info)
9aecce1c 4892{
7c4a7ec8
IS
4893 struct mlxsw_sp_fib4_entry *fib4_entry, *fib4_replaced;
4894 struct mlxsw_sp_fib_entry *replaced;
9aecce1c 4895 struct mlxsw_sp_fib_node *fib_node;
61c503f9
JP
4896 int err;
4897
9011b677 4898 if (mlxsw_sp->router->aborted)
b45f64d1
JP
4899 return 0;
4900
731ea1ca
IS
4901 fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, fen_info->tb_id,
4902 &fen_info->dst, sizeof(fen_info->dst),
4903 fen_info->dst_len,
4904 MLXSW_SP_L3_PROTO_IPV4);
9aecce1c
IS
4905 if (IS_ERR(fib_node)) {
4906 dev_warn(mlxsw_sp->bus_info->dev, "Failed to get FIB node\n");
4907 return PTR_ERR(fib_node);
b45f64d1 4908 }
61c503f9 4909
4f1c7f1f
IS
4910 fib4_entry = mlxsw_sp_fib4_entry_create(mlxsw_sp, fib_node, fen_info);
4911 if (IS_ERR(fib4_entry)) {
9aecce1c 4912 dev_warn(mlxsw_sp->bus_info->dev, "Failed to create FIB entry\n");
4f1c7f1f 4913 err = PTR_ERR(fib4_entry);
9aecce1c
IS
4914 goto err_fib4_entry_create;
4915 }
5b004412 4916
0508ff89
IS
4917 if (!mlxsw_sp_fib4_allow_replace(fib4_entry)) {
4918 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
4919 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
4920 return 0;
4921 }
4922
7c4a7ec8 4923 replaced = fib_node->fib_entry;
b04720ae 4924 err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib4_entry->common);
b45f64d1 4925 if (err) {
9aecce1c 4926 dev_warn(mlxsw_sp->bus_info->dev, "Failed to link FIB entry to node\n");
b04720ae 4927 goto err_fib_node_entry_link;
b45f64d1 4928 }
9aecce1c 4929
7c4a7ec8
IS
4930 /* Nothing to replace */
4931 if (!replaced)
4932 return 0;
4933
ee5a0448 4934 mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, replaced);
7c4a7ec8
IS
4935 fib4_replaced = container_of(replaced, struct mlxsw_sp_fib4_entry,
4936 common);
4937 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_replaced);
599cf8f9 4938
61c503f9
JP
4939 return 0;
4940
b04720ae 4941err_fib_node_entry_link:
7c4a7ec8 4942 fib_node->fib_entry = replaced;
4f1c7f1f 4943 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
9aecce1c 4944err_fib4_entry_create:
731ea1ca 4945 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
61c503f9
JP
4946 return err;
4947}
4948
37956d78
JP
4949static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
4950 struct fib_entry_notifier_info *fen_info)
61c503f9 4951{
4f1c7f1f 4952 struct mlxsw_sp_fib4_entry *fib4_entry;
9aecce1c 4953 struct mlxsw_sp_fib_node *fib_node;
61c503f9 4954
9011b677 4955 if (mlxsw_sp->router->aborted)
37956d78 4956 return;
b45f64d1 4957
4f1c7f1f 4958 fib4_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info);
0508ff89 4959 if (!fib4_entry)
37956d78 4960 return;
4f1c7f1f 4961 fib_node = fib4_entry->common.fib_node;
5b004412 4962
b04720ae 4963 mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib4_entry->common);
4f1c7f1f 4964 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
731ea1ca 4965 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
61c503f9 4966}
b45f64d1 4967
8d1c802b 4968static bool mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info *rt)
428b851f
IS
4969{
4970 /* Packets with link-local destination IP arriving to the router
4971 * are trapped to the CPU, so no need to program specific routes
4972 * for them.
4973 */
93c2fb25 4974 if (ipv6_addr_type(&rt->fib6_dst.addr) & IPV6_ADDR_LINKLOCAL)
428b851f
IS
4975 return true;
4976
4977 /* Multicast routes aren't supported, so ignore them. Neighbour
4978 * Discovery packets are specifically trapped.
4979 */
93c2fb25 4980 if (ipv6_addr_type(&rt->fib6_dst.addr) & IPV6_ADDR_MULTICAST)
428b851f
IS
4981 return true;
4982
4983 /* Cloned routes are irrelevant in the forwarding path. */
93c2fb25 4984 if (rt->fib6_flags & RTF_CACHE)
428b851f
IS
4985 return true;
4986
4987 return false;
4988}
4989
8d1c802b 4990static struct mlxsw_sp_rt6 *mlxsw_sp_rt6_create(struct fib6_info *rt)
428b851f
IS
4991{
4992 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
4993
4994 mlxsw_sp_rt6 = kzalloc(sizeof(*mlxsw_sp_rt6), GFP_KERNEL);
4995 if (!mlxsw_sp_rt6)
4996 return ERR_PTR(-ENOMEM);
4997
4998 /* In case of route replace, replaced route is deleted with
4999 * no notification. Take reference to prevent accessing freed
5000 * memory.
5001 */
5002 mlxsw_sp_rt6->rt = rt;
8d1c802b 5003 fib6_info_hold(rt);
428b851f
IS
5004
5005 return mlxsw_sp_rt6;
5006}
5007
5008#if IS_ENABLED(CONFIG_IPV6)
8d1c802b 5009static void mlxsw_sp_rt6_release(struct fib6_info *rt)
428b851f 5010{
8d1c802b 5011 fib6_info_release(rt);
428b851f
IS
5012}
5013#else
8d1c802b 5014static void mlxsw_sp_rt6_release(struct fib6_info *rt)
428b851f
IS
5015{
5016}
5017#endif
5018
5019static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
5020{
490f0542
IS
5021 struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
5022
5023 fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
428b851f
IS
5024 mlxsw_sp_rt6_release(mlxsw_sp_rt6->rt);
5025 kfree(mlxsw_sp_rt6);
5026}
5027
8d1c802b 5028static struct fib6_info *
428b851f
IS
5029mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry)
5030{
5031 return list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6,
5032 list)->rt;
5033}
5034
428b851f
IS
5035static struct mlxsw_sp_rt6 *
5036mlxsw_sp_fib6_entry_rt_find(const struct mlxsw_sp_fib6_entry *fib6_entry,
8d1c802b 5037 const struct fib6_info *rt)
428b851f
IS
5038{
5039 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
5040
5041 list_for_each_entry(mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {
5042 if (mlxsw_sp_rt6->rt == rt)
5043 return mlxsw_sp_rt6;
5044 }
5045
5046 return NULL;
5047}
5048
8f28a309 5049static bool mlxsw_sp_nexthop6_ipip_type(const struct mlxsw_sp *mlxsw_sp,
8d1c802b 5050 const struct fib6_info *rt,
8f28a309
PM
5051 enum mlxsw_sp_ipip_type *ret)
5052{
1cf844c7
DA
5053 return rt->fib6_nh->fib_nh_dev &&
5054 mlxsw_sp_netdev_ipip_type(mlxsw_sp, rt->fib6_nh->fib_nh_dev, ret);
8f28a309
PM
5055}
5056
35225e47
PM
5057static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp *mlxsw_sp,
5058 struct mlxsw_sp_nexthop_group *nh_grp,
5059 struct mlxsw_sp_nexthop *nh,
8d1c802b 5060 const struct fib6_info *rt)
428b851f 5061{
d97cda5f
PM
5062 const struct mlxsw_sp_ipip_ops *ipip_ops;
5063 struct mlxsw_sp_ipip_entry *ipip_entry;
1cf844c7 5064 struct net_device *dev = rt->fib6_nh->fib_nh_dev;
428b851f
IS
5065 struct mlxsw_sp_rif *rif;
5066 int err;
5067
d97cda5f
PM
5068 ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, dev);
5069 if (ipip_entry) {
5070 ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
5071 if (ipip_ops->can_offload(mlxsw_sp, dev,
5072 MLXSW_SP_L3_PROTO_IPV6)) {
5073 nh->type = MLXSW_SP_NEXTHOP_TYPE_IPIP;
5074 mlxsw_sp_nexthop_ipip_init(mlxsw_sp, nh, ipip_entry);
5075 return 0;
5076 }
8f28a309
PM
5077 }
5078
35225e47 5079 nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH;
428b851f
IS
5080 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
5081 if (!rif)
5082 return 0;
5083 mlxsw_sp_nexthop_rif_init(nh, rif);
5084
5085 err = mlxsw_sp_nexthop_neigh_init(mlxsw_sp, nh);
5086 if (err)
5087 goto err_nexthop_neigh_init;
5088
5089 return 0;
5090
5091err_nexthop_neigh_init:
5092 mlxsw_sp_nexthop_rif_fini(nh);
5093 return err;
5094}
5095
35225e47
PM
5096static void mlxsw_sp_nexthop6_type_fini(struct mlxsw_sp *mlxsw_sp,
5097 struct mlxsw_sp_nexthop *nh)
5098{
5099 mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh);
5100}
5101
5102static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,
5103 struct mlxsw_sp_nexthop_group *nh_grp,
5104 struct mlxsw_sp_nexthop *nh,
8d1c802b 5105 const struct fib6_info *rt)
35225e47 5106{
1cf844c7 5107 struct net_device *dev = rt->fib6_nh->fib_nh_dev;
35225e47
PM
5108
5109 nh->nh_grp = nh_grp;
1cf844c7
DA
5110 nh->nh_weight = rt->fib6_nh->fib_nh_weight;
5111 memcpy(&nh->gw_addr, &rt->fib6_nh->fib_nh_gw6, sizeof(nh->gw_addr));
a5390278 5112 mlxsw_sp_nexthop_counter_alloc(mlxsw_sp, nh);
35225e47 5113
dbe4598c
AS
5114 list_add_tail(&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
5115
35225e47
PM
5116 if (!dev)
5117 return 0;
5118 nh->ifindex = dev->ifindex;
5119
5120 return mlxsw_sp_nexthop6_type_init(mlxsw_sp, nh_grp, nh, rt);
5121}
5122
428b851f
IS
5123static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp,
5124 struct mlxsw_sp_nexthop *nh)
5125{
35225e47 5126 mlxsw_sp_nexthop6_type_fini(mlxsw_sp, nh);
dbe4598c 5127 list_del(&nh->router_list_node);
a5390278 5128 mlxsw_sp_nexthop_counter_free(mlxsw_sp, nh);
428b851f
IS
5129}
5130
f6050ee6 5131static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp *mlxsw_sp,
8d1c802b 5132 const struct fib6_info *rt)
f6050ee6 5133{
1cf844c7 5134 return rt->fib6_nh->fib_nh_gw_family ||
8f28a309 5135 mlxsw_sp_nexthop6_ipip_type(mlxsw_sp, rt, NULL);
f6050ee6
PM
5136}
5137
428b851f
IS
5138static struct mlxsw_sp_nexthop_group *
5139mlxsw_sp_nexthop6_group_create(struct mlxsw_sp *mlxsw_sp,
5140 struct mlxsw_sp_fib6_entry *fib6_entry)
5141{
5142 struct mlxsw_sp_nexthop_group *nh_grp;
5143 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
5144 struct mlxsw_sp_nexthop *nh;
428b851f
IS
5145 int i = 0;
5146 int err;
5147
9e475293
GS
5148 nh_grp = kzalloc(struct_size(nh_grp, nexthops, fib6_entry->nrt6),
5149 GFP_KERNEL);
428b851f
IS
5150 if (!nh_grp)
5151 return ERR_PTR(-ENOMEM);
5152 INIT_LIST_HEAD(&nh_grp->fib_list);
5153#if IS_ENABLED(CONFIG_IPV6)
5154 nh_grp->neigh_tbl = &nd_tbl;
5155#endif
5156 mlxsw_sp_rt6 = list_first_entry(&fib6_entry->rt6_list,
5157 struct mlxsw_sp_rt6, list);
f6050ee6 5158 nh_grp->gateway = mlxsw_sp_rt6_is_gateway(mlxsw_sp, mlxsw_sp_rt6->rt);
428b851f
IS
5159 nh_grp->count = fib6_entry->nrt6;
5160 for (i = 0; i < nh_grp->count; i++) {
8d1c802b 5161 struct fib6_info *rt = mlxsw_sp_rt6->rt;
428b851f
IS
5162
5163 nh = &nh_grp->nexthops[i];
5164 err = mlxsw_sp_nexthop6_init(mlxsw_sp, nh_grp, nh, rt);
5165 if (err)
5166 goto err_nexthop6_init;
5167 mlxsw_sp_rt6 = list_next_entry(mlxsw_sp_rt6, list);
5168 }
e6f3b379
AS
5169
5170 err = mlxsw_sp_nexthop_group_insert(mlxsw_sp, nh_grp);
5171 if (err)
5172 goto err_nexthop_group_insert;
5173
428b851f
IS
5174 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
5175 return nh_grp;
5176
e6f3b379 5177err_nexthop_group_insert:
428b851f
IS
5178err_nexthop6_init:
5179 for (i--; i >= 0; i--) {
5180 nh = &nh_grp->nexthops[i];
5181 mlxsw_sp_nexthop6_fini(mlxsw_sp, nh);
5182 }
5183 kfree(nh_grp);
5184 return ERR_PTR(err);
5185}
5186
5187static void
5188mlxsw_sp_nexthop6_group_destroy(struct mlxsw_sp *mlxsw_sp,
5189 struct mlxsw_sp_nexthop_group *nh_grp)
5190{
5191 struct mlxsw_sp_nexthop *nh;
5192 int i = nh_grp->count;
5193
e6f3b379 5194 mlxsw_sp_nexthop_group_remove(mlxsw_sp, nh_grp);
428b851f
IS
5195 for (i--; i >= 0; i--) {
5196 nh = &nh_grp->nexthops[i];
5197 mlxsw_sp_nexthop6_fini(mlxsw_sp, nh);
5198 }
5199 mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp);
5200 WARN_ON(nh_grp->adj_index_valid);
5201 kfree(nh_grp);
5202}
5203
5204static int mlxsw_sp_nexthop6_group_get(struct mlxsw_sp *mlxsw_sp,
5205 struct mlxsw_sp_fib6_entry *fib6_entry)
5206{
5207 struct mlxsw_sp_nexthop_group *nh_grp;
5208
e6f3b379
AS
5209 nh_grp = mlxsw_sp_nexthop6_group_lookup(mlxsw_sp, fib6_entry);
5210 if (!nh_grp) {
5211 nh_grp = mlxsw_sp_nexthop6_group_create(mlxsw_sp, fib6_entry);
5212 if (IS_ERR(nh_grp))
5213 return PTR_ERR(nh_grp);
5214 }
428b851f
IS
5215
5216 list_add_tail(&fib6_entry->common.nexthop_group_node,
5217 &nh_grp->fib_list);
5218 fib6_entry->common.nh_group = nh_grp;
5219
8c5a5b9b
IS
5220 /* The route and the nexthop are described by the same struct, so we
5221 * need to the update the nexthop offload indication for the new route.
5222 */
5223 __mlxsw_sp_nexthop6_group_offload_refresh(nh_grp, fib6_entry);
5224
428b851f
IS
5225 return 0;
5226}
5227
5228static void mlxsw_sp_nexthop6_group_put(struct mlxsw_sp *mlxsw_sp,
5229 struct mlxsw_sp_fib_entry *fib_entry)
5230{
5231 struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
5232
5233 list_del(&fib_entry->nexthop_group_node);
5234 if (!list_empty(&nh_grp->fib_list))
5235 return;
5236 mlxsw_sp_nexthop6_group_destroy(mlxsw_sp, nh_grp);
5237}
5238
5239static int
5240mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp,
5241 struct mlxsw_sp_fib6_entry *fib6_entry)
5242{
5243 struct mlxsw_sp_nexthop_group *old_nh_grp = fib6_entry->common.nh_group;
5244 int err;
5245
5246 fib6_entry->common.nh_group = NULL;
5247 list_del(&fib6_entry->common.nexthop_group_node);
5248
5249 err = mlxsw_sp_nexthop6_group_get(mlxsw_sp, fib6_entry);
5250 if (err)
5251 goto err_nexthop6_group_get;
5252
5253 /* In case this entry is offloaded, then the adjacency index
5254 * currently associated with it in the device's table is that
5255 * of the old group. Start using the new one instead.
5256 */
7c4a7ec8 5257 err = mlxsw_sp_fib_entry_update(mlxsw_sp, &fib6_entry->common);
428b851f 5258 if (err)
7c4a7ec8 5259 goto err_fib_entry_update;
428b851f
IS
5260
5261 if (list_empty(&old_nh_grp->fib_list))
5262 mlxsw_sp_nexthop6_group_destroy(mlxsw_sp, old_nh_grp);
5263
5264 return 0;
5265
7c4a7ec8 5266err_fib_entry_update:
428b851f
IS
5267 mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common);
5268err_nexthop6_group_get:
5269 list_add_tail(&fib6_entry->common.nexthop_group_node,
5270 &old_nh_grp->fib_list);
5271 fib6_entry->common.nh_group = old_nh_grp;
5272 return err;
5273}
5274
5275static int
5276mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,
5277 struct mlxsw_sp_fib6_entry *fib6_entry,
d21afd30 5278 struct fib6_info **rt_arr, unsigned int nrt6)
428b851f
IS
5279{
5280 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
d21afd30 5281 int err, i;
428b851f 5282
d21afd30
IS
5283 for (i = 0; i < nrt6; i++) {
5284 mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt_arr[i]);
5285 if (IS_ERR(mlxsw_sp_rt6)) {
5286 err = PTR_ERR(mlxsw_sp_rt6);
5287 goto err_rt6_create;
5288 }
428b851f 5289
d21afd30
IS
5290 list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list);
5291 fib6_entry->nrt6++;
5292 }
428b851f
IS
5293
5294 err = mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
5295 if (err)
5296 goto err_nexthop6_group_update;
5297
5298 return 0;
5299
5300err_nexthop6_group_update:
d21afd30
IS
5301 i = nrt6;
5302err_rt6_create:
5303 for (i--; i >= 0; i--) {
5304 fib6_entry->nrt6--;
5305 mlxsw_sp_rt6 = list_last_entry(&fib6_entry->rt6_list,
5306 struct mlxsw_sp_rt6, list);
5307 list_del(&mlxsw_sp_rt6->list);
5308 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
5309 }
428b851f
IS
5310 return err;
5311}
5312
5313static void
5314mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,
5315 struct mlxsw_sp_fib6_entry *fib6_entry,
d21afd30 5316 struct fib6_info **rt_arr, unsigned int nrt6)
428b851f
IS
5317{
5318 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
d21afd30 5319 int i;
428b851f 5320
d21afd30
IS
5321 for (i = 0; i < nrt6; i++) {
5322 mlxsw_sp_rt6 = mlxsw_sp_fib6_entry_rt_find(fib6_entry,
5323 rt_arr[i]);
5324 if (WARN_ON_ONCE(!mlxsw_sp_rt6))
5325 continue;
5326
5327 fib6_entry->nrt6--;
5328 list_del(&mlxsw_sp_rt6->list);
5329 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
5330 }
428b851f 5331
428b851f 5332 mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
428b851f
IS
5333}
5334
f6050ee6
PM
5335static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
5336 struct mlxsw_sp_fib_entry *fib_entry,
8d1c802b 5337 const struct fib6_info *rt)
428b851f
IS
5338{
5339 /* Packets hitting RTF_REJECT routes need to be discarded by the
5340 * stack. We can rely on their destination device not having a
5341 * RIF (it's the loopback device) and can thus use action type
5342 * local, which will cause them to be trapped with a lower
5343 * priority than packets that need to be locally received.
5344 */
93c2fb25 5345 if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
428b851f 5346 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
2810c3b2
IS
5347 else if (rt->fib6_type == RTN_BLACKHOLE)
5348 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE;
93c2fb25 5349 else if (rt->fib6_flags & RTF_REJECT)
21151f64 5350 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE;
f6050ee6 5351 else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt))
428b851f
IS
5352 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE;
5353 else
5354 fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
5355}
5356
5357static void
5358mlxsw_sp_fib6_entry_rt_destroy_all(struct mlxsw_sp_fib6_entry *fib6_entry)
5359{
5360 struct mlxsw_sp_rt6 *mlxsw_sp_rt6, *tmp;
5361
5362 list_for_each_entry_safe(mlxsw_sp_rt6, tmp, &fib6_entry->rt6_list,
5363 list) {
5364 fib6_entry->nrt6--;
5365 list_del(&mlxsw_sp_rt6->list);
5366 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
5367 }
5368}
5369
5370static struct mlxsw_sp_fib6_entry *
5371mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
5372 struct mlxsw_sp_fib_node *fib_node,
2d9dd7ec 5373 struct fib6_info **rt_arr, unsigned int nrt6)
428b851f
IS
5374{
5375 struct mlxsw_sp_fib6_entry *fib6_entry;
5376 struct mlxsw_sp_fib_entry *fib_entry;
5377 struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
2d9dd7ec 5378 int err, i;
428b851f
IS
5379
5380 fib6_entry = kzalloc(sizeof(*fib6_entry), GFP_KERNEL);
5381 if (!fib6_entry)
5382 return ERR_PTR(-ENOMEM);
5383 fib_entry = &fib6_entry->common;
5384
2d9dd7ec
IS
5385 INIT_LIST_HEAD(&fib6_entry->rt6_list);
5386
5387 for (i = 0; i < nrt6; i++) {
5388 mlxsw_sp_rt6 = mlxsw_sp_rt6_create(rt_arr[i]);
5389 if (IS_ERR(mlxsw_sp_rt6)) {
5390 err = PTR_ERR(mlxsw_sp_rt6);
5391 goto err_rt6_create;
5392 }
5393 list_add_tail(&mlxsw_sp_rt6->list, &fib6_entry->rt6_list);
5394 fib6_entry->nrt6++;
428b851f
IS
5395 }
5396
2d9dd7ec 5397 mlxsw_sp_fib6_entry_type_set(mlxsw_sp, fib_entry, rt_arr[0]);
428b851f 5398
428b851f
IS
5399 err = mlxsw_sp_nexthop6_group_get(mlxsw_sp, fib6_entry);
5400 if (err)
5401 goto err_nexthop6_group_get;
5402
5403 fib_entry->fib_node = fib_node;
5404
5405 return fib6_entry;
5406
5407err_nexthop6_group_get:
2d9dd7ec 5408 i = nrt6;
428b851f 5409err_rt6_create:
2d9dd7ec
IS
5410 for (i--; i >= 0; i--) {
5411 fib6_entry->nrt6--;
5412 mlxsw_sp_rt6 = list_last_entry(&fib6_entry->rt6_list,
5413 struct mlxsw_sp_rt6, list);
5414 list_del(&mlxsw_sp_rt6->list);
5415 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
5416 }
428b851f
IS
5417 kfree(fib6_entry);
5418 return ERR_PTR(err);
5419}
5420
5421static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp *mlxsw_sp,
5422 struct mlxsw_sp_fib6_entry *fib6_entry)
5423{
5424 mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common);
5425 mlxsw_sp_fib6_entry_rt_destroy_all(fib6_entry);
5426 WARN_ON(fib6_entry->nrt6);
5427 kfree(fib6_entry);
5428}
5429
428b851f
IS
5430static struct mlxsw_sp_fib6_entry *
5431mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp,
8d1c802b 5432 const struct fib6_info *rt)
428b851f
IS
5433{
5434 struct mlxsw_sp_fib6_entry *fib6_entry;
5435 struct mlxsw_sp_fib_node *fib_node;
5436 struct mlxsw_sp_fib *fib;
7c4a7ec8 5437 struct fib6_info *cmp_rt;
428b851f
IS
5438 struct mlxsw_sp_vr *vr;
5439
93c2fb25 5440 vr = mlxsw_sp_vr_find(mlxsw_sp, rt->fib6_table->tb6_id);
428b851f
IS
5441 if (!vr)
5442 return NULL;
5443 fib = mlxsw_sp_vr_fib(vr, MLXSW_SP_L3_PROTO_IPV6);
5444
93c2fb25
DA
5445 fib_node = mlxsw_sp_fib_node_lookup(fib, &rt->fib6_dst.addr,
5446 sizeof(rt->fib6_dst.addr),
5447 rt->fib6_dst.plen);
428b851f
IS
5448 if (!fib_node)
5449 return NULL;
5450
7c4a7ec8
IS
5451 fib6_entry = container_of(fib_node->fib_entry,
5452 struct mlxsw_sp_fib6_entry, common);
5453 cmp_rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
5454 if (rt->fib6_table->tb6_id == cmp_rt->fib6_table->tb6_id &&
5455 rt->fib6_metric == cmp_rt->fib6_metric &&
5456 mlxsw_sp_fib6_entry_rt_find(fib6_entry, rt))
5457 return fib6_entry;
428b851f
IS
5458
5459 return NULL;
5460}
5461
0508ff89
IS
5462static bool mlxsw_sp_fib6_allow_replace(struct mlxsw_sp_fib6_entry *fib6_entry)
5463{
5464 struct mlxsw_sp_fib_node *fib_node = fib6_entry->common.fib_node;
5465 struct mlxsw_sp_fib6_entry *fib6_replaced;
5466 struct fib6_info *rt, *rt_replaced;
5467
5468 if (!fib_node->fib_entry)
5469 return true;
5470
5471 fib6_replaced = container_of(fib_node->fib_entry,
5472 struct mlxsw_sp_fib6_entry,
5473 common);
5474 rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
5475 rt_replaced = mlxsw_sp_fib6_entry_rt(fib6_replaced);
5476 if (rt->fib6_table->tb6_id == RT_TABLE_MAIN &&
5477 rt_replaced->fib6_table->tb6_id == RT_TABLE_LOCAL)
5478 return false;
5479
5480 return true;
5481}
5482
dacad7b3
IS
5483static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
5484 struct fib6_info **rt_arr,
5485 unsigned int nrt6)
428b851f 5486{
7c4a7ec8
IS
5487 struct mlxsw_sp_fib6_entry *fib6_entry, *fib6_replaced;
5488 struct mlxsw_sp_fib_entry *replaced;
428b851f 5489 struct mlxsw_sp_fib_node *fib_node;
921bc539 5490 struct fib6_info *rt = rt_arr[0];
428b851f
IS
5491 int err;
5492
5493 if (mlxsw_sp->router->aborted)
5494 return 0;
5495
93c2fb25 5496 if (rt->fib6_src.plen)
f36f5ac6
IS
5497 return -EINVAL;
5498
428b851f
IS
5499 if (mlxsw_sp_fib6_rt_should_ignore(rt))
5500 return 0;
5501
93c2fb25
DA
5502 fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, rt->fib6_table->tb6_id,
5503 &rt->fib6_dst.addr,
5504 sizeof(rt->fib6_dst.addr),
5505 rt->fib6_dst.plen,
428b851f
IS
5506 MLXSW_SP_L3_PROTO_IPV6);
5507 if (IS_ERR(fib_node))
5508 return PTR_ERR(fib_node);
5509
2d9dd7ec
IS
5510 fib6_entry = mlxsw_sp_fib6_entry_create(mlxsw_sp, fib_node, rt_arr,
5511 nrt6);
428b851f
IS
5512 if (IS_ERR(fib6_entry)) {
5513 err = PTR_ERR(fib6_entry);
5514 goto err_fib6_entry_create;
5515 }
5516
0508ff89
IS
5517 if (!mlxsw_sp_fib6_allow_replace(fib6_entry)) {
5518 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
5519 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
5520 return 0;
5521 }
5522
7c4a7ec8 5523 replaced = fib_node->fib_entry;
b04720ae 5524 err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib6_entry->common);
428b851f 5525 if (err)
b04720ae 5526 goto err_fib_node_entry_link;
428b851f 5527
7c4a7ec8
IS
5528 /* Nothing to replace */
5529 if (!replaced)
5530 return 0;
5531
ee5a0448 5532 mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, replaced);
7c4a7ec8
IS
5533 fib6_replaced = container_of(replaced, struct mlxsw_sp_fib6_entry,
5534 common);
5535 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_replaced);
0a7fd1ac 5536
428b851f
IS
5537 return 0;
5538
b04720ae 5539err_fib_node_entry_link:
7c4a7ec8 5540 fib_node->fib_entry = replaced;
428b851f
IS
5541 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
5542err_fib6_entry_create:
dacad7b3
IS
5543 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
5544 return err;
5545}
5546
5547static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp,
5548 struct fib6_info **rt_arr,
5549 unsigned int nrt6)
5550{
5551 struct mlxsw_sp_fib6_entry *fib6_entry;
5552 struct mlxsw_sp_fib_node *fib_node;
5553 struct fib6_info *rt = rt_arr[0];
5554 int err;
5555
5556 if (mlxsw_sp->router->aborted)
5557 return 0;
5558
5559 if (rt->fib6_src.plen)
5560 return -EINVAL;
5561
5562 if (mlxsw_sp_fib6_rt_should_ignore(rt))
5563 return 0;
5564
5565 fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, rt->fib6_table->tb6_id,
5566 &rt->fib6_dst.addr,
5567 sizeof(rt->fib6_dst.addr),
5568 rt->fib6_dst.plen,
5569 MLXSW_SP_L3_PROTO_IPV6);
5570 if (IS_ERR(fib_node))
5571 return PTR_ERR(fib_node);
5572
7c4a7ec8 5573 if (WARN_ON_ONCE(!fib_node->fib_entry)) {
dacad7b3
IS
5574 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
5575 return -EINVAL;
5576 }
5577
7c4a7ec8
IS
5578 fib6_entry = container_of(fib_node->fib_entry,
5579 struct mlxsw_sp_fib6_entry, common);
dacad7b3
IS
5580 err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt_arr,
5581 nrt6);
5582 if (err)
5583 goto err_fib6_entry_nexthop_add;
5584
5585 return 0;
5586
428b851f
IS
5587err_fib6_entry_nexthop_add:
5588 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
5589 return err;
5590}
5591
5592static void mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
921bc539
IS
5593 struct fib6_info **rt_arr,
5594 unsigned int nrt6)
428b851f
IS
5595{
5596 struct mlxsw_sp_fib6_entry *fib6_entry;
5597 struct mlxsw_sp_fib_node *fib_node;
921bc539 5598 struct fib6_info *rt = rt_arr[0];
428b851f
IS
5599
5600 if (mlxsw_sp->router->aborted)
5601 return;
5602
5603 if (mlxsw_sp_fib6_rt_should_ignore(rt))
5604 return;
5605
62201c00
IS
5606 /* Multipath routes are first added to the FIB trie and only then
5607 * notified. If we vetoed the addition, we will get a delete
5608 * notification for a route we do not have. Therefore, do not warn if
5609 * route was not found.
5610 */
428b851f 5611 fib6_entry = mlxsw_sp_fib6_entry_lookup(mlxsw_sp, rt);
62201c00 5612 if (!fib6_entry)
428b851f
IS
5613 return;
5614
d21afd30
IS
5615 /* If not all the nexthops are deleted, then only reduce the nexthop
5616 * group.
428b851f 5617 */
d21afd30
IS
5618 if (nrt6 != fib6_entry->nrt6) {
5619 mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp, fib6_entry, rt_arr,
5620 nrt6);
428b851f
IS
5621 return;
5622 }
5623
5624 fib_node = fib6_entry->common.fib_node;
5625
b04720ae 5626 mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib6_entry->common);
428b851f
IS
5627 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
5628 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
5629}
5630
bc65a8a4
IS
5631static int __mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp,
5632 enum mlxsw_reg_ralxx_protocol proto,
5633 u8 tree_id)
b45f64d1
JP
5634{
5635 char ralta_pl[MLXSW_REG_RALTA_LEN];
5636 char ralst_pl[MLXSW_REG_RALST_LEN];
b5d90e6d 5637 int i, err;
b45f64d1 5638
bc65a8a4 5639 mlxsw_reg_ralta_pack(ralta_pl, true, proto, tree_id);
b45f64d1
JP
5640 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
5641 if (err)
5642 return err;
5643
bc65a8a4 5644 mlxsw_reg_ralst_pack(ralst_pl, 0xff, tree_id);
b45f64d1
JP
5645 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl);
5646 if (err)
5647 return err;
5648
b5d90e6d 5649 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
9011b677 5650 struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
b5d90e6d
IS
5651 char raltb_pl[MLXSW_REG_RALTB_LEN];
5652 char ralue_pl[MLXSW_REG_RALUE_LEN];
b45f64d1 5653
bc65a8a4 5654 mlxsw_reg_raltb_pack(raltb_pl, vr->id, proto, tree_id);
b5d90e6d
IS
5655 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb),
5656 raltb_pl);
5657 if (err)
5658 return err;
5659
bc65a8a4
IS
5660 mlxsw_reg_ralue_pack(ralue_pl, proto,
5661 MLXSW_REG_RALUE_OP_WRITE_WRITE, vr->id, 0);
b5d90e6d
IS
5662 mlxsw_reg_ralue_act_ip2me_pack(ralue_pl);
5663 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue),
5664 ralue_pl);
5665 if (err)
5666 return err;
5667 }
5668
5669 return 0;
b45f64d1
JP
5670}
5671
eb35da0c
YM
5672static struct mlxsw_sp_mr_table *
5673mlxsw_sp_router_fibmr_family_to_table(struct mlxsw_sp_vr *vr, int family)
5674{
64ed1b9e 5675 if (family == RTNL_FAMILY_IPMR)
eb35da0c 5676 return vr->mr_table[MLXSW_SP_L3_PROTO_IPV4];
64ed1b9e
YM
5677 else
5678 return vr->mr_table[MLXSW_SP_L3_PROTO_IPV6];
eb35da0c
YM
5679}
5680
d42b0965
YG
5681static int mlxsw_sp_router_fibmr_add(struct mlxsw_sp *mlxsw_sp,
5682 struct mfc_entry_notifier_info *men_info,
5683 bool replace)
5684{
eb35da0c 5685 struct mlxsw_sp_mr_table *mrt;
d42b0965
YG
5686 struct mlxsw_sp_vr *vr;
5687
5688 if (mlxsw_sp->router->aborted)
5689 return 0;
5690
f8fa9b4e 5691 vr = mlxsw_sp_vr_get(mlxsw_sp, men_info->tb_id, NULL);
d42b0965
YG
5692 if (IS_ERR(vr))
5693 return PTR_ERR(vr);
5694
eb35da0c
YM
5695 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, men_info->info.family);
5696 return mlxsw_sp_mr_route_add(mrt, men_info->mfc, replace);
d42b0965
YG
5697}
5698
5699static void mlxsw_sp_router_fibmr_del(struct mlxsw_sp *mlxsw_sp,
5700 struct mfc_entry_notifier_info *men_info)
5701{
eb35da0c 5702 struct mlxsw_sp_mr_table *mrt;
d42b0965
YG
5703 struct mlxsw_sp_vr *vr;
5704
5705 if (mlxsw_sp->router->aborted)
5706 return;
5707
5708 vr = mlxsw_sp_vr_find(mlxsw_sp, men_info->tb_id);
5709 if (WARN_ON(!vr))
5710 return;
5711
eb35da0c
YM
5712 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, men_info->info.family);
5713 mlxsw_sp_mr_route_del(mrt, men_info->mfc);
2b52ce02 5714 mlxsw_sp_vr_put(mlxsw_sp, vr);
d42b0965
YG
5715}
5716
5717static int
5718mlxsw_sp_router_fibmr_vif_add(struct mlxsw_sp *mlxsw_sp,
5719 struct vif_entry_notifier_info *ven_info)
5720{
eb35da0c 5721 struct mlxsw_sp_mr_table *mrt;
d42b0965
YG
5722 struct mlxsw_sp_rif *rif;
5723 struct mlxsw_sp_vr *vr;
5724
5725 if (mlxsw_sp->router->aborted)
5726 return 0;
5727
f8fa9b4e 5728 vr = mlxsw_sp_vr_get(mlxsw_sp, ven_info->tb_id, NULL);
d42b0965
YG
5729 if (IS_ERR(vr))
5730 return PTR_ERR(vr);
5731
eb35da0c 5732 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, ven_info->info.family);
d42b0965 5733 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, ven_info->dev);
eb35da0c 5734 return mlxsw_sp_mr_vif_add(mrt, ven_info->dev,
d42b0965
YG
5735 ven_info->vif_index,
5736 ven_info->vif_flags, rif);
5737}
5738
5739static void
5740mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp *mlxsw_sp,
5741 struct vif_entry_notifier_info *ven_info)
5742{
eb35da0c 5743 struct mlxsw_sp_mr_table *mrt;
d42b0965
YG
5744 struct mlxsw_sp_vr *vr;
5745
5746 if (mlxsw_sp->router->aborted)
5747 return;
5748
5749 vr = mlxsw_sp_vr_find(mlxsw_sp, ven_info->tb_id);
5750 if (WARN_ON(!vr))
5751 return;
5752
eb35da0c
YM
5753 mrt = mlxsw_sp_router_fibmr_family_to_table(vr, ven_info->info.family);
5754 mlxsw_sp_mr_vif_del(mrt, ven_info->vif_index);
2b52ce02 5755 mlxsw_sp_vr_put(mlxsw_sp, vr);
d42b0965
YG
5756}
5757
bc65a8a4
IS
5758static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
5759{
5760 enum mlxsw_reg_ralxx_protocol proto = MLXSW_REG_RALXX_PROTOCOL_IPV4;
5761 int err;
5762
5763 err = __mlxsw_sp_router_set_abort_trap(mlxsw_sp, proto,
5764 MLXSW_SP_LPM_TREE_MIN);
5765 if (err)
5766 return err;
5767
d42b0965
YG
5768 /* The multicast router code does not need an abort trap as by default,
5769 * packets that don't match any routes are trapped to the CPU.
5770 */
5771
bc65a8a4
IS
5772 proto = MLXSW_REG_RALXX_PROTOCOL_IPV6;
5773 return __mlxsw_sp_router_set_abort_trap(mlxsw_sp, proto,
5774 MLXSW_SP_LPM_TREE_MIN + 1);
5775}
5776
9aecce1c
IS
5777static void mlxsw_sp_fib4_node_flush(struct mlxsw_sp *mlxsw_sp,
5778 struct mlxsw_sp_fib_node *fib_node)
5779{
7c4a7ec8 5780 struct mlxsw_sp_fib4_entry *fib4_entry;
9aecce1c 5781
7c4a7ec8
IS
5782 fib4_entry = container_of(fib_node->fib_entry,
5783 struct mlxsw_sp_fib4_entry, common);
5784 mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, fib_node->fib_entry);
5785 mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
5786 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
9aecce1c
IS
5787}
5788
428b851f
IS
5789static void mlxsw_sp_fib6_node_flush(struct mlxsw_sp *mlxsw_sp,
5790 struct mlxsw_sp_fib_node *fib_node)
5791{
7c4a7ec8 5792 struct mlxsw_sp_fib6_entry *fib6_entry;
428b851f 5793
7c4a7ec8
IS
5794 fib6_entry = container_of(fib_node->fib_entry,
5795 struct mlxsw_sp_fib6_entry, common);
5796 mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, fib_node->fib_entry);
5797 mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
5798 mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
428b851f
IS
5799}
5800
9aecce1c
IS
5801static void mlxsw_sp_fib_node_flush(struct mlxsw_sp *mlxsw_sp,
5802 struct mlxsw_sp_fib_node *fib_node)
5803{
76610ebb 5804 switch (fib_node->fib->proto) {
9aecce1c
IS
5805 case MLXSW_SP_L3_PROTO_IPV4:
5806 mlxsw_sp_fib4_node_flush(mlxsw_sp, fib_node);
5807 break;
5808 case MLXSW_SP_L3_PROTO_IPV6:
428b851f 5809 mlxsw_sp_fib6_node_flush(mlxsw_sp, fib_node);
9aecce1c
IS
5810 break;
5811 }
5812}
5813
76610ebb
IS
5814static void mlxsw_sp_vr_fib_flush(struct mlxsw_sp *mlxsw_sp,
5815 struct mlxsw_sp_vr *vr,
5816 enum mlxsw_sp_l3proto proto)
b45f64d1 5817{
76610ebb 5818 struct mlxsw_sp_fib *fib = mlxsw_sp_vr_fib(vr, proto);
9aecce1c 5819 struct mlxsw_sp_fib_node *fib_node, *tmp;
76610ebb
IS
5820
5821 list_for_each_entry_safe(fib_node, tmp, &fib->node_list, list) {
5822 bool do_break = &tmp->list == &fib->node_list;
5823
5824 mlxsw_sp_fib_node_flush(mlxsw_sp, fib_node);
5825 if (do_break)
5826 break;
5827 }
5828}
5829
5830static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp)
5831{
9742f866 5832 int i, j;
b45f64d1 5833
c1a38311 5834 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
9011b677 5835 struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
ac571de9 5836
76610ebb 5837 if (!mlxsw_sp_vr_is_used(vr))
b45f64d1 5838 continue;
d42b0965 5839
9742f866
YM
5840 for (j = 0; j < MLXSW_SP_L3_PROTO_MAX; j++)
5841 mlxsw_sp_mr_table_flush(vr->mr_table[j]);
76610ebb 5842 mlxsw_sp_vr_fib_flush(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
a3d9bc50
IS
5843
5844 /* If virtual router was only used for IPv4, then it's no
5845 * longer used.
5846 */
5847 if (!mlxsw_sp_vr_is_used(vr))
5848 continue;
5849 mlxsw_sp_vr_fib_flush(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
b45f64d1 5850 }
983db619
IS
5851
5852 /* After flushing all the routes, it is not possible anyone is still
5853 * using the adjacency index that is discarding packets, so free it in
5854 * case it was allocated.
5855 */
5856 if (!mlxsw_sp->router->adj_discard_index_valid)
5857 return;
5858 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
5859 mlxsw_sp->router->adj_discard_index);
5860 mlxsw_sp->router->adj_discard_index_valid = false;
ac571de9
IS
5861}
5862
bc65a8a4 5863static void mlxsw_sp_router_fib_abort(struct mlxsw_sp *mlxsw_sp)
ac571de9
IS
5864{
5865 int err;
5866
9011b677 5867 if (mlxsw_sp->router->aborted)
d331d303
IS
5868 return;
5869 dev_warn(mlxsw_sp->bus_info->dev, "FIB abort triggered. Note that FIB entries are no longer being offloaded to this device.\n");
ac571de9 5870 mlxsw_sp_router_fib_flush(mlxsw_sp);
9011b677 5871 mlxsw_sp->router->aborted = true;
b45f64d1
JP
5872 err = mlxsw_sp_router_set_abort_trap(mlxsw_sp);
5873 if (err)
5874 dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
5875}
5876
928c0b53
IS
5877struct mlxsw_sp_fib6_event_work {
5878 struct fib6_info **rt_arr;
5879 unsigned int nrt6;
5880};
5881
3057224e 5882struct mlxsw_sp_fib_event_work {
a0e4761d 5883 struct work_struct work;
ad178c8e 5884 union {
928c0b53 5885 struct mlxsw_sp_fib6_event_work fib6_work;
ad178c8e 5886 struct fib_entry_notifier_info fen_info;
5d7bfd14 5887 struct fib_rule_notifier_info fr_info;
ad178c8e 5888 struct fib_nh_notifier_info fnh_info;
d42b0965
YG
5889 struct mfc_entry_notifier_info men_info;
5890 struct vif_entry_notifier_info ven_info;
ad178c8e 5891 };
3057224e
IS
5892 struct mlxsw_sp *mlxsw_sp;
5893 unsigned long event;
5894};
5895
928c0b53
IS
5896static int
5897mlxsw_sp_router_fib6_work_init(struct mlxsw_sp_fib6_event_work *fib6_work,
5898 struct fib6_entry_notifier_info *fen6_info)
5899{
5900 struct fib6_info *rt = fen6_info->rt;
5901 struct fib6_info **rt_arr;
5902 struct fib6_info *iter;
5903 unsigned int nrt6;
5904 int i = 0;
5905
5906 nrt6 = fen6_info->nsiblings + 1;
5907
5908 rt_arr = kcalloc(nrt6, sizeof(struct fib6_info *), GFP_ATOMIC);
5909 if (!rt_arr)
5910 return -ENOMEM;
5911
5912 fib6_work->rt_arr = rt_arr;
5913 fib6_work->nrt6 = nrt6;
5914
5915 rt_arr[0] = rt;
5916 fib6_info_hold(rt);
5917
5918 if (!fen6_info->nsiblings)
5919 return 0;
5920
5921 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
5922 if (i == fen6_info->nsiblings)
5923 break;
5924
5925 rt_arr[i + 1] = iter;
5926 fib6_info_hold(iter);
5927 i++;
5928 }
5929 WARN_ON_ONCE(i != fen6_info->nsiblings);
5930
5931 return 0;
5932}
5933
5934static void
5935mlxsw_sp_router_fib6_work_fini(struct mlxsw_sp_fib6_event_work *fib6_work)
5936{
5937 int i;
5938
5939 for (i = 0; i < fib6_work->nrt6; i++)
5940 mlxsw_sp_rt6_release(fib6_work->rt_arr[i]);
5941 kfree(fib6_work->rt_arr);
5942}
5943
66a5763a 5944static void mlxsw_sp_router_fib4_event_work(struct work_struct *work)
b45f64d1 5945{
3057224e 5946 struct mlxsw_sp_fib_event_work *fib_work =
a0e4761d 5947 container_of(work, struct mlxsw_sp_fib_event_work, work);
3057224e 5948 struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
b45f64d1
JP
5949 int err;
5950
3057224e
IS
5951 /* Protect internal structures from changes */
5952 rtnl_lock();
803335ac
PM
5953 mlxsw_sp_span_respin(mlxsw_sp);
5954
3057224e 5955 switch (fib_work->event) {
446f7391 5956 case FIB_EVENT_ENTRY_REPLACE:
b6a1d871
IS
5957 err = mlxsw_sp_router_fib4_replace(mlxsw_sp,
5958 &fib_work->fen_info);
b45f64d1 5959 if (err)
bc65a8a4 5960 mlxsw_sp_router_fib_abort(mlxsw_sp);
3057224e 5961 fib_info_put(fib_work->fen_info.fi);
b45f64d1 5962 break;
446f7391 5963 case FIB_EVENT_ENTRY_DEL:
3057224e
IS
5964 mlxsw_sp_router_fib4_del(mlxsw_sp, &fib_work->fen_info);
5965 fib_info_put(fib_work->fen_info.fi);
b45f64d1 5966 break;
ad178c8e
IS
5967 case FIB_EVENT_NH_ADD: /* fall through */
5968 case FIB_EVENT_NH_DEL:
0e6ea2a4
IS
5969 mlxsw_sp_nexthop4_event(mlxsw_sp, fib_work->event,
5970 fib_work->fnh_info.fib_nh);
ad178c8e
IS
5971 fib_info_put(fib_work->fnh_info.fib_nh->nh_parent);
5972 break;
b45f64d1 5973 }
3057224e
IS
5974 rtnl_unlock();
5975 kfree(fib_work);
5976}
5977
66a5763a
IS
5978static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
5979{
583419fd
IS
5980 struct mlxsw_sp_fib_event_work *fib_work =
5981 container_of(work, struct mlxsw_sp_fib_event_work, work);
5982 struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
428b851f 5983 int err;
583419fd
IS
5984
5985 rtnl_lock();
803335ac
PM
5986 mlxsw_sp_span_respin(mlxsw_sp);
5987
583419fd 5988 switch (fib_work->event) {
caafb250 5989 case FIB_EVENT_ENTRY_REPLACE:
dacad7b3
IS
5990 err = mlxsw_sp_router_fib6_replace(mlxsw_sp,
5991 fib_work->fib6_work.rt_arr,
5992 fib_work->fib6_work.nrt6);
428b851f
IS
5993 if (err)
5994 mlxsw_sp_router_fib_abort(mlxsw_sp);
928c0b53 5995 mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work);
428b851f 5996 break;
dacad7b3
IS
5997 case FIB_EVENT_ENTRY_APPEND:
5998 err = mlxsw_sp_router_fib6_append(mlxsw_sp,
5999 fib_work->fib6_work.rt_arr,
6000 fib_work->fib6_work.nrt6);
6001 if (err)
6002 mlxsw_sp_router_fib_abort(mlxsw_sp);
6003 mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work);
6004 break;
caafb250 6005 case FIB_EVENT_ENTRY_DEL:
928c0b53 6006 mlxsw_sp_router_fib6_del(mlxsw_sp,
921bc539
IS
6007 fib_work->fib6_work.rt_arr,
6008 fib_work->fib6_work.nrt6);
928c0b53 6009 mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work);
428b851f 6010 break;
583419fd
IS
6011 }
6012 rtnl_unlock();
6013 kfree(fib_work);
66a5763a
IS
6014}
6015
d42b0965
YG
6016static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work)
6017{
6018 struct mlxsw_sp_fib_event_work *fib_work =
6019 container_of(work, struct mlxsw_sp_fib_event_work, work);
6020 struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
d42b0965
YG
6021 bool replace;
6022 int err;
6023
6024 rtnl_lock();
6025 switch (fib_work->event) {
6026 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
6027 case FIB_EVENT_ENTRY_ADD:
6028 replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
6029
6030 err = mlxsw_sp_router_fibmr_add(mlxsw_sp, &fib_work->men_info,
6031 replace);
6032 if (err)
6033 mlxsw_sp_router_fib_abort(mlxsw_sp);
8c13af2a 6034 mr_cache_put(fib_work->men_info.mfc);
d42b0965
YG
6035 break;
6036 case FIB_EVENT_ENTRY_DEL:
6037 mlxsw_sp_router_fibmr_del(mlxsw_sp, &fib_work->men_info);
8c13af2a 6038 mr_cache_put(fib_work->men_info.mfc);
d42b0965
YG
6039 break;
6040 case FIB_EVENT_VIF_ADD:
6041 err = mlxsw_sp_router_fibmr_vif_add(mlxsw_sp,
6042 &fib_work->ven_info);
6043 if (err)
6044 mlxsw_sp_router_fib_abort(mlxsw_sp);
6045 dev_put(fib_work->ven_info.dev);
6046 break;
6047 case FIB_EVENT_VIF_DEL:
6048 mlxsw_sp_router_fibmr_vif_del(mlxsw_sp,
6049 &fib_work->ven_info);
6050 dev_put(fib_work->ven_info.dev);
6051 break;
d42b0965
YG
6052 }
6053 rtnl_unlock();
6054 kfree(fib_work);
6055}
6056
66a5763a
IS
6057static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work *fib_work,
6058 struct fib_notifier_info *info)
6059{
3c75f9b1 6060 struct fib_entry_notifier_info *fen_info;
3c75f9b1
DA
6061 struct fib_nh_notifier_info *fnh_info;
6062
66a5763a 6063 switch (fib_work->event) {
446f7391
IS
6064 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
6065 case FIB_EVENT_ENTRY_DEL:
3c75f9b1
DA
6066 fen_info = container_of(info, struct fib_entry_notifier_info,
6067 info);
6068 fib_work->fen_info = *fen_info;
6069 /* Take reference on fib_info to prevent it from being
66a5763a
IS
6070 * freed while work is queued. Release it afterwards.
6071 */
6072 fib_info_hold(fib_work->fen_info.fi);
6073 break;
66a5763a
IS
6074 case FIB_EVENT_NH_ADD: /* fall through */
6075 case FIB_EVENT_NH_DEL:
3c75f9b1
DA
6076 fnh_info = container_of(info, struct fib_nh_notifier_info,
6077 info);
6078 fib_work->fnh_info = *fnh_info;
66a5763a
IS
6079 fib_info_hold(fib_work->fnh_info.fib_nh->nh_parent);
6080 break;
6081 }
6082}
6083
ccd56a5f
IS
6084static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work,
6085 struct fib_notifier_info *info)
66a5763a 6086{
3c75f9b1 6087 struct fib6_entry_notifier_info *fen6_info;
928c0b53 6088 int err;
3c75f9b1 6089
583419fd 6090 switch (fib_work->event) {
caafb250 6091 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
dacad7b3 6092 case FIB_EVENT_ENTRY_APPEND: /* fall through */
caafb250 6093 case FIB_EVENT_ENTRY_DEL:
3c75f9b1
DA
6094 fen6_info = container_of(info, struct fib6_entry_notifier_info,
6095 info);
928c0b53
IS
6096 err = mlxsw_sp_router_fib6_work_init(&fib_work->fib6_work,
6097 fen6_info);
6098 if (err)
6099 return err;
428b851f 6100 break;
583419fd 6101 }
ccd56a5f
IS
6102
6103 return 0;
66a5763a
IS
6104}
6105
d42b0965
YG
6106static void
6107mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event_work *fib_work,
6108 struct fib_notifier_info *info)
6109{
6110 switch (fib_work->event) {
6111 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
6112 case FIB_EVENT_ENTRY_ADD: /* fall through */
6113 case FIB_EVENT_ENTRY_DEL:
6114 memcpy(&fib_work->men_info, info, sizeof(fib_work->men_info));
8c13af2a 6115 mr_cache_hold(fib_work->men_info.mfc);
d42b0965
YG
6116 break;
6117 case FIB_EVENT_VIF_ADD: /* fall through */
6118 case FIB_EVENT_VIF_DEL:
6119 memcpy(&fib_work->ven_info, info, sizeof(fib_work->ven_info));
6120 dev_hold(fib_work->ven_info.dev);
6121 break;
1f279233
DA
6122 }
6123}
6124
6125static int mlxsw_sp_router_fib_rule_event(unsigned long event,
6126 struct fib_notifier_info *info,
6127 struct mlxsw_sp *mlxsw_sp)
6128{
6129 struct netlink_ext_ack *extack = info->extack;
6130 struct fib_rule_notifier_info *fr_info;
6131 struct fib_rule *rule;
6132 int err = 0;
6133
6134 /* nothing to do at the moment */
6135 if (event == FIB_EVENT_RULE_DEL)
6136 return 0;
6137
6138 if (mlxsw_sp->router->aborted)
6139 return 0;
6140
6141 fr_info = container_of(info, struct fib_rule_notifier_info, info);
6142 rule = fr_info->rule;
6143
05414dd1 6144 /* Rule only affects locally generated traffic */
053e92aa 6145 if (rule->iifindex == mlxsw_sp_net(mlxsw_sp)->loopback_dev->ifindex)
05414dd1
IS
6146 return 0;
6147
1f279233
DA
6148 switch (info->family) {
6149 case AF_INET:
6150 if (!fib4_rule_default(rule) && !rule->l3mdev)
6290182b 6151 err = -EOPNOTSUPP;
1f279233
DA
6152 break;
6153 case AF_INET6:
6154 if (!fib6_rule_default(rule) && !rule->l3mdev)
6290182b 6155 err = -EOPNOTSUPP;
1f279233
DA
6156 break;
6157 case RTNL_FAMILY_IPMR:
6158 if (!ipmr_rule_default(rule) && !rule->l3mdev)
6290182b 6159 err = -EOPNOTSUPP;
d42b0965 6160 break;
64ed1b9e
YM
6161 case RTNL_FAMILY_IP6MR:
6162 if (!ip6mr_rule_default(rule) && !rule->l3mdev)
6290182b 6163 err = -EOPNOTSUPP;
64ed1b9e 6164 break;
d42b0965 6165 }
1f279233
DA
6166
6167 if (err < 0)
6290182b 6168 NL_SET_ERR_MSG_MOD(extack, "FIB rules not supported");
1f279233
DA
6169
6170 return err;
d42b0965
YG
6171}
6172
3057224e
IS
6173/* Called with rcu_read_lock() */
6174static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
6175 unsigned long event, void *ptr)
6176{
3057224e
IS
6177 struct mlxsw_sp_fib_event_work *fib_work;
6178 struct fib_notifier_info *info = ptr;
7e39d115 6179 struct mlxsw_sp_router *router;
1f279233 6180 int err;
3057224e 6181
7c550daf 6182 if ((info->family != AF_INET && info->family != AF_INET6 &&
64ed1b9e
YM
6183 info->family != RTNL_FAMILY_IPMR &&
6184 info->family != RTNL_FAMILY_IP6MR))
3057224e
IS
6185 return NOTIFY_DONE;
6186
1f279233
DA
6187 router = container_of(nb, struct mlxsw_sp_router, fib_nb);
6188
6189 switch (event) {
6190 case FIB_EVENT_RULE_ADD: /* fall through */
6191 case FIB_EVENT_RULE_DEL:
6192 err = mlxsw_sp_router_fib_rule_event(event, info,
6193 router->mlxsw_sp);
3f9e5c11 6194 return notifier_from_errno(err);
b6a1d871 6195 case FIB_EVENT_ENTRY_ADD: /* fall through */
dacad7b3 6196 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
dacad7b3 6197 case FIB_EVENT_ENTRY_APPEND:
50d10711
IS
6198 if (router->aborted) {
6199 NL_SET_ERR_MSG_MOD(info->extack, "FIB offload was aborted. Not configuring route");
6200 return notifier_from_errno(-EINVAL);
6201 }
19a9d136
DA
6202 if (info->family == AF_INET) {
6203 struct fib_entry_notifier_info *fen_info = ptr;
6204
6205 if (fen_info->fi->fib_nh_is_v6) {
6206 NL_SET_ERR_MSG_MOD(info->extack, "IPv6 gateway with IPv4 route is not supported");
6207 return notifier_from_errno(-EINVAL);
6208 }
54250805
DA
6209 if (fen_info->fi->nh) {
6210 NL_SET_ERR_MSG_MOD(info->extack, "IPv4 route with nexthop objects is not supported");
6211 return notifier_from_errno(-EINVAL);
6212 }
6213 } else if (info->family == AF_INET6) {
6214 struct fib6_entry_notifier_info *fen6_info;
6215
6216 fen6_info = container_of(info,
6217 struct fib6_entry_notifier_info,
6218 info);
6219 if (fen6_info->rt->nh) {
6220 NL_SET_ERR_MSG_MOD(info->extack, "IPv6 route with nexthop objects is not supported");
6221 return notifier_from_errno(-EINVAL);
6222 }
19a9d136 6223 }
50d10711 6224 break;
1f279233
DA
6225 }
6226
3057224e
IS
6227 fib_work = kzalloc(sizeof(*fib_work), GFP_ATOMIC);
6228 if (WARN_ON(!fib_work))
6229 return NOTIFY_BAD;
6230
7e39d115 6231 fib_work->mlxsw_sp = router->mlxsw_sp;
3057224e
IS
6232 fib_work->event = event;
6233
66a5763a
IS
6234 switch (info->family) {
6235 case AF_INET:
6236 INIT_WORK(&fib_work->work, mlxsw_sp_router_fib4_event_work);
6237 mlxsw_sp_router_fib4_event(fib_work, info);
3057224e 6238 break;
66a5763a
IS
6239 case AF_INET6:
6240 INIT_WORK(&fib_work->work, mlxsw_sp_router_fib6_event_work);
ccd56a5f
IS
6241 err = mlxsw_sp_router_fib6_event(fib_work, info);
6242 if (err)
6243 goto err_fib_event;
ad178c8e 6244 break;
64ed1b9e 6245 case RTNL_FAMILY_IP6MR:
d42b0965
YG
6246 case RTNL_FAMILY_IPMR:
6247 INIT_WORK(&fib_work->work, mlxsw_sp_router_fibmr_event_work);
6248 mlxsw_sp_router_fibmr_event(fib_work, info);
6249 break;
3057224e
IS
6250 }
6251
a0e4761d 6252 mlxsw_core_schedule_work(&fib_work->work);
3057224e 6253
b45f64d1 6254 return NOTIFY_DONE;
ccd56a5f
IS
6255
6256err_fib_event:
6257 kfree(fib_work);
6258 return NOTIFY_BAD;
b45f64d1
JP
6259}
6260
b69e1337 6261static struct mlxsw_sp_rif *
4724ba56
IS
6262mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
6263 const struct net_device *dev)
6264{
6265 int i;
6266
6267 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
5f9efffb
IS
6268 if (mlxsw_sp->router->rifs[i] &&
6269 mlxsw_sp->router->rifs[i]->dev == dev)
6270 return mlxsw_sp->router->rifs[i];
4724ba56
IS
6271
6272 return NULL;
6273}
6274
b69e1337
IS
6275bool mlxsw_sp_rif_exists(struct mlxsw_sp *mlxsw_sp,
6276 const struct net_device *dev)
6277{
6278 return !!mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6279}
6280
5e9a664d
IS
6281u16 mlxsw_sp_rif_vid(struct mlxsw_sp *mlxsw_sp, const struct net_device *dev)
6282{
6283 struct mlxsw_sp_rif *rif;
6284 u16 vid = 0;
6285
6286 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6287 if (!rif)
6288 goto out;
6289
6290 /* We only return the VID for VLAN RIFs. Otherwise we return an
6291 * invalid value (0).
6292 */
6293 if (rif->ops->type != MLXSW_SP_RIF_TYPE_VLAN)
6294 goto out;
6295
6296 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
6297
6298out:
6299 return vid;
6300}
6301
4724ba56
IS
6302static int mlxsw_sp_router_rif_disable(struct mlxsw_sp *mlxsw_sp, u16 rif)
6303{
6304 char ritr_pl[MLXSW_REG_RITR_LEN];
6305 int err;
6306
6307 mlxsw_reg_ritr_rif_pack(ritr_pl, rif);
6308 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
24f91ce0 6309 if (err)
4724ba56
IS
6310 return err;
6311
6312 mlxsw_reg_ritr_enable_set(ritr_pl, false);
6313 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
6314}
6315
6316static void mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
bf95233e 6317 struct mlxsw_sp_rif *rif)
4724ba56 6318{
bf95233e
AS
6319 mlxsw_sp_router_rif_disable(mlxsw_sp, rif->rif_index);
6320 mlxsw_sp_nexthop_rif_gone_sync(mlxsw_sp, rif);
6321 mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif);
4724ba56
IS
6322}
6323
5ea1237f
AS
6324static bool
6325mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *rif, struct net_device *dev,
6326 unsigned long event)
4724ba56 6327{
5ea1237f
AS
6328 struct inet6_dev *inet6_dev;
6329 bool addr_list_empty = true;
6330 struct in_device *idev;
6331
4724ba56
IS
6332 switch (event) {
6333 case NETDEV_UP:
f1b1f273 6334 return rif == NULL;
4724ba56 6335 case NETDEV_DOWN:
23d154c0
IS
6336 rcu_read_lock();
6337 idev = __in_dev_get_rcu(dev);
5ea1237f
AS
6338 if (idev && idev->ifa_list)
6339 addr_list_empty = false;
6340
6341 inet6_dev = __in6_dev_get(dev);
6342 if (addr_list_empty && inet6_dev &&
6343 !list_empty(&inet6_dev->addr_list))
6344 addr_list_empty = false;
23d154c0 6345 rcu_read_unlock();
5ea1237f 6346
2db99378
IS
6347 /* macvlans do not have a RIF, but rather piggy back on the
6348 * RIF of their lower device.
6349 */
6350 if (netif_is_macvlan(dev) && addr_list_empty)
6351 return true;
6352
5ea1237f 6353 if (rif && addr_list_empty &&
bf95233e 6354 !netif_is_l3_slave(rif->dev))
4724ba56
IS
6355 return true;
6356 /* It is possible we already removed the RIF ourselves
6357 * if it was assigned to a netdev that is now a bridge
6358 * or LAG slave.
6359 */
6360 return false;
6361 }
6362
6363 return false;
6364}
6365
e4f3c1c1
IS
6366static enum mlxsw_sp_rif_type
6367mlxsw_sp_dev_rif_type(const struct mlxsw_sp *mlxsw_sp,
6368 const struct net_device *dev)
6369{
6370 enum mlxsw_sp_fid_type type;
6371
6ddb7426
PM
6372 if (mlxsw_sp_netdev_ipip_type(mlxsw_sp, dev, NULL))
6373 return MLXSW_SP_RIF_TYPE_IPIP_LB;
6374
6375 /* Otherwise RIF type is derived from the type of the underlying FID. */
e4f3c1c1
IS
6376 if (is_vlan_dev(dev) && netif_is_bridge_master(vlan_dev_real_dev(dev)))
6377 type = MLXSW_SP_FID_TYPE_8021Q;
6378 else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev))
6379 type = MLXSW_SP_FID_TYPE_8021Q;
6380 else if (netif_is_bridge_master(dev))
6381 type = MLXSW_SP_FID_TYPE_8021D;
6382 else
6383 type = MLXSW_SP_FID_TYPE_RFID;
6384
6385 return mlxsw_sp_fid_type_rif_type(mlxsw_sp, type);
6386}
6387
de5ed99e 6388static int mlxsw_sp_rif_index_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_rif_index)
4724ba56
IS
6389{
6390 int i;
6391
de5ed99e
IS
6392 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
6393 if (!mlxsw_sp->router->rifs[i]) {
6394 *p_rif_index = i;
6395 return 0;
6396 }
6397 }
4724ba56 6398
de5ed99e 6399 return -ENOBUFS;
4724ba56
IS
6400}
6401
e4f3c1c1
IS
6402static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index,
6403 u16 vr_id,
6404 struct net_device *l3_dev)
4724ba56 6405{
bf95233e 6406 struct mlxsw_sp_rif *rif;
4724ba56 6407
e4f3c1c1 6408 rif = kzalloc(rif_size, GFP_KERNEL);
bf95233e 6409 if (!rif)
4724ba56
IS
6410 return NULL;
6411
bf95233e
AS
6412 INIT_LIST_HEAD(&rif->nexthop_list);
6413 INIT_LIST_HEAD(&rif->neigh_list);
73b8f493
ND
6414 if (l3_dev) {
6415 ether_addr_copy(rif->addr, l3_dev->dev_addr);
6416 rif->mtu = l3_dev->mtu;
6417 rif->dev = l3_dev;
6418 }
bf95233e 6419 rif->vr_id = vr_id;
bf95233e 6420 rif->rif_index = rif_index;
4724ba56 6421
bf95233e 6422 return rif;
4724ba56
IS
6423}
6424
5f9efffb
IS
6425struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
6426 u16 rif_index)
6427{
6428 return mlxsw_sp->router->rifs[rif_index];
6429}
6430
fd1b9d41
AS
6431u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif)
6432{
6433 return rif->rif_index;
6434}
6435
92107cfb
PM
6436u16 mlxsw_sp_ipip_lb_rif_index(const struct mlxsw_sp_rif_ipip_lb *lb_rif)
6437{
6438 return lb_rif->common.rif_index;
6439}
6440
6441u16 mlxsw_sp_ipip_lb_ul_vr_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif)
6442{
33c04afe
ND
6443 u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(lb_rif->common.dev);
6444 struct mlxsw_sp_vr *ul_vr;
6445
6446 ul_vr = mlxsw_sp_vr_get(lb_rif->common.mlxsw_sp, ul_tb_id, NULL);
6447 if (WARN_ON(IS_ERR(ul_vr)))
6448 return 0;
6449
6450 return ul_vr->id;
92107cfb
PM
6451}
6452
311596f5
ND
6453u16 mlxsw_sp_ipip_lb_ul_rif_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif)
6454{
6455 return lb_rif->ul_rif_id;
6456}
6457
fd1b9d41
AS
6458int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif)
6459{
6460 return rif->dev->ifindex;
6461}
6462
91e4d59a
YG
6463const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif)
6464{
6465 return rif->dev;
6466}
6467
4724ba56 6468static struct mlxsw_sp_rif *
e4f3c1c1 6469mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
f8fa9b4e
DA
6470 const struct mlxsw_sp_rif_params *params,
6471 struct netlink_ext_ack *extack)
4724ba56 6472{
e4f3c1c1
IS
6473 u32 tb_id = l3mdev_fib_table(params->dev);
6474 const struct mlxsw_sp_rif_ops *ops;
010cadf9 6475 struct mlxsw_sp_fid *fid = NULL;
e4f3c1c1 6476 enum mlxsw_sp_rif_type type;
bf95233e 6477 struct mlxsw_sp_rif *rif;
a1107487
IS
6478 struct mlxsw_sp_vr *vr;
6479 u16 rif_index;
9742f866 6480 int i, err;
4724ba56 6481
e4f3c1c1 6482 type = mlxsw_sp_dev_rif_type(mlxsw_sp, params->dev);
1f5b2303 6483 ops = mlxsw_sp->rif_ops_arr[type];
e4f3c1c1 6484
f8fa9b4e 6485 vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN, extack);
c9ec53f0
IS
6486 if (IS_ERR(vr))
6487 return ERR_CAST(vr);
28a04c7b 6488 vr->rif_count++;
c9ec53f0 6489
de5ed99e 6490 err = mlxsw_sp_rif_index_alloc(mlxsw_sp, &rif_index);
f8fa9b4e 6491 if (err) {
6c677750 6492 NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported router interfaces");
de5ed99e 6493 goto err_rif_index_alloc;
f8fa9b4e 6494 }
4724ba56 6495
e4f3c1c1 6496 rif = mlxsw_sp_rif_alloc(ops->rif_size, rif_index, vr->id, params->dev);
a13a594d
IS
6497 if (!rif) {
6498 err = -ENOMEM;
6499 goto err_rif_alloc;
6500 }
b61cd7c6 6501 dev_hold(rif->dev);
a04563e4 6502 mlxsw_sp->router->rifs[rif_index] = rif;
e4f3c1c1
IS
6503 rif->mlxsw_sp = mlxsw_sp;
6504 rif->ops = ops;
a13a594d 6505
010cadf9 6506 if (ops->fid_get) {
5f15e257 6507 fid = ops->fid_get(rif, extack);
010cadf9
PM
6508 if (IS_ERR(fid)) {
6509 err = PTR_ERR(fid);
6510 goto err_fid_get;
6511 }
6512 rif->fid = fid;
4d93ceeb
IS
6513 }
6514
e4f3c1c1
IS
6515 if (ops->setup)
6516 ops->setup(rif, params);
6517
6518 err = ops->configure(rif);
4724ba56 6519 if (err)
e4f3c1c1 6520 goto err_configure;
4724ba56 6521
9742f866
YM
6522 for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++) {
6523 err = mlxsw_sp_mr_rif_add(vr->mr_table[i], rif);
6524 if (err)
6525 goto err_mr_rif_add;
6526 }
d42b0965 6527
e4f3c1c1 6528 mlxsw_sp_rif_counters_alloc(rif);
4724ba56 6529
bf95233e 6530 return rif;
4724ba56 6531
d42b0965 6532err_mr_rif_add:
9742f866
YM
6533 for (i--; i >= 0; i--)
6534 mlxsw_sp_mr_rif_del(vr->mr_table[i], rif);
d42b0965 6535 ops->deconfigure(rif);
e4f3c1c1 6536err_configure:
010cadf9
PM
6537 if (fid)
6538 mlxsw_sp_fid_put(fid);
a1107487 6539err_fid_get:
a04563e4 6540 mlxsw_sp->router->rifs[rif_index] = NULL;
b61cd7c6 6541 dev_put(rif->dev);
e4f3c1c1
IS
6542 kfree(rif);
6543err_rif_alloc:
de5ed99e 6544err_rif_index_alloc:
28a04c7b 6545 vr->rif_count--;
2b52ce02 6546 mlxsw_sp_vr_put(mlxsw_sp, vr);
4724ba56
IS
6547 return ERR_PTR(err);
6548}
6549
32fd4b49 6550static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
4724ba56 6551{
e4f3c1c1
IS
6552 const struct mlxsw_sp_rif_ops *ops = rif->ops;
6553 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
a1107487 6554 struct mlxsw_sp_fid *fid = rif->fid;
e4f3c1c1 6555 struct mlxsw_sp_vr *vr;
9742f866 6556 int i;
4724ba56 6557
bf95233e 6558 mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
e4f3c1c1 6559 vr = &mlxsw_sp->router->vrs[rif->vr_id];
e0c0afd8 6560
e4f3c1c1 6561 mlxsw_sp_rif_counters_free(rif);
9742f866
YM
6562 for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++)
6563 mlxsw_sp_mr_rif_del(vr->mr_table[i], rif);
e4f3c1c1 6564 ops->deconfigure(rif);
010cadf9
PM
6565 if (fid)
6566 /* Loopback RIFs are not associated with a FID. */
6567 mlxsw_sp_fid_put(fid);
a04563e4 6568 mlxsw_sp->router->rifs[rif->rif_index] = NULL;
b61cd7c6 6569 dev_put(rif->dev);
e4f3c1c1 6570 kfree(rif);
28a04c7b 6571 vr->rif_count--;
2b52ce02 6572 mlxsw_sp_vr_put(mlxsw_sp, vr);
4724ba56
IS
6573}
6574
602b74ed
IS
6575void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp,
6576 struct net_device *dev)
6577{
6578 struct mlxsw_sp_rif *rif;
6579
6580 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6581 if (!rif)
6582 return;
6583 mlxsw_sp_rif_destroy(rif);
6584}
6585
e4f3c1c1
IS
6586static void
6587mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params,
6588 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
6589{
6590 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
6591
6592 params->vid = mlxsw_sp_port_vlan->vid;
6593 params->lag = mlxsw_sp_port->lagged;
6594 if (params->lag)
6595 params->lag_id = mlxsw_sp_port->lag_id;
6596 else
6597 params->system_port = mlxsw_sp_port->local_port;
6598}
6599
32fd4b49
IS
6600static struct mlxsw_sp_rif_subport *
6601mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif)
6602{
6603 return container_of(rif, struct mlxsw_sp_rif_subport, common);
6604}
6605
6606static struct mlxsw_sp_rif *
6607mlxsw_sp_rif_subport_get(struct mlxsw_sp *mlxsw_sp,
6608 const struct mlxsw_sp_rif_params *params,
6609 struct netlink_ext_ack *extack)
6610{
6611 struct mlxsw_sp_rif_subport *rif_subport;
6612 struct mlxsw_sp_rif *rif;
6613
6614 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, params->dev);
6615 if (!rif)
6616 return mlxsw_sp_rif_create(mlxsw_sp, params, extack);
6617
6618 rif_subport = mlxsw_sp_rif_subport_rif(rif);
6619 refcount_inc(&rif_subport->ref_count);
6620 return rif;
6621}
6622
6623static void mlxsw_sp_rif_subport_put(struct mlxsw_sp_rif *rif)
6624{
6625 struct mlxsw_sp_rif_subport *rif_subport;
6626
6627 rif_subport = mlxsw_sp_rif_subport_rif(rif);
6628 if (!refcount_dec_and_test(&rif_subport->ref_count))
6629 return;
6630
6631 mlxsw_sp_rif_destroy(rif);
6632}
6633
7cbecf24 6634static int
a1107487 6635mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
f8fa9b4e
DA
6636 struct net_device *l3_dev,
6637 struct netlink_ext_ack *extack)
4724ba56 6638{
7cbecf24 6639 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
1b8f09a0 6640 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
32fd4b49
IS
6641 struct mlxsw_sp_rif_params params = {
6642 .dev = l3_dev,
6643 };
7cbecf24 6644 u16 vid = mlxsw_sp_port_vlan->vid;
bf95233e 6645 struct mlxsw_sp_rif *rif;
a1107487 6646 struct mlxsw_sp_fid *fid;
03ea01e9 6647 int err;
4724ba56 6648
32fd4b49
IS
6649 mlxsw_sp_rif_subport_params_init(&params, mlxsw_sp_port_vlan);
6650 rif = mlxsw_sp_rif_subport_get(mlxsw_sp, &params, extack);
6651 if (IS_ERR(rif))
6652 return PTR_ERR(rif);
4724ba56 6653
a1107487 6654 /* FID was already created, just take a reference */
5f15e257 6655 fid = rif->ops->fid_get(rif, extack);
a1107487
IS
6656 err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
6657 if (err)
6658 goto err_fid_port_vid_map;
6659
7cbecf24 6660 err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
03ea01e9
IS
6661 if (err)
6662 goto err_port_vid_learning_set;
6663
7cbecf24 6664 err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid,
03ea01e9
IS
6665 BR_STATE_FORWARDING);
6666 if (err)
6667 goto err_port_vid_stp_set;
6668
a1107487 6669 mlxsw_sp_port_vlan->fid = fid;
4724ba56 6670
4724ba56 6671 return 0;
03ea01e9
IS
6672
6673err_port_vid_stp_set:
7cbecf24 6674 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
03ea01e9 6675err_port_vid_learning_set:
a1107487
IS
6676 mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
6677err_fid_port_vid_map:
6678 mlxsw_sp_fid_put(fid);
32fd4b49 6679 mlxsw_sp_rif_subport_put(rif);
03ea01e9 6680 return err;
4724ba56
IS
6681}
6682
1c6d6b51
IS
6683static void
6684__mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
4724ba56 6685{
ce95e154 6686 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
7cbecf24 6687 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
32fd4b49 6688 struct mlxsw_sp_rif *rif = mlxsw_sp_fid_rif(fid);
ce95e154 6689 u16 vid = mlxsw_sp_port_vlan->vid;
ce95e154 6690
a1107487
IS
6691 if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_RFID))
6692 return;
4aafc368 6693
a1107487 6694 mlxsw_sp_port_vlan->fid = NULL;
7cbecf24
IS
6695 mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING);
6696 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
a1107487 6697 mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
a1107487 6698 mlxsw_sp_fid_put(fid);
32fd4b49 6699 mlxsw_sp_rif_subport_put(rif);
4724ba56
IS
6700}
6701
1c6d6b51
IS
6702void
6703mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
6704{
6705 __mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
6706}
6707
7cbecf24
IS
6708static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev,
6709 struct net_device *port_dev,
f8fa9b4e
DA
6710 unsigned long event, u16 vid,
6711 struct netlink_ext_ack *extack)
4724ba56
IS
6712{
6713 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(port_dev);
ce95e154 6714 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
4724ba56 6715
ce95e154 6716 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
7cbecf24
IS
6717 if (WARN_ON(!mlxsw_sp_port_vlan))
6718 return -EINVAL;
4724ba56
IS
6719
6720 switch (event) {
6721 case NETDEV_UP:
a1107487 6722 return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan,
f8fa9b4e 6723 l3_dev, extack);
4724ba56 6724 case NETDEV_DOWN:
1c6d6b51 6725 __mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
4724ba56
IS
6726 break;
6727 }
6728
6729 return 0;
6730}
6731
6732static int mlxsw_sp_inetaddr_port_event(struct net_device *port_dev,
f8fa9b4e
DA
6733 unsigned long event,
6734 struct netlink_ext_ack *extack)
4724ba56 6735{
2b94e58d
JP
6736 if (netif_is_bridge_port(port_dev) ||
6737 netif_is_lag_port(port_dev) ||
6738 netif_is_ovs_port(port_dev))
4724ba56
IS
6739 return 0;
6740
a2d2a205
IS
6741 return mlxsw_sp_inetaddr_port_vlan_event(port_dev, port_dev, event,
6742 MLXSW_SP_DEFAULT_VID, extack);
4724ba56
IS
6743}
6744
6745static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev,
6746 struct net_device *lag_dev,
f8fa9b4e
DA
6747 unsigned long event, u16 vid,
6748 struct netlink_ext_ack *extack)
4724ba56
IS
6749{
6750 struct net_device *port_dev;
6751 struct list_head *iter;
6752 int err;
6753
6754 netdev_for_each_lower_dev(lag_dev, port_dev, iter) {
6755 if (mlxsw_sp_port_dev_check(port_dev)) {
7cbecf24
IS
6756 err = mlxsw_sp_inetaddr_port_vlan_event(l3_dev,
6757 port_dev,
f8fa9b4e
DA
6758 event, vid,
6759 extack);
4724ba56
IS
6760 if (err)
6761 return err;
6762 }
6763 }
6764
6765 return 0;
6766}
6767
6768static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
f8fa9b4e
DA
6769 unsigned long event,
6770 struct netlink_ext_ack *extack)
4724ba56
IS
6771{
6772 if (netif_is_bridge_port(lag_dev))
6773 return 0;
6774
a2d2a205
IS
6775 return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event,
6776 MLXSW_SP_DEFAULT_VID, extack);
4724ba56
IS
6777}
6778
21ffedb6
IS
6779static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
6780 struct net_device *l3_dev,
f8fa9b4e
DA
6781 unsigned long event,
6782 struct netlink_ext_ack *extack)
4724ba56 6783{
e4f3c1c1
IS
6784 struct mlxsw_sp_rif_params params = {
6785 .dev = l3_dev,
6786 };
a1107487 6787 struct mlxsw_sp_rif *rif;
4724ba56
IS
6788
6789 switch (event) {
6790 case NETDEV_UP:
f8fa9b4e 6791 rif = mlxsw_sp_rif_create(mlxsw_sp, &params, extack);
e4f3c1c1
IS
6792 if (IS_ERR(rif))
6793 return PTR_ERR(rif);
6794 break;
4724ba56 6795 case NETDEV_DOWN:
a1107487 6796 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
e4f3c1c1 6797 mlxsw_sp_rif_destroy(rif);
4724ba56
IS
6798 break;
6799 }
6800
6801 return 0;
6802}
6803
21ffedb6
IS
6804static int mlxsw_sp_inetaddr_vlan_event(struct mlxsw_sp *mlxsw_sp,
6805 struct net_device *vlan_dev,
f8fa9b4e
DA
6806 unsigned long event,
6807 struct netlink_ext_ack *extack)
4724ba56
IS
6808{
6809 struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
4724ba56
IS
6810 u16 vid = vlan_dev_vlan_id(vlan_dev);
6811
6b27c8ad
IS
6812 if (netif_is_bridge_port(vlan_dev))
6813 return 0;
6814
4724ba56 6815 if (mlxsw_sp_port_dev_check(real_dev))
7cbecf24 6816 return mlxsw_sp_inetaddr_port_vlan_event(vlan_dev, real_dev,
f8fa9b4e 6817 event, vid, extack);
4724ba56
IS
6818 else if (netif_is_lag_master(real_dev))
6819 return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
f8fa9b4e 6820 vid, extack);
c57529e1 6821 else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev))
21ffedb6
IS
6822 return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, vlan_dev, event,
6823 extack);
4724ba56
IS
6824
6825 return 0;
6826}
6827
c3a49540
IS
6828static bool mlxsw_sp_rif_macvlan_is_vrrp4(const u8 *mac)
6829{
6830 u8 vrrp4[ETH_ALEN] = { 0x00, 0x00, 0x5e, 0x00, 0x01, 0x00 };
6831 u8 mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
6832
6833 return ether_addr_equal_masked(mac, vrrp4, mask);
6834}
6835
6836static bool mlxsw_sp_rif_macvlan_is_vrrp6(const u8 *mac)
6837{
6838 u8 vrrp6[ETH_ALEN] = { 0x00, 0x00, 0x5e, 0x00, 0x02, 0x00 };
6839 u8 mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
6840
6841 return ether_addr_equal_masked(mac, vrrp6, mask);
6842}
6843
6844static int mlxsw_sp_rif_vrrp_op(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
6845 const u8 *mac, bool adding)
6846{
6847 char ritr_pl[MLXSW_REG_RITR_LEN];
6848 u8 vrrp_id = adding ? mac[5] : 0;
6849 int err;
6850
6851 if (!mlxsw_sp_rif_macvlan_is_vrrp4(mac) &&
6852 !mlxsw_sp_rif_macvlan_is_vrrp6(mac))
6853 return 0;
6854
6855 mlxsw_reg_ritr_rif_pack(ritr_pl, rif_index);
6856 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
6857 if (err)
6858 return err;
6859
6860 if (mlxsw_sp_rif_macvlan_is_vrrp4(mac))
6861 mlxsw_reg_ritr_if_vrrp_id_ipv4_set(ritr_pl, vrrp_id);
6862 else
6863 mlxsw_reg_ritr_if_vrrp_id_ipv6_set(ritr_pl, vrrp_id);
6864
6865 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
6866}
6867
2db99378
IS
6868static int mlxsw_sp_rif_macvlan_add(struct mlxsw_sp *mlxsw_sp,
6869 const struct net_device *macvlan_dev,
6870 struct netlink_ext_ack *extack)
6871{
6872 struct macvlan_dev *vlan = netdev_priv(macvlan_dev);
6873 struct mlxsw_sp_rif *rif;
6874 int err;
6875
6876 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan->lowerdev);
6877 if (!rif) {
6878 NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
6879 return -EOPNOTSUPP;
6880 }
6881
6882 err = mlxsw_sp_rif_fdb_op(mlxsw_sp, macvlan_dev->dev_addr,
6883 mlxsw_sp_fid_index(rif->fid), true);
6884 if (err)
6885 return err;
6886
c3a49540
IS
6887 err = mlxsw_sp_rif_vrrp_op(mlxsw_sp, rif->rif_index,
6888 macvlan_dev->dev_addr, true);
6889 if (err)
6890 goto err_rif_vrrp_add;
6891
2db99378
IS
6892 /* Make sure the bridge driver does not have this MAC pointing at
6893 * some other port.
6894 */
6895 if (rif->ops->fdb_del)
6896 rif->ops->fdb_del(rif, macvlan_dev->dev_addr);
6897
6898 return 0;
c3a49540
IS
6899
6900err_rif_vrrp_add:
6901 mlxsw_sp_rif_fdb_op(mlxsw_sp, macvlan_dev->dev_addr,
6902 mlxsw_sp_fid_index(rif->fid), false);
6903 return err;
2db99378
IS
6904}
6905
fbf8b356
IS
6906static void __mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp,
6907 const struct net_device *macvlan_dev)
2db99378
IS
6908{
6909 struct macvlan_dev *vlan = netdev_priv(macvlan_dev);
6910 struct mlxsw_sp_rif *rif;
6911
6912 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan->lowerdev);
6913 /* If we do not have a RIF, then we already took care of
6914 * removing the macvlan's MAC during RIF deletion.
6915 */
6916 if (!rif)
6917 return;
c3a49540
IS
6918 mlxsw_sp_rif_vrrp_op(mlxsw_sp, rif->rif_index, macvlan_dev->dev_addr,
6919 false);
2db99378
IS
6920 mlxsw_sp_rif_fdb_op(mlxsw_sp, macvlan_dev->dev_addr,
6921 mlxsw_sp_fid_index(rif->fid), false);
6922}
6923
fbf8b356
IS
6924void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp,
6925 const struct net_device *macvlan_dev)
6926{
6927 __mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev);
6928}
6929
21ffedb6
IS
6930static int mlxsw_sp_inetaddr_macvlan_event(struct mlxsw_sp *mlxsw_sp,
6931 struct net_device *macvlan_dev,
2db99378
IS
6932 unsigned long event,
6933 struct netlink_ext_ack *extack)
6934{
2db99378
IS
6935 switch (event) {
6936 case NETDEV_UP:
6937 return mlxsw_sp_rif_macvlan_add(mlxsw_sp, macvlan_dev, extack);
6938 case NETDEV_DOWN:
fbf8b356 6939 __mlxsw_sp_rif_macvlan_del(mlxsw_sp, macvlan_dev);
2db99378
IS
6940 break;
6941 }
6942
6943 return 0;
6944}
6945
74bc9939
PM
6946static int mlxsw_sp_router_port_check_rif_addr(struct mlxsw_sp *mlxsw_sp,
6947 struct net_device *dev,
6948 const unsigned char *dev_addr,
6949 struct netlink_ext_ack *extack)
6950{
6951 struct mlxsw_sp_rif *rif;
6952 int i;
6953
6954 /* A RIF is not created for macvlan netdevs. Their MAC is used to
6955 * populate the FDB
6956 */
972fae68 6957 if (netif_is_macvlan(dev) || netif_is_l3_master(dev))
74bc9939
PM
6958 return 0;
6959
6960 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
6961 rif = mlxsw_sp->router->rifs[i];
314bd842
AC
6962 if (rif && rif->ops &&
6963 rif->ops->type == MLXSW_SP_RIF_TYPE_IPIP_LB)
6964 continue;
73b8f493 6965 if (rif && rif->dev && rif->dev != dev &&
74bc9939
PM
6966 !ether_addr_equal_masked(rif->dev->dev_addr, dev_addr,
6967 mlxsw_sp->mac_mask)) {
6968 NL_SET_ERR_MSG_MOD(extack, "All router interface MAC addresses must have the same prefix");
6969 return -EINVAL;
6970 }
6971 }
6972
6973 return 0;
6974}
6975
21ffedb6
IS
6976static int __mlxsw_sp_inetaddr_event(struct mlxsw_sp *mlxsw_sp,
6977 struct net_device *dev,
f8fa9b4e
DA
6978 unsigned long event,
6979 struct netlink_ext_ack *extack)
b1e45526
IS
6980{
6981 if (mlxsw_sp_port_dev_check(dev))
f8fa9b4e 6982 return mlxsw_sp_inetaddr_port_event(dev, event, extack);
b1e45526 6983 else if (netif_is_lag_master(dev))
f8fa9b4e 6984 return mlxsw_sp_inetaddr_lag_event(dev, event, extack);
b1e45526 6985 else if (netif_is_bridge_master(dev))
21ffedb6
IS
6986 return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, dev, event,
6987 extack);
b1e45526 6988 else if (is_vlan_dev(dev))
21ffedb6
IS
6989 return mlxsw_sp_inetaddr_vlan_event(mlxsw_sp, dev, event,
6990 extack);
2db99378 6991 else if (netif_is_macvlan(dev))
21ffedb6
IS
6992 return mlxsw_sp_inetaddr_macvlan_event(mlxsw_sp, dev, event,
6993 extack);
b1e45526
IS
6994 else
6995 return 0;
6996}
6997
965fa8e6
IS
6998static int mlxsw_sp_inetaddr_event(struct notifier_block *nb,
6999 unsigned long event, void *ptr)
4724ba56
IS
7000{
7001 struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
7002 struct net_device *dev = ifa->ifa_dev->dev;
965fa8e6 7003 struct mlxsw_sp_router *router;
bf95233e 7004 struct mlxsw_sp_rif *rif;
4724ba56
IS
7005 int err = 0;
7006
89d5dd2e
DA
7007 /* NETDEV_UP event is handled by mlxsw_sp_inetaddr_valid_event */
7008 if (event == NETDEV_UP)
7009 goto out;
7010
965fa8e6
IS
7011 router = container_of(nb, struct mlxsw_sp_router, inetaddr_nb);
7012 rif = mlxsw_sp_rif_find_by_dev(router->mlxsw_sp, dev);
89d5dd2e
DA
7013 if (!mlxsw_sp_rif_should_config(rif, dev, event))
7014 goto out;
7015
965fa8e6 7016 err = __mlxsw_sp_inetaddr_event(router->mlxsw_sp, dev, event, NULL);
89d5dd2e
DA
7017out:
7018 return notifier_from_errno(err);
7019}
7020
7021int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused,
7022 unsigned long event, void *ptr)
7023{
7024 struct in_validator_info *ivi = (struct in_validator_info *) ptr;
7025 struct net_device *dev = ivi->ivi_dev->dev;
7026 struct mlxsw_sp *mlxsw_sp;
7027 struct mlxsw_sp_rif *rif;
7028 int err = 0;
7029
4724ba56
IS
7030 mlxsw_sp = mlxsw_sp_lower_get(dev);
7031 if (!mlxsw_sp)
7032 goto out;
7033
bf95233e 7034 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
5ea1237f 7035 if (!mlxsw_sp_rif_should_config(rif, dev, event))
4724ba56
IS
7036 goto out;
7037
74bc9939
PM
7038 err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr,
7039 ivi->extack);
7040 if (err)
7041 goto out;
7042
21ffedb6 7043 err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, ivi->extack);
4724ba56
IS
7044out:
7045 return notifier_from_errno(err);
7046}
7047
5ea1237f
AS
7048struct mlxsw_sp_inet6addr_event_work {
7049 struct work_struct work;
965fa8e6 7050 struct mlxsw_sp *mlxsw_sp;
5ea1237f
AS
7051 struct net_device *dev;
7052 unsigned long event;
7053};
7054
7055static void mlxsw_sp_inet6addr_event_work(struct work_struct *work)
7056{
7057 struct mlxsw_sp_inet6addr_event_work *inet6addr_work =
7058 container_of(work, struct mlxsw_sp_inet6addr_event_work, work);
965fa8e6 7059 struct mlxsw_sp *mlxsw_sp = inet6addr_work->mlxsw_sp;
5ea1237f
AS
7060 struct net_device *dev = inet6addr_work->dev;
7061 unsigned long event = inet6addr_work->event;
5ea1237f
AS
7062 struct mlxsw_sp_rif *rif;
7063
7064 rtnl_lock();
5ea1237f
AS
7065
7066 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
7067 if (!mlxsw_sp_rif_should_config(rif, dev, event))
7068 goto out;
7069
21ffedb6 7070 __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, NULL);
5ea1237f
AS
7071out:
7072 rtnl_unlock();
7073 dev_put(dev);
7074 kfree(inet6addr_work);
7075}
7076
7077/* Called with rcu_read_lock() */
965fa8e6
IS
7078static int mlxsw_sp_inet6addr_event(struct notifier_block *nb,
7079 unsigned long event, void *ptr)
5ea1237f
AS
7080{
7081 struct inet6_ifaddr *if6 = (struct inet6_ifaddr *) ptr;
7082 struct mlxsw_sp_inet6addr_event_work *inet6addr_work;
7083 struct net_device *dev = if6->idev->dev;
965fa8e6 7084 struct mlxsw_sp_router *router;
5ea1237f 7085
89d5dd2e
DA
7086 /* NETDEV_UP event is handled by mlxsw_sp_inet6addr_valid_event */
7087 if (event == NETDEV_UP)
7088 return NOTIFY_DONE;
7089
5ea1237f
AS
7090 inet6addr_work = kzalloc(sizeof(*inet6addr_work), GFP_ATOMIC);
7091 if (!inet6addr_work)
7092 return NOTIFY_BAD;
7093
965fa8e6 7094 router = container_of(nb, struct mlxsw_sp_router, inet6addr_nb);
5ea1237f 7095 INIT_WORK(&inet6addr_work->work, mlxsw_sp_inet6addr_event_work);
965fa8e6 7096 inet6addr_work->mlxsw_sp = router->mlxsw_sp;
5ea1237f
AS
7097 inet6addr_work->dev = dev;
7098 inet6addr_work->event = event;
7099 dev_hold(dev);
7100 mlxsw_core_schedule_work(&inet6addr_work->work);
7101
7102 return NOTIFY_DONE;
7103}
7104
89d5dd2e
DA
7105int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused,
7106 unsigned long event, void *ptr)
7107{
7108 struct in6_validator_info *i6vi = (struct in6_validator_info *) ptr;
7109 struct net_device *dev = i6vi->i6vi_dev->dev;
7110 struct mlxsw_sp *mlxsw_sp;
7111 struct mlxsw_sp_rif *rif;
7112 int err = 0;
7113
7114 mlxsw_sp = mlxsw_sp_lower_get(dev);
7115 if (!mlxsw_sp)
7116 goto out;
7117
7118 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
7119 if (!mlxsw_sp_rif_should_config(rif, dev, event))
7120 goto out;
7121
74bc9939
PM
7122 err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr,
7123 i6vi->extack);
7124 if (err)
7125 goto out;
7126
21ffedb6 7127 err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, i6vi->extack);
89d5dd2e
DA
7128out:
7129 return notifier_from_errno(err);
7130}
7131
bf95233e 7132static int mlxsw_sp_rif_edit(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
4724ba56
IS
7133 const char *mac, int mtu)
7134{
7135 char ritr_pl[MLXSW_REG_RITR_LEN];
7136 int err;
7137
bf95233e 7138 mlxsw_reg_ritr_rif_pack(ritr_pl, rif_index);
4724ba56
IS
7139 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
7140 if (err)
7141 return err;
7142
7143 mlxsw_reg_ritr_mtu_set(ritr_pl, mtu);
7144 mlxsw_reg_ritr_if_mac_memcpy_to(ritr_pl, mac);
7145 mlxsw_reg_ritr_op_set(ritr_pl, MLXSW_REG_RITR_RIF_CREATE);
7146 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
7147}
7148
9735f2d2
PM
7149static int
7150mlxsw_sp_router_port_change_event(struct mlxsw_sp *mlxsw_sp,
7151 struct mlxsw_sp_rif *rif)
4724ba56 7152{
9735f2d2 7153 struct net_device *dev = rif->dev;
a1107487 7154 u16 fid_index;
4724ba56
IS
7155 int err;
7156
a1107487 7157 fid_index = mlxsw_sp_fid_index(rif->fid);
4724ba56 7158
a1107487 7159 err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, false);
4724ba56
IS
7160 if (err)
7161 return err;
7162
bf95233e
AS
7163 err = mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, dev->dev_addr,
7164 dev->mtu);
4724ba56
IS
7165 if (err)
7166 goto err_rif_edit;
7167
a1107487 7168 err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, fid_index, true);
4724ba56
IS
7169 if (err)
7170 goto err_rif_fdb_op;
7171
fd890fe9
YG
7172 if (rif->mtu != dev->mtu) {
7173 struct mlxsw_sp_vr *vr;
9742f866 7174 int i;
fd890fe9
YG
7175
7176 /* The RIF is relevant only to its mr_table instance, as unlike
7177 * unicast routing, in multicast routing a RIF cannot be shared
7178 * between several multicast routing tables.
7179 */
7180 vr = &mlxsw_sp->router->vrs[rif->vr_id];
9742f866
YM
7181 for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++)
7182 mlxsw_sp_mr_rif_mtu_update(vr->mr_table[i],
7183 rif, dev->mtu);
fd890fe9
YG
7184 }
7185
bf95233e
AS
7186 ether_addr_copy(rif->addr, dev->dev_addr);
7187 rif->mtu = dev->mtu;
4724ba56 7188
bf95233e 7189 netdev_dbg(dev, "Updated RIF=%d\n", rif->rif_index);
4724ba56
IS
7190
7191 return 0;
7192
7193err_rif_fdb_op:
bf95233e 7194 mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu);
4724ba56 7195err_rif_edit:
a1107487 7196 mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, true);
4724ba56
IS
7197 return err;
7198}
7199
74bc9939
PM
7200static int mlxsw_sp_router_port_pre_changeaddr_event(struct mlxsw_sp_rif *rif,
7201 struct netdev_notifier_pre_changeaddr_info *info)
7202{
7203 struct netlink_ext_ack *extack;
7204
7205 extack = netdev_notifier_info_to_extack(&info->info);
7206 return mlxsw_sp_router_port_check_rif_addr(rif->mlxsw_sp, rif->dev,
7207 info->dev_addr, extack);
7208}
7209
9735f2d2
PM
7210int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
7211 unsigned long event, void *ptr)
7212{
7213 struct mlxsw_sp *mlxsw_sp;
7214 struct mlxsw_sp_rif *rif;
7215
7216 mlxsw_sp = mlxsw_sp_lower_get(dev);
7217 if (!mlxsw_sp)
7218 return 0;
7219
7220 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
7221 if (!rif)
7222 return 0;
7223
7224 switch (event) {
7225 case NETDEV_CHANGEMTU: /* fall through */
7226 case NETDEV_CHANGEADDR:
7227 return mlxsw_sp_router_port_change_event(mlxsw_sp, rif);
74bc9939
PM
7228 case NETDEV_PRE_CHANGEADDR:
7229 return mlxsw_sp_router_port_pre_changeaddr_event(rif, ptr);
9735f2d2
PM
7230 }
7231
7232 return 0;
7233}
7234
b1e45526 7235static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp,
f8fa9b4e
DA
7236 struct net_device *l3_dev,
7237 struct netlink_ext_ack *extack)
7179eb5a 7238{
b1e45526 7239 struct mlxsw_sp_rif *rif;
7179eb5a 7240
b1e45526
IS
7241 /* If netdev is already associated with a RIF, then we need to
7242 * destroy it and create a new one with the new virtual router ID.
7179eb5a 7243 */
b1e45526
IS
7244 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
7245 if (rif)
21ffedb6
IS
7246 __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN,
7247 extack);
7179eb5a 7248
21ffedb6 7249 return __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_UP, extack);
7179eb5a
IS
7250}
7251
b1e45526
IS
7252static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp,
7253 struct net_device *l3_dev)
7179eb5a 7254{
b1e45526 7255 struct mlxsw_sp_rif *rif;
7179eb5a 7256
b1e45526
IS
7257 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
7258 if (!rif)
7179eb5a 7259 return;
21ffedb6 7260 __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN, NULL);
7179eb5a
IS
7261}
7262
b1e45526
IS
7263int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
7264 struct netdev_notifier_changeupper_info *info)
3d70e458 7265{
b1e45526
IS
7266 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
7267 int err = 0;
3d70e458 7268
c5516185
IS
7269 /* We do not create a RIF for a macvlan, but only use it to
7270 * direct more MAC addresses to the router.
7271 */
7272 if (!mlxsw_sp || netif_is_macvlan(l3_dev))
b1e45526 7273 return 0;
3d70e458 7274
b1e45526
IS
7275 switch (event) {
7276 case NETDEV_PRECHANGEUPPER:
7277 return 0;
7278 case NETDEV_CHANGEUPPER:
f8fa9b4e
DA
7279 if (info->linking) {
7280 struct netlink_ext_ack *extack;
7281
7282 extack = netdev_notifier_info_to_extack(&info->info);
7283 err = mlxsw_sp_port_vrf_join(mlxsw_sp, l3_dev, extack);
7284 } else {
b1e45526 7285 mlxsw_sp_port_vrf_leave(mlxsw_sp, l3_dev);
f8fa9b4e 7286 }
b1e45526
IS
7287 break;
7288 }
3d70e458 7289
b1e45526 7290 return err;
3d70e458
IS
7291}
7292
2db99378
IS
7293static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev, void *data)
7294{
7295 struct mlxsw_sp_rif *rif = data;
7296
7297 if (!netif_is_macvlan(dev))
7298 return 0;
7299
7300 return mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
7301 mlxsw_sp_fid_index(rif->fid), false);
7302}
7303
7304static int mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif *rif)
7305{
7306 if (!netif_is_macvlan_port(rif->dev))
7307 return 0;
7308
7309 netdev_warn(rif->dev, "Router interface is deleted. Upper macvlans will not work\n");
7310 return netdev_walk_all_upper_dev_rcu(rif->dev,
7311 __mlxsw_sp_rif_macvlan_flush, rif);
7312}
7313
e4f3c1c1
IS
7314static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif,
7315 const struct mlxsw_sp_rif_params *params)
7316{
7317 struct mlxsw_sp_rif_subport *rif_subport;
7318
7319 rif_subport = mlxsw_sp_rif_subport_rif(rif);
32fd4b49 7320 refcount_set(&rif_subport->ref_count, 1);
e4f3c1c1
IS
7321 rif_subport->vid = params->vid;
7322 rif_subport->lag = params->lag;
7323 if (params->lag)
7324 rif_subport->lag_id = params->lag_id;
a1107487 7325 else
e4f3c1c1
IS
7326 rif_subport->system_port = params->system_port;
7327}
7328
7329static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable)
7330{
7331 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7332 struct mlxsw_sp_rif_subport *rif_subport;
7333 char ritr_pl[MLXSW_REG_RITR_LEN];
7334
7335 rif_subport = mlxsw_sp_rif_subport_rif(rif);
7336 mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_SP_IF,
9571e828
PM
7337 rif->rif_index, rif->vr_id, rif->dev->mtu);
7338 mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr);
e4f3c1c1
IS
7339 mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag,
7340 rif_subport->lag ? rif_subport->lag_id :
7341 rif_subport->system_port,
7342 rif_subport->vid);
7343
7344 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
7345}
7346
7347static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif)
7348{
010cadf9
PM
7349 int err;
7350
7351 err = mlxsw_sp_rif_subport_op(rif, true);
7352 if (err)
7353 return err;
7354
7355 err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
7356 mlxsw_sp_fid_index(rif->fid), true);
7357 if (err)
7358 goto err_rif_fdb_op;
7359
7360 mlxsw_sp_fid_rif_set(rif->fid, rif);
7361 return 0;
7362
7363err_rif_fdb_op:
7364 mlxsw_sp_rif_subport_op(rif, false);
7365 return err;
a1107487
IS
7366}
7367
e4f3c1c1
IS
7368static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif)
7369{
010cadf9
PM
7370 struct mlxsw_sp_fid *fid = rif->fid;
7371
7372 mlxsw_sp_fid_rif_set(fid, NULL);
7373 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
7374 mlxsw_sp_fid_index(fid), false);
2db99378 7375 mlxsw_sp_rif_macvlan_flush(rif);
e4f3c1c1
IS
7376 mlxsw_sp_rif_subport_op(rif, false);
7377}
7378
7379static struct mlxsw_sp_fid *
5f15e257
PM
7380mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif *rif,
7381 struct netlink_ext_ack *extack)
e4f3c1c1
IS
7382{
7383 return mlxsw_sp_fid_rfid_get(rif->mlxsw_sp, rif->rif_index);
7384}
7385
7386static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_subport_ops = {
7387 .type = MLXSW_SP_RIF_TYPE_SUBPORT,
7388 .rif_size = sizeof(struct mlxsw_sp_rif_subport),
7389 .setup = mlxsw_sp_rif_subport_setup,
7390 .configure = mlxsw_sp_rif_subport_configure,
7391 .deconfigure = mlxsw_sp_rif_subport_deconfigure,
7392 .fid_get = mlxsw_sp_rif_subport_fid_get,
7393};
7394
7395static int mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif *rif,
7396 enum mlxsw_reg_ritr_if_type type,
7397 u16 vid_fid, bool enable)
7398{
7399 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7400 char ritr_pl[MLXSW_REG_RITR_LEN];
7401
7402 mlxsw_reg_ritr_pack(ritr_pl, enable, type, rif->rif_index, rif->vr_id,
9571e828
PM
7403 rif->dev->mtu);
7404 mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr);
e4f3c1c1
IS
7405 mlxsw_reg_ritr_fid_set(ritr_pl, type, vid_fid);
7406
7407 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
7408}
7409
b35750f1 7410u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp)
e4f3c1c1
IS
7411{
7412 return mlxsw_core_max_ports(mlxsw_sp->core) + 1;
7413}
7414
7415static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif)
7416{
7417 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7418 u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
7419 int err;
7420
7421 err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, true);
7422 if (err)
7423 return err;
7424
0d284818
IS
7425 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7426 mlxsw_sp_router_port(mlxsw_sp), true);
7427 if (err)
7428 goto err_fid_mc_flood_set;
7429
e4f3c1c1
IS
7430 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7431 mlxsw_sp_router_port(mlxsw_sp), true);
7432 if (err)
7433 goto err_fid_bc_flood_set;
7434
010cadf9
PM
7435 err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
7436 mlxsw_sp_fid_index(rif->fid), true);
7437 if (err)
7438 goto err_rif_fdb_op;
7439
7440 mlxsw_sp_fid_rif_set(rif->fid, rif);
e4f3c1c1
IS
7441 return 0;
7442
010cadf9
PM
7443err_rif_fdb_op:
7444 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7445 mlxsw_sp_router_port(mlxsw_sp), false);
e4f3c1c1 7446err_fid_bc_flood_set:
0d284818
IS
7447 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7448 mlxsw_sp_router_port(mlxsw_sp), false);
7449err_fid_mc_flood_set:
e4f3c1c1
IS
7450 mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false);
7451 return err;
7452}
7453
7454static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif *rif)
7455{
e4f3c1c1 7456 u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
010cadf9
PM
7457 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7458 struct mlxsw_sp_fid *fid = rif->fid;
e4f3c1c1 7459
010cadf9
PM
7460 mlxsw_sp_fid_rif_set(fid, NULL);
7461 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
7462 mlxsw_sp_fid_index(fid), false);
2db99378 7463 mlxsw_sp_rif_macvlan_flush(rif);
e4f3c1c1
IS
7464 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7465 mlxsw_sp_router_port(mlxsw_sp), false);
0d284818
IS
7466 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7467 mlxsw_sp_router_port(mlxsw_sp), false);
e4f3c1c1
IS
7468 mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false);
7469}
7470
7471static struct mlxsw_sp_fid *
5f15e257
PM
7472mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif,
7473 struct netlink_ext_ack *extack)
e4f3c1c1 7474{
f40be47a 7475 struct net_device *br_dev = rif->dev;
e6f1960a
PM
7476 u16 vid;
7477 int err;
7478
7479 if (is_vlan_dev(rif->dev)) {
7480 vid = vlan_dev_vlan_id(rif->dev);
f40be47a
IS
7481 br_dev = vlan_dev_real_dev(rif->dev);
7482 if (WARN_ON(!netif_is_bridge_master(br_dev)))
7483 return ERR_PTR(-EINVAL);
e6f1960a
PM
7484 } else {
7485 err = br_vlan_get_pvid(rif->dev, &vid);
be9c64b1 7486 if (err < 0 || !vid) {
e6f1960a 7487 NL_SET_ERR_MSG_MOD(extack, "Couldn't determine bridge PVID");
be9c64b1 7488 return ERR_PTR(-EINVAL);
e6f1960a
PM
7489 }
7490 }
e4f3c1c1 7491
da1f9f8c 7492 return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid);
e4f3c1c1
IS
7493}
7494
2db99378
IS
7495static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac)
7496{
7497 u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
7498 struct switchdev_notifier_fdb_info info;
7499 struct net_device *br_dev;
7500 struct net_device *dev;
7501
7502 br_dev = is_vlan_dev(rif->dev) ? vlan_dev_real_dev(rif->dev) : rif->dev;
7503 dev = br_fdb_find_port(br_dev, mac, vid);
7504 if (!dev)
7505 return;
7506
7507 info.addr = mac;
7508 info.vid = vid;
6685987c
PM
7509 call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info,
7510 NULL);
2db99378
IS
7511}
7512
e4f3c1c1
IS
7513static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_ops = {
7514 .type = MLXSW_SP_RIF_TYPE_VLAN,
7515 .rif_size = sizeof(struct mlxsw_sp_rif),
7516 .configure = mlxsw_sp_rif_vlan_configure,
7517 .deconfigure = mlxsw_sp_rif_vlan_deconfigure,
7518 .fid_get = mlxsw_sp_rif_vlan_fid_get,
2db99378 7519 .fdb_del = mlxsw_sp_rif_vlan_fdb_del,
e4f3c1c1
IS
7520};
7521
7522static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif)
7523{
7524 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7525 u16 fid_index = mlxsw_sp_fid_index(rif->fid);
7526 int err;
7527
7528 err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index,
7529 true);
7530 if (err)
7531 return err;
7532
0d284818
IS
7533 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7534 mlxsw_sp_router_port(mlxsw_sp), true);
7535 if (err)
7536 goto err_fid_mc_flood_set;
7537
e4f3c1c1
IS
7538 err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7539 mlxsw_sp_router_port(mlxsw_sp), true);
7540 if (err)
7541 goto err_fid_bc_flood_set;
7542
010cadf9
PM
7543 err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
7544 mlxsw_sp_fid_index(rif->fid), true);
7545 if (err)
7546 goto err_rif_fdb_op;
7547
7548 mlxsw_sp_fid_rif_set(rif->fid, rif);
e4f3c1c1
IS
7549 return 0;
7550
010cadf9
PM
7551err_rif_fdb_op:
7552 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7553 mlxsw_sp_router_port(mlxsw_sp), false);
e4f3c1c1 7554err_fid_bc_flood_set:
0d284818
IS
7555 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7556 mlxsw_sp_router_port(mlxsw_sp), false);
7557err_fid_mc_flood_set:
e4f3c1c1
IS
7558 mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
7559 return err;
7560}
7561
7562static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)
7563{
e4f3c1c1 7564 u16 fid_index = mlxsw_sp_fid_index(rif->fid);
010cadf9
PM
7565 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7566 struct mlxsw_sp_fid *fid = rif->fid;
e4f3c1c1 7567
010cadf9
PM
7568 mlxsw_sp_fid_rif_set(fid, NULL);
7569 mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
7570 mlxsw_sp_fid_index(fid), false);
2db99378 7571 mlxsw_sp_rif_macvlan_flush(rif);
e4f3c1c1
IS
7572 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
7573 mlxsw_sp_router_port(mlxsw_sp), false);
0d284818
IS
7574 mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
7575 mlxsw_sp_router_port(mlxsw_sp), false);
e4f3c1c1
IS
7576 mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
7577}
7578
7579static struct mlxsw_sp_fid *
5f15e257
PM
7580mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif,
7581 struct netlink_ext_ack *extack)
e4f3c1c1 7582{
da1f9f8c 7583 return mlxsw_sp_fid_8021d_get(rif->mlxsw_sp, rif->dev->ifindex);
e4f3c1c1
IS
7584}
7585
2db99378
IS
7586static void mlxsw_sp_rif_fid_fdb_del(struct mlxsw_sp_rif *rif, const char *mac)
7587{
7588 struct switchdev_notifier_fdb_info info;
7589 struct net_device *dev;
7590
7591 dev = br_fdb_find_port(rif->dev, mac, 0);
7592 if (!dev)
7593 return;
7594
7595 info.addr = mac;
7596 info.vid = 0;
6685987c
PM
7597 call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, dev, &info.info,
7598 NULL);
2db99378
IS
7599}
7600
e4f3c1c1
IS
7601static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = {
7602 .type = MLXSW_SP_RIF_TYPE_FID,
7603 .rif_size = sizeof(struct mlxsw_sp_rif),
7604 .configure = mlxsw_sp_rif_fid_configure,
7605 .deconfigure = mlxsw_sp_rif_fid_deconfigure,
7606 .fid_get = mlxsw_sp_rif_fid_fid_get,
2db99378 7607 .fdb_del = mlxsw_sp_rif_fid_fdb_del,
e4f3c1c1
IS
7608};
7609
ba6da02a
IS
7610static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_emu_ops = {
7611 .type = MLXSW_SP_RIF_TYPE_VLAN,
7612 .rif_size = sizeof(struct mlxsw_sp_rif),
7613 .configure = mlxsw_sp_rif_fid_configure,
7614 .deconfigure = mlxsw_sp_rif_fid_deconfigure,
7615 .fid_get = mlxsw_sp_rif_vlan_fid_get,
7616 .fdb_del = mlxsw_sp_rif_vlan_fdb_del,
7617};
7618
6ddb7426
PM
7619static struct mlxsw_sp_rif_ipip_lb *
7620mlxsw_sp_rif_ipip_lb_rif(struct mlxsw_sp_rif *rif)
7621{
7622 return container_of(rif, struct mlxsw_sp_rif_ipip_lb, common);
7623}
7624
7625static void
7626mlxsw_sp_rif_ipip_lb_setup(struct mlxsw_sp_rif *rif,
7627 const struct mlxsw_sp_rif_params *params)
7628{
7629 struct mlxsw_sp_rif_params_ipip_lb *params_lb;
7630 struct mlxsw_sp_rif_ipip_lb *rif_lb;
7631
7632 params_lb = container_of(params, struct mlxsw_sp_rif_params_ipip_lb,
7633 common);
7634 rif_lb = mlxsw_sp_rif_ipip_lb_rif(rif);
7635 rif_lb->lb_config = params_lb->lb_config;
7636}
7637
6ddb7426 7638static int
99974468 7639mlxsw_sp1_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif)
6ddb7426
PM
7640{
7641 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
7642 u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(rif->dev);
7643 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7644 struct mlxsw_sp_vr *ul_vr;
7645 int err;
7646
f8fa9b4e 7647 ul_vr = mlxsw_sp_vr_get(mlxsw_sp, ul_tb_id, NULL);
6ddb7426
PM
7648 if (IS_ERR(ul_vr))
7649 return PTR_ERR(ul_vr);
7650
3c747500 7651 err = mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr->id, 0, true);
6ddb7426
PM
7652 if (err)
7653 goto err_loopback_op;
7654
7655 lb_rif->ul_vr_id = ul_vr->id;
25f844dd 7656 lb_rif->ul_rif_id = 0;
6ddb7426
PM
7657 ++ul_vr->rif_count;
7658 return 0;
7659
7660err_loopback_op:
2b52ce02 7661 mlxsw_sp_vr_put(mlxsw_sp, ul_vr);
6ddb7426
PM
7662 return err;
7663}
7664
99974468 7665static void mlxsw_sp1_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif)
6ddb7426
PM
7666{
7667 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
7668 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7669 struct mlxsw_sp_vr *ul_vr;
7670
7671 ul_vr = &mlxsw_sp->router->vrs[lb_rif->ul_vr_id];
3c747500 7672 mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr->id, 0, false);
6ddb7426
PM
7673
7674 --ul_vr->rif_count;
2b52ce02 7675 mlxsw_sp_vr_put(mlxsw_sp, ul_vr);
6ddb7426
PM
7676}
7677
99974468 7678static const struct mlxsw_sp_rif_ops mlxsw_sp1_rif_ipip_lb_ops = {
6ddb7426
PM
7679 .type = MLXSW_SP_RIF_TYPE_IPIP_LB,
7680 .rif_size = sizeof(struct mlxsw_sp_rif_ipip_lb),
7681 .setup = mlxsw_sp_rif_ipip_lb_setup,
99974468
ND
7682 .configure = mlxsw_sp1_rif_ipip_lb_configure,
7683 .deconfigure = mlxsw_sp1_rif_ipip_lb_deconfigure,
6ddb7426
PM
7684};
7685
99974468 7686const struct mlxsw_sp_rif_ops *mlxsw_sp1_rif_ops_arr[] = {
e4f3c1c1 7687 [MLXSW_SP_RIF_TYPE_SUBPORT] = &mlxsw_sp_rif_subport_ops,
c2e7490c 7688 [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp_rif_vlan_emu_ops,
e4f3c1c1 7689 [MLXSW_SP_RIF_TYPE_FID] = &mlxsw_sp_rif_fid_ops,
99974468
ND
7690 [MLXSW_SP_RIF_TYPE_IPIP_LB] = &mlxsw_sp1_rif_ipip_lb_ops,
7691};
7692
a5040a90
ND
7693static int
7694mlxsw_sp_rif_ipip_lb_ul_rif_op(struct mlxsw_sp_rif *ul_rif, bool enable)
7695{
7696 struct mlxsw_sp *mlxsw_sp = ul_rif->mlxsw_sp;
7697 char ritr_pl[MLXSW_REG_RITR_LEN];
7698
7699 mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF,
7700 ul_rif->rif_index, ul_rif->vr_id, IP_MAX_MTU);
7701 mlxsw_reg_ritr_loopback_protocol_set(ritr_pl,
7702 MLXSW_REG_RITR_LOOPBACK_GENERIC);
7703
7704 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
7705}
7706
7707static struct mlxsw_sp_rif *
7708mlxsw_sp_ul_rif_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr,
7709 struct netlink_ext_ack *extack)
7710{
7711 struct mlxsw_sp_rif *ul_rif;
7712 u16 rif_index;
7713 int err;
7714
7715 err = mlxsw_sp_rif_index_alloc(mlxsw_sp, &rif_index);
7716 if (err) {
7717 NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported router interfaces");
7718 return ERR_PTR(err);
7719 }
7720
7721 ul_rif = mlxsw_sp_rif_alloc(sizeof(*ul_rif), rif_index, vr->id, NULL);
7722 if (!ul_rif)
7723 return ERR_PTR(-ENOMEM);
7724
7725 mlxsw_sp->router->rifs[rif_index] = ul_rif;
7726 ul_rif->mlxsw_sp = mlxsw_sp;
7727 err = mlxsw_sp_rif_ipip_lb_ul_rif_op(ul_rif, true);
7728 if (err)
7729 goto ul_rif_op_err;
7730
7731 return ul_rif;
7732
7733ul_rif_op_err:
7734 mlxsw_sp->router->rifs[rif_index] = NULL;
7735 kfree(ul_rif);
7736 return ERR_PTR(err);
7737}
7738
7739static void mlxsw_sp_ul_rif_destroy(struct mlxsw_sp_rif *ul_rif)
7740{
7741 struct mlxsw_sp *mlxsw_sp = ul_rif->mlxsw_sp;
7742
7743 mlxsw_sp_rif_ipip_lb_ul_rif_op(ul_rif, false);
7744 mlxsw_sp->router->rifs[ul_rif->rif_index] = NULL;
7745 kfree(ul_rif);
7746}
7747
7748static struct mlxsw_sp_rif *
7749mlxsw_sp_ul_rif_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
7750 struct netlink_ext_ack *extack)
7751{
7752 struct mlxsw_sp_vr *vr;
7753 int err;
7754
7755 vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id, extack);
7756 if (IS_ERR(vr))
7757 return ERR_CAST(vr);
7758
7759 if (refcount_inc_not_zero(&vr->ul_rif_refcnt))
7760 return vr->ul_rif;
7761
7762 vr->ul_rif = mlxsw_sp_ul_rif_create(mlxsw_sp, vr, extack);
7763 if (IS_ERR(vr->ul_rif)) {
7764 err = PTR_ERR(vr->ul_rif);
7765 goto err_ul_rif_create;
7766 }
7767
7768 vr->rif_count++;
7769 refcount_set(&vr->ul_rif_refcnt, 1);
7770
7771 return vr->ul_rif;
7772
7773err_ul_rif_create:
7774 mlxsw_sp_vr_put(mlxsw_sp, vr);
7775 return ERR_PTR(err);
7776}
7777
7778static void mlxsw_sp_ul_rif_put(struct mlxsw_sp_rif *ul_rif)
7779{
7780 struct mlxsw_sp *mlxsw_sp = ul_rif->mlxsw_sp;
7781 struct mlxsw_sp_vr *vr;
7782
7783 vr = &mlxsw_sp->router->vrs[ul_rif->vr_id];
7784
7785 if (!refcount_dec_and_test(&vr->ul_rif_refcnt))
7786 return;
7787
7788 vr->rif_count--;
7789 mlxsw_sp_ul_rif_destroy(ul_rif);
7790 mlxsw_sp_vr_put(mlxsw_sp, vr);
7791}
7792
eff42aa9
IS
7793int mlxsw_sp_router_ul_rif_get(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
7794 u16 *ul_rif_index)
7795{
7796 struct mlxsw_sp_rif *ul_rif;
7797
7798 ASSERT_RTNL();
7799
7800 ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, NULL);
7801 if (IS_ERR(ul_rif))
7802 return PTR_ERR(ul_rif);
7803 *ul_rif_index = ul_rif->rif_index;
7804
7805 return 0;
7806}
7807
7808void mlxsw_sp_router_ul_rif_put(struct mlxsw_sp *mlxsw_sp, u16 ul_rif_index)
7809{
7810 struct mlxsw_sp_rif *ul_rif;
7811
7812 ASSERT_RTNL();
7813
7814 ul_rif = mlxsw_sp->router->rifs[ul_rif_index];
7815 if (WARN_ON(!ul_rif))
7816 return;
7817
7818 mlxsw_sp_ul_rif_put(ul_rif);
7819}
7820
99974468
ND
7821static int
7822mlxsw_sp2_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif)
7823{
a5040a90
ND
7824 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
7825 u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(rif->dev);
7826 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7827 struct mlxsw_sp_rif *ul_rif;
7828 int err;
7829
7830 ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, NULL);
7831 if (IS_ERR(ul_rif))
7832 return PTR_ERR(ul_rif);
7833
7834 err = mlxsw_sp_rif_ipip_lb_op(lb_rif, 0, ul_rif->rif_index, true);
7835 if (err)
7836 goto err_loopback_op;
7837
7838 lb_rif->ul_vr_id = 0;
7839 lb_rif->ul_rif_id = ul_rif->rif_index;
7840
99974468 7841 return 0;
a5040a90
ND
7842
7843err_loopback_op:
7844 mlxsw_sp_ul_rif_put(ul_rif);
7845 return err;
99974468
ND
7846}
7847
7848static void mlxsw_sp2_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif *rif)
7849{
a5040a90
ND
7850 struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
7851 struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
7852 struct mlxsw_sp_rif *ul_rif;
7853
7854 ul_rif = mlxsw_sp_rif_by_index(mlxsw_sp, lb_rif->ul_rif_id);
7855 mlxsw_sp_rif_ipip_lb_op(lb_rif, 0, lb_rif->ul_rif_id, false);
7856 mlxsw_sp_ul_rif_put(ul_rif);
99974468
ND
7857}
7858
7859static const struct mlxsw_sp_rif_ops mlxsw_sp2_rif_ipip_lb_ops = {
7860 .type = MLXSW_SP_RIF_TYPE_IPIP_LB,
7861 .rif_size = sizeof(struct mlxsw_sp_rif_ipip_lb),
7862 .setup = mlxsw_sp_rif_ipip_lb_setup,
7863 .configure = mlxsw_sp2_rif_ipip_lb_configure,
7864 .deconfigure = mlxsw_sp2_rif_ipip_lb_deconfigure,
7865};
7866
7867const struct mlxsw_sp_rif_ops *mlxsw_sp2_rif_ops_arr[] = {
7868 [MLXSW_SP_RIF_TYPE_SUBPORT] = &mlxsw_sp_rif_subport_ops,
7869 [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp_rif_vlan_emu_ops,
7870 [MLXSW_SP_RIF_TYPE_FID] = &mlxsw_sp_rif_fid_ops,
7871 [MLXSW_SP_RIF_TYPE_IPIP_LB] = &mlxsw_sp2_rif_ipip_lb_ops,
e4f3c1c1
IS
7872};
7873
348b8fc3
IS
7874static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
7875{
7876 u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
7877
7878 mlxsw_sp->router->rifs = kcalloc(max_rifs,
7879 sizeof(struct mlxsw_sp_rif *),
7880 GFP_KERNEL);
7881 if (!mlxsw_sp->router->rifs)
7882 return -ENOMEM;
e4f3c1c1 7883
348b8fc3
IS
7884 return 0;
7885}
7886
7887static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp)
7888{
7889 int i;
7890
7891 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
7892 WARN_ON_ONCE(mlxsw_sp->router->rifs[i]);
7893
7894 kfree(mlxsw_sp->router->rifs);
7895}
7896
dcbda282
PM
7897static int
7898mlxsw_sp_ipip_config_tigcr(struct mlxsw_sp *mlxsw_sp)
7899{
7900 char tigcr_pl[MLXSW_REG_TIGCR_LEN];
7901
7902 mlxsw_reg_tigcr_pack(tigcr_pl, true, 0);
7903 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tigcr), tigcr_pl);
7904}
7905
38ebc0f4
PM
7906static int mlxsw_sp_ipips_init(struct mlxsw_sp *mlxsw_sp)
7907{
4a44ee67
AC
7908 int err;
7909
38ebc0f4 7910 mlxsw_sp->router->ipip_ops_arr = mlxsw_sp_ipip_ops_arr;
1012b9ac 7911 INIT_LIST_HEAD(&mlxsw_sp->router->ipip_list);
4a44ee67
AC
7912
7913 err = mlxsw_sp_ipip_ecn_encap_init(mlxsw_sp);
7914 if (err)
7915 return err;
7916 err = mlxsw_sp_ipip_ecn_decap_init(mlxsw_sp);
7917 if (err)
7918 return err;
7919
dcbda282 7920 return mlxsw_sp_ipip_config_tigcr(mlxsw_sp);
38ebc0f4
PM
7921}
7922
7923static void mlxsw_sp_ipips_fini(struct mlxsw_sp *mlxsw_sp)
7924{
1012b9ac 7925 WARN_ON(!list_empty(&mlxsw_sp->router->ipip_list));
38ebc0f4
PM
7926}
7927
c3852ef7
IS
7928static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
7929{
7e39d115 7930 struct mlxsw_sp_router *router;
c3852ef7
IS
7931
7932 /* Flush pending FIB notifications and then flush the device's
7933 * table before requesting another dump. The FIB notification
7934 * block is unregistered, so no need to take RTNL.
7935 */
7936 mlxsw_core_flush_owq();
7e39d115
IS
7937 router = container_of(nb, struct mlxsw_sp_router, fib_nb);
7938 mlxsw_sp_router_fib_flush(router->mlxsw_sp);
c3852ef7
IS
7939}
7940
af658b6a
IS
7941#ifdef CONFIG_IP_ROUTE_MULTIPATH
7942static void mlxsw_sp_mp_hash_header_set(char *recr2_pl, int header)
7943{
7944 mlxsw_reg_recr2_outer_header_enables_set(recr2_pl, header, true);
7945}
7946
7947static void mlxsw_sp_mp_hash_field_set(char *recr2_pl, int field)
7948{
7949 mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, field, true);
7950}
7951
053e92aa 7952static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl)
af658b6a 7953{
053e92aa
JP
7954 struct net *net = mlxsw_sp_net(mlxsw_sp);
7955 bool only_l3 = !net->ipv4.sysctl_fib_multipath_hash_policy;
af658b6a
IS
7956
7957 mlxsw_sp_mp_hash_header_set(recr2_pl,
7958 MLXSW_REG_RECR2_IPV4_EN_NOT_TCP_NOT_UDP);
7959 mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV4_EN_TCP_UDP);
7960 mlxsw_reg_recr2_ipv4_sip_enable(recr2_pl);
7961 mlxsw_reg_recr2_ipv4_dip_enable(recr2_pl);
7962 if (only_l3)
7963 return;
7964 mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_EN_IPV4);
7965 mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV4_PROTOCOL);
7966 mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_SPORT);
7967 mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_DPORT);
7968}
7969
053e92aa 7970static void mlxsw_sp_mp6_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl)
af658b6a 7971{
053e92aa 7972 bool only_l3 = !ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp));
5e18b9c5 7973
af658b6a
IS
7974 mlxsw_sp_mp_hash_header_set(recr2_pl,
7975 MLXSW_REG_RECR2_IPV6_EN_NOT_TCP_NOT_UDP);
7976 mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV6_EN_TCP_UDP);
7977 mlxsw_reg_recr2_ipv6_sip_enable(recr2_pl);
7978 mlxsw_reg_recr2_ipv6_dip_enable(recr2_pl);
af658b6a 7979 mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV6_NEXT_HEADER);
5e18b9c5
DA
7980 if (only_l3) {
7981 mlxsw_sp_mp_hash_field_set(recr2_pl,
7982 MLXSW_REG_RECR2_IPV6_FLOW_LABEL);
7983 } else {
7984 mlxsw_sp_mp_hash_header_set(recr2_pl,
7985 MLXSW_REG_RECR2_TCP_UDP_EN_IPV6);
7986 mlxsw_sp_mp_hash_field_set(recr2_pl,
7987 MLXSW_REG_RECR2_TCP_UDP_SPORT);
7988 mlxsw_sp_mp_hash_field_set(recr2_pl,
7989 MLXSW_REG_RECR2_TCP_UDP_DPORT);
7990 }
af658b6a
IS
7991}
7992
7993static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp)
7994{
7995 char recr2_pl[MLXSW_REG_RECR2_LEN];
7996 u32 seed;
7997
fa73989f 7998 seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0);
af658b6a 7999 mlxsw_reg_recr2_pack(recr2_pl, seed);
053e92aa
JP
8000 mlxsw_sp_mp4_hash_init(mlxsw_sp, recr2_pl);
8001 mlxsw_sp_mp6_hash_init(mlxsw_sp, recr2_pl);
af658b6a
IS
8002
8003 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(recr2), recr2_pl);
8004}
8005#else
8006static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp)
8007{
8008 return 0;
8009}
8010#endif
8011
48276a29
YM
8012static int mlxsw_sp_dscp_init(struct mlxsw_sp *mlxsw_sp)
8013{
8014 char rdpm_pl[MLXSW_REG_RDPM_LEN];
8015 unsigned int i;
8016
8017 MLXSW_REG_ZERO(rdpm, rdpm_pl);
8018
8019 /* HW is determining switch priority based on DSCP-bits, but the
8020 * kernel is still doing that based on the ToS. Since there's a
8021 * mismatch in bits we need to make sure to translate the right
8022 * value ToS would observe, skipping the 2 least-significant ECN bits.
8023 */
8024 for (i = 0; i < MLXSW_REG_RDPM_DSCP_ENTRY_REC_MAX_COUNT; i++)
8025 mlxsw_reg_rdpm_pack(rdpm_pl, i, rt_tos2priority(i << 2));
8026
8027 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rdpm), rdpm_pl);
8028}
8029
4724ba56
IS
8030static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
8031{
053e92aa
JP
8032 struct net *net = mlxsw_sp_net(mlxsw_sp);
8033 bool usp = net->ipv4.sysctl_ip_fwd_update_priority;
4724ba56
IS
8034 char rgcr_pl[MLXSW_REG_RGCR_LEN];
8035 u64 max_rifs;
8036 int err;
8037
8038 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_RIFS))
8039 return -EIO;
4724ba56 8040 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
4724ba56 8041
e29237e7 8042 mlxsw_reg_rgcr_pack(rgcr_pl, true, true);
4724ba56 8043 mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, max_rifs);
64953423 8044 mlxsw_reg_rgcr_usp_set(rgcr_pl, usp);
4724ba56
IS
8045 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
8046 if (err)
348b8fc3 8047 return err;
4724ba56 8048 return 0;
4724ba56
IS
8049}
8050
8051static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
8052{
8053 char rgcr_pl[MLXSW_REG_RGCR_LEN];
4724ba56 8054
e29237e7 8055 mlxsw_reg_rgcr_pack(rgcr_pl, false, false);
4724ba56 8056 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
4724ba56
IS
8057}
8058
5bcfb6a4
JP
8059int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
8060 struct netlink_ext_ack *extack)
b45f64d1 8061{
9011b677 8062 struct mlxsw_sp_router *router;
b45f64d1
JP
8063 int err;
8064
9011b677
IS
8065 router = kzalloc(sizeof(*mlxsw_sp->router), GFP_KERNEL);
8066 if (!router)
8067 return -ENOMEM;
8068 mlxsw_sp->router = router;
8069 router->mlxsw_sp = mlxsw_sp;
8070
965fa8e6
IS
8071 router->inetaddr_nb.notifier_call = mlxsw_sp_inetaddr_event;
8072 err = register_inetaddr_notifier(&router->inetaddr_nb);
8073 if (err)
8074 goto err_register_inetaddr_notifier;
8075
8076 router->inet6addr_nb.notifier_call = mlxsw_sp_inet6addr_event;
8077 err = register_inet6addr_notifier(&router->inet6addr_nb);
8078 if (err)
8079 goto err_register_inet6addr_notifier;
8080
9011b677 8081 INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list);
b45f64d1
JP
8082 err = __mlxsw_sp_router_init(mlxsw_sp);
8083 if (err)
9011b677 8084 goto err_router_init;
b45f64d1 8085
348b8fc3
IS
8086 err = mlxsw_sp_rifs_init(mlxsw_sp);
8087 if (err)
8088 goto err_rifs_init;
8089
38ebc0f4
PM
8090 err = mlxsw_sp_ipips_init(mlxsw_sp);
8091 if (err)
8092 goto err_ipips_init;
8093
9011b677 8094 err = rhashtable_init(&mlxsw_sp->router->nexthop_ht,
c53b8e1b
IS
8095 &mlxsw_sp_nexthop_ht_params);
8096 if (err)
8097 goto err_nexthop_ht_init;
8098
9011b677 8099 err = rhashtable_init(&mlxsw_sp->router->nexthop_group_ht,
e9ad5e7d
IS
8100 &mlxsw_sp_nexthop_group_ht_params);
8101 if (err)
8102 goto err_nexthop_group_ht_init;
8103
dbe4598c 8104 INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_list);
8494ab06
IS
8105 err = mlxsw_sp_lpm_init(mlxsw_sp);
8106 if (err)
8107 goto err_lpm_init;
8108
d42b0965
YG
8109 err = mlxsw_sp_mr_init(mlxsw_sp, &mlxsw_sp_mr_tcam_ops);
8110 if (err)
8111 goto err_mr_init;
8112
b45f64d1
JP
8113 err = mlxsw_sp_vrs_init(mlxsw_sp);
8114 if (err)
8115 goto err_vrs_init;
8116
8c9583a8 8117 err = mlxsw_sp_neigh_init(mlxsw_sp);
b45f64d1
JP
8118 if (err)
8119 goto err_neigh_init;
8120
48fac885
IS
8121 mlxsw_sp->router->netevent_nb.notifier_call =
8122 mlxsw_sp_router_netevent_event;
8123 err = register_netevent_notifier(&mlxsw_sp->router->netevent_nb);
8124 if (err)
8125 goto err_register_netevent_notifier;
8126
af658b6a
IS
8127 err = mlxsw_sp_mp_hash_init(mlxsw_sp);
8128 if (err)
8129 goto err_mp_hash_init;
8130
48276a29
YM
8131 err = mlxsw_sp_dscp_init(mlxsw_sp);
8132 if (err)
8133 goto err_dscp_init;
8134
7e39d115 8135 mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event;
053e92aa
JP
8136 err = register_fib_notifier(mlxsw_sp_net(mlxsw_sp),
8137 &mlxsw_sp->router->fib_nb,
5bcfb6a4 8138 mlxsw_sp_router_fib_dump_flush, extack);
c3852ef7
IS
8139 if (err)
8140 goto err_register_fib_notifier;
8141
b45f64d1
JP
8142 return 0;
8143
c3852ef7 8144err_register_fib_notifier:
48276a29 8145err_dscp_init:
af658b6a 8146err_mp_hash_init:
48fac885
IS
8147 unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb);
8148err_register_netevent_notifier:
c3852ef7 8149 mlxsw_sp_neigh_fini(mlxsw_sp);
b45f64d1
JP
8150err_neigh_init:
8151 mlxsw_sp_vrs_fini(mlxsw_sp);
8152err_vrs_init:
d42b0965
YG
8153 mlxsw_sp_mr_fini(mlxsw_sp);
8154err_mr_init:
8494ab06
IS
8155 mlxsw_sp_lpm_fini(mlxsw_sp);
8156err_lpm_init:
9011b677 8157 rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht);
e9ad5e7d 8158err_nexthop_group_ht_init:
9011b677 8159 rhashtable_destroy(&mlxsw_sp->router->nexthop_ht);
c53b8e1b 8160err_nexthop_ht_init:
38ebc0f4
PM
8161 mlxsw_sp_ipips_fini(mlxsw_sp);
8162err_ipips_init:
348b8fc3
IS
8163 mlxsw_sp_rifs_fini(mlxsw_sp);
8164err_rifs_init:
b45f64d1 8165 __mlxsw_sp_router_fini(mlxsw_sp);
9011b677 8166err_router_init:
965fa8e6
IS
8167 unregister_inet6addr_notifier(&router->inet6addr_nb);
8168err_register_inet6addr_notifier:
8169 unregister_inetaddr_notifier(&router->inetaddr_nb);
8170err_register_inetaddr_notifier:
9011b677 8171 kfree(mlxsw_sp->router);
b45f64d1
JP
8172 return err;
8173}
8174
8175void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
8176{
053e92aa
JP
8177 unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp),
8178 &mlxsw_sp->router->fib_nb);
48fac885 8179 unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb);
b45f64d1
JP
8180 mlxsw_sp_neigh_fini(mlxsw_sp);
8181 mlxsw_sp_vrs_fini(mlxsw_sp);
d42b0965 8182 mlxsw_sp_mr_fini(mlxsw_sp);
8494ab06 8183 mlxsw_sp_lpm_fini(mlxsw_sp);
9011b677
IS
8184 rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht);
8185 rhashtable_destroy(&mlxsw_sp->router->nexthop_ht);
38ebc0f4 8186 mlxsw_sp_ipips_fini(mlxsw_sp);
348b8fc3 8187 mlxsw_sp_rifs_fini(mlxsw_sp);
b45f64d1 8188 __mlxsw_sp_router_fini(mlxsw_sp);
965fa8e6
IS
8189 unregister_inet6addr_notifier(&mlxsw_sp->router->inet6addr_nb);
8190 unregister_inetaddr_notifier(&mlxsw_sp->router->inetaddr_nb);
9011b677 8191 kfree(mlxsw_sp->router);
b45f64d1 8192}