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