2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
3 * Copyright (c) 2016-2017 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5 * Copyright (c) 2016 Ido Schimmel <idosch@mellanox.com>
6 * Copyright (c) 2016 Yotam Gigi <yotamg@mellanox.com>
7 * Copyright (c) 2017 Petr Machata <petrm@mellanox.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
21 * Alternatively, this software may be distributed under the terms of the
22 * GNU General Public License ("GPL") version 2 as published by the Free
23 * Software Foundation.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
38 #include <linux/kernel.h>
39 #include <linux/types.h>
40 #include <linux/rhashtable.h>
41 #include <linux/bitops.h>
42 #include <linux/in6.h>
43 #include <linux/notifier.h>
44 #include <linux/inetdevice.h>
45 #include <linux/netdevice.h>
46 #include <linux/if_bridge.h>
47 #include <linux/socket.h>
48 #include <linux/route.h>
49 #include <net/netevent.h>
50 #include <net/neighbour.h>
52 #include <net/ip_fib.h>
53 #include <net/ip6_fib.h>
54 #include <net/fib_rules.h>
55 #include <net/ip_tunnels.h>
56 #include <net/l3mdev.h>
57 #include <net/addrconf.h>
58 #include <net/ndisc.h>
60 #include <net/fib_notifier.h>
65 #include "spectrum_cnt.h"
66 #include "spectrum_dpipe.h"
67 #include "spectrum_ipip.h"
68 #include "spectrum_router.h"
71 struct mlxsw_sp_lpm_tree
;
72 struct mlxsw_sp_rif_ops
;
74 struct mlxsw_sp_router
{
75 struct mlxsw_sp
*mlxsw_sp
;
76 struct mlxsw_sp_rif
**rifs
;
77 struct mlxsw_sp_vr
*vrs
;
78 struct rhashtable neigh_ht
;
79 struct rhashtable nexthop_group_ht
;
80 struct rhashtable nexthop_ht
;
82 struct mlxsw_sp_lpm_tree
*trees
;
83 unsigned int tree_count
;
86 struct delayed_work dw
;
87 unsigned long interval
; /* ms */
89 struct delayed_work nexthop_probe_dw
;
90 #define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */
91 struct list_head nexthop_neighs_list
;
92 struct list_head ipip_list
;
94 struct notifier_block fib_nb
;
95 const struct mlxsw_sp_rif_ops
**rif_ops_arr
;
96 const struct mlxsw_sp_ipip_ops
**ipip_ops_arr
;
100 struct list_head nexthop_list
;
101 struct list_head neigh_list
;
102 struct net_device
*dev
;
103 struct mlxsw_sp_fid
*fid
;
104 unsigned char addr
[ETH_ALEN
];
108 const struct mlxsw_sp_rif_ops
*ops
;
109 struct mlxsw_sp
*mlxsw_sp
;
111 unsigned int counter_ingress
;
112 bool counter_ingress_valid
;
113 unsigned int counter_egress
;
114 bool counter_egress_valid
;
117 struct mlxsw_sp_rif_params
{
118 struct net_device
*dev
;
127 struct mlxsw_sp_rif_subport
{
128 struct mlxsw_sp_rif common
;
137 struct mlxsw_sp_rif_ipip_lb
{
138 struct mlxsw_sp_rif common
;
139 struct mlxsw_sp_rif_ipip_lb_config lb_config
;
140 u16 ul_vr_id
; /* Reserved for Spectrum-2. */
143 struct mlxsw_sp_rif_params_ipip_lb
{
144 struct mlxsw_sp_rif_params common
;
145 struct mlxsw_sp_rif_ipip_lb_config lb_config
;
148 struct mlxsw_sp_rif_ops
{
149 enum mlxsw_sp_rif_type type
;
152 void (*setup
)(struct mlxsw_sp_rif
*rif
,
153 const struct mlxsw_sp_rif_params
*params
);
154 int (*configure
)(struct mlxsw_sp_rif
*rif
);
155 void (*deconfigure
)(struct mlxsw_sp_rif
*rif
);
156 struct mlxsw_sp_fid
* (*fid_get
)(struct mlxsw_sp_rif
*rif
);
159 static unsigned int *
160 mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif
*rif
,
161 enum mlxsw_sp_rif_counter_dir dir
)
164 case MLXSW_SP_RIF_COUNTER_EGRESS
:
165 return &rif
->counter_egress
;
166 case MLXSW_SP_RIF_COUNTER_INGRESS
:
167 return &rif
->counter_ingress
;
173 mlxsw_sp_rif_counter_valid_get(struct mlxsw_sp_rif
*rif
,
174 enum mlxsw_sp_rif_counter_dir dir
)
177 case MLXSW_SP_RIF_COUNTER_EGRESS
:
178 return rif
->counter_egress_valid
;
179 case MLXSW_SP_RIF_COUNTER_INGRESS
:
180 return rif
->counter_ingress_valid
;
186 mlxsw_sp_rif_counter_valid_set(struct mlxsw_sp_rif
*rif
,
187 enum mlxsw_sp_rif_counter_dir dir
,
191 case MLXSW_SP_RIF_COUNTER_EGRESS
:
192 rif
->counter_egress_valid
= valid
;
194 case MLXSW_SP_RIF_COUNTER_INGRESS
:
195 rif
->counter_ingress_valid
= valid
;
200 static int mlxsw_sp_rif_counter_edit(struct mlxsw_sp
*mlxsw_sp
, u16 rif_index
,
201 unsigned int counter_index
, bool enable
,
202 enum mlxsw_sp_rif_counter_dir dir
)
204 char ritr_pl
[MLXSW_REG_RITR_LEN
];
205 bool is_egress
= false;
208 if (dir
== MLXSW_SP_RIF_COUNTER_EGRESS
)
210 mlxsw_reg_ritr_rif_pack(ritr_pl
, rif_index
);
211 err
= mlxsw_reg_query(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
215 mlxsw_reg_ritr_counter_pack(ritr_pl
, counter_index
, enable
,
217 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
220 int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp
*mlxsw_sp
,
221 struct mlxsw_sp_rif
*rif
,
222 enum mlxsw_sp_rif_counter_dir dir
, u64
*cnt
)
224 char ricnt_pl
[MLXSW_REG_RICNT_LEN
];
225 unsigned int *p_counter_index
;
229 valid
= mlxsw_sp_rif_counter_valid_get(rif
, dir
);
233 p_counter_index
= mlxsw_sp_rif_p_counter_get(rif
, dir
);
234 if (!p_counter_index
)
236 mlxsw_reg_ricnt_pack(ricnt_pl
, *p_counter_index
,
237 MLXSW_REG_RICNT_OPCODE_NOP
);
238 err
= mlxsw_reg_query(mlxsw_sp
->core
, MLXSW_REG(ricnt
), ricnt_pl
);
241 *cnt
= mlxsw_reg_ricnt_good_unicast_packets_get(ricnt_pl
);
245 static int mlxsw_sp_rif_counter_clear(struct mlxsw_sp
*mlxsw_sp
,
246 unsigned int counter_index
)
248 char ricnt_pl
[MLXSW_REG_RICNT_LEN
];
250 mlxsw_reg_ricnt_pack(ricnt_pl
, counter_index
,
251 MLXSW_REG_RICNT_OPCODE_CLEAR
);
252 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ricnt
), ricnt_pl
);
255 int mlxsw_sp_rif_counter_alloc(struct mlxsw_sp
*mlxsw_sp
,
256 struct mlxsw_sp_rif
*rif
,
257 enum mlxsw_sp_rif_counter_dir dir
)
259 unsigned int *p_counter_index
;
262 p_counter_index
= mlxsw_sp_rif_p_counter_get(rif
, dir
);
263 if (!p_counter_index
)
265 err
= mlxsw_sp_counter_alloc(mlxsw_sp
, MLXSW_SP_COUNTER_SUB_POOL_RIF
,
270 err
= mlxsw_sp_rif_counter_clear(mlxsw_sp
, *p_counter_index
);
272 goto err_counter_clear
;
274 err
= mlxsw_sp_rif_counter_edit(mlxsw_sp
, rif
->rif_index
,
275 *p_counter_index
, true, dir
);
277 goto err_counter_edit
;
278 mlxsw_sp_rif_counter_valid_set(rif
, dir
, true);
283 mlxsw_sp_counter_free(mlxsw_sp
, MLXSW_SP_COUNTER_SUB_POOL_RIF
,
288 void mlxsw_sp_rif_counter_free(struct mlxsw_sp
*mlxsw_sp
,
289 struct mlxsw_sp_rif
*rif
,
290 enum mlxsw_sp_rif_counter_dir dir
)
292 unsigned int *p_counter_index
;
294 if (!mlxsw_sp_rif_counter_valid_get(rif
, dir
))
297 p_counter_index
= mlxsw_sp_rif_p_counter_get(rif
, dir
);
298 if (WARN_ON(!p_counter_index
))
300 mlxsw_sp_rif_counter_edit(mlxsw_sp
, rif
->rif_index
,
301 *p_counter_index
, false, dir
);
302 mlxsw_sp_counter_free(mlxsw_sp
, MLXSW_SP_COUNTER_SUB_POOL_RIF
,
304 mlxsw_sp_rif_counter_valid_set(rif
, dir
, false);
307 static void mlxsw_sp_rif_counters_alloc(struct mlxsw_sp_rif
*rif
)
309 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
310 struct devlink
*devlink
;
312 devlink
= priv_to_devlink(mlxsw_sp
->core
);
313 if (!devlink_dpipe_table_counter_enabled(devlink
,
314 MLXSW_SP_DPIPE_TABLE_NAME_ERIF
))
316 mlxsw_sp_rif_counter_alloc(mlxsw_sp
, rif
, MLXSW_SP_RIF_COUNTER_EGRESS
);
319 static void mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif
*rif
)
321 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
323 mlxsw_sp_rif_counter_free(mlxsw_sp
, rif
, MLXSW_SP_RIF_COUNTER_EGRESS
);
326 static struct mlxsw_sp_rif
*
327 mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp
*mlxsw_sp
,
328 const struct net_device
*dev
);
330 #define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE + 1)
332 struct mlxsw_sp_prefix_usage
{
333 DECLARE_BITMAP(b
, MLXSW_SP_PREFIX_COUNT
);
336 #define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \
337 for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
340 mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage
*prefix_usage1
,
341 struct mlxsw_sp_prefix_usage
*prefix_usage2
)
343 return !memcmp(prefix_usage1
, prefix_usage2
, sizeof(*prefix_usage1
));
347 mlxsw_sp_prefix_usage_none(struct mlxsw_sp_prefix_usage
*prefix_usage
)
349 struct mlxsw_sp_prefix_usage prefix_usage_none
= {{ 0 } };
351 return mlxsw_sp_prefix_usage_eq(prefix_usage
, &prefix_usage_none
);
355 mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage
*prefix_usage1
,
356 struct mlxsw_sp_prefix_usage
*prefix_usage2
)
358 memcpy(prefix_usage1
, prefix_usage2
, sizeof(*prefix_usage1
));
362 mlxsw_sp_prefix_usage_set(struct mlxsw_sp_prefix_usage
*prefix_usage
,
363 unsigned char prefix_len
)
365 set_bit(prefix_len
, prefix_usage
->b
);
369 mlxsw_sp_prefix_usage_clear(struct mlxsw_sp_prefix_usage
*prefix_usage
,
370 unsigned char prefix_len
)
372 clear_bit(prefix_len
, prefix_usage
->b
);
375 struct mlxsw_sp_fib_key
{
376 unsigned char addr
[sizeof(struct in6_addr
)];
377 unsigned char prefix_len
;
380 enum mlxsw_sp_fib_entry_type
{
381 MLXSW_SP_FIB_ENTRY_TYPE_REMOTE
,
382 MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
,
383 MLXSW_SP_FIB_ENTRY_TYPE_TRAP
,
386 struct mlxsw_sp_nexthop_group
;
389 struct mlxsw_sp_fib_node
{
390 struct list_head entry_list
;
391 struct list_head list
;
392 struct rhash_head ht_node
;
393 struct mlxsw_sp_fib
*fib
;
394 struct mlxsw_sp_fib_key key
;
397 struct mlxsw_sp_fib_entry
{
398 struct list_head list
;
399 struct mlxsw_sp_fib_node
*fib_node
;
400 enum mlxsw_sp_fib_entry_type type
;
401 struct list_head nexthop_group_node
;
402 struct mlxsw_sp_nexthop_group
*nh_group
;
405 struct mlxsw_sp_fib4_entry
{
406 struct mlxsw_sp_fib_entry common
;
413 struct mlxsw_sp_fib6_entry
{
414 struct mlxsw_sp_fib_entry common
;
415 struct list_head rt6_list
;
419 struct mlxsw_sp_rt6
{
420 struct list_head list
;
424 struct mlxsw_sp_lpm_tree
{
426 unsigned int ref_count
;
427 enum mlxsw_sp_l3proto proto
;
428 struct mlxsw_sp_prefix_usage prefix_usage
;
431 struct mlxsw_sp_fib
{
432 struct rhashtable ht
;
433 struct list_head node_list
;
434 struct mlxsw_sp_vr
*vr
;
435 struct mlxsw_sp_lpm_tree
*lpm_tree
;
436 unsigned long prefix_ref_count
[MLXSW_SP_PREFIX_COUNT
];
437 struct mlxsw_sp_prefix_usage prefix_usage
;
438 enum mlxsw_sp_l3proto proto
;
442 u16 id
; /* virtual router ID */
443 u32 tb_id
; /* kernel fib table id */
444 unsigned int rif_count
;
445 struct mlxsw_sp_fib
*fib4
;
446 struct mlxsw_sp_fib
*fib6
;
449 static const struct rhashtable_params mlxsw_sp_fib_ht_params
;
451 static struct mlxsw_sp_fib
*mlxsw_sp_fib_create(struct mlxsw_sp_vr
*vr
,
452 enum mlxsw_sp_l3proto proto
)
454 struct mlxsw_sp_fib
*fib
;
457 fib
= kzalloc(sizeof(*fib
), GFP_KERNEL
);
459 return ERR_PTR(-ENOMEM
);
460 err
= rhashtable_init(&fib
->ht
, &mlxsw_sp_fib_ht_params
);
462 goto err_rhashtable_init
;
463 INIT_LIST_HEAD(&fib
->node_list
);
473 static void mlxsw_sp_fib_destroy(struct mlxsw_sp_fib
*fib
)
475 WARN_ON(!list_empty(&fib
->node_list
));
476 WARN_ON(fib
->lpm_tree
);
477 rhashtable_destroy(&fib
->ht
);
481 static struct mlxsw_sp_lpm_tree
*
482 mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp
*mlxsw_sp
)
484 static struct mlxsw_sp_lpm_tree
*lpm_tree
;
487 for (i
= 0; i
< mlxsw_sp
->router
->lpm
.tree_count
; i
++) {
488 lpm_tree
= &mlxsw_sp
->router
->lpm
.trees
[i
];
489 if (lpm_tree
->ref_count
== 0)
495 static int mlxsw_sp_lpm_tree_alloc(struct mlxsw_sp
*mlxsw_sp
,
496 struct mlxsw_sp_lpm_tree
*lpm_tree
)
498 char ralta_pl
[MLXSW_REG_RALTA_LEN
];
500 mlxsw_reg_ralta_pack(ralta_pl
, true,
501 (enum mlxsw_reg_ralxx_protocol
) lpm_tree
->proto
,
503 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralta
), ralta_pl
);
506 static void mlxsw_sp_lpm_tree_free(struct mlxsw_sp
*mlxsw_sp
,
507 struct mlxsw_sp_lpm_tree
*lpm_tree
)
509 char ralta_pl
[MLXSW_REG_RALTA_LEN
];
511 mlxsw_reg_ralta_pack(ralta_pl
, false,
512 (enum mlxsw_reg_ralxx_protocol
) lpm_tree
->proto
,
514 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralta
), ralta_pl
);
518 mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp
*mlxsw_sp
,
519 struct mlxsw_sp_prefix_usage
*prefix_usage
,
520 struct mlxsw_sp_lpm_tree
*lpm_tree
)
522 char ralst_pl
[MLXSW_REG_RALST_LEN
];
525 u8 last_prefix
= MLXSW_REG_RALST_BIN_NO_CHILD
;
527 mlxsw_sp_prefix_usage_for_each(prefix
, prefix_usage
)
530 mlxsw_reg_ralst_pack(ralst_pl
, root_bin
, lpm_tree
->id
);
531 mlxsw_sp_prefix_usage_for_each(prefix
, prefix_usage
) {
534 mlxsw_reg_ralst_bin_pack(ralst_pl
, prefix
, last_prefix
,
535 MLXSW_REG_RALST_BIN_NO_CHILD
);
536 last_prefix
= prefix
;
538 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralst
), ralst_pl
);
541 static struct mlxsw_sp_lpm_tree
*
542 mlxsw_sp_lpm_tree_create(struct mlxsw_sp
*mlxsw_sp
,
543 struct mlxsw_sp_prefix_usage
*prefix_usage
,
544 enum mlxsw_sp_l3proto proto
)
546 struct mlxsw_sp_lpm_tree
*lpm_tree
;
549 lpm_tree
= mlxsw_sp_lpm_tree_find_unused(mlxsw_sp
);
551 return ERR_PTR(-EBUSY
);
552 lpm_tree
->proto
= proto
;
553 err
= mlxsw_sp_lpm_tree_alloc(mlxsw_sp
, lpm_tree
);
557 err
= mlxsw_sp_lpm_tree_left_struct_set(mlxsw_sp
, prefix_usage
,
560 goto err_left_struct_set
;
561 memcpy(&lpm_tree
->prefix_usage
, prefix_usage
,
562 sizeof(lpm_tree
->prefix_usage
));
566 mlxsw_sp_lpm_tree_free(mlxsw_sp
, lpm_tree
);
570 static void mlxsw_sp_lpm_tree_destroy(struct mlxsw_sp
*mlxsw_sp
,
571 struct mlxsw_sp_lpm_tree
*lpm_tree
)
573 mlxsw_sp_lpm_tree_free(mlxsw_sp
, lpm_tree
);
576 static struct mlxsw_sp_lpm_tree
*
577 mlxsw_sp_lpm_tree_get(struct mlxsw_sp
*mlxsw_sp
,
578 struct mlxsw_sp_prefix_usage
*prefix_usage
,
579 enum mlxsw_sp_l3proto proto
)
581 struct mlxsw_sp_lpm_tree
*lpm_tree
;
584 for (i
= 0; i
< mlxsw_sp
->router
->lpm
.tree_count
; i
++) {
585 lpm_tree
= &mlxsw_sp
->router
->lpm
.trees
[i
];
586 if (lpm_tree
->ref_count
!= 0 &&
587 lpm_tree
->proto
== proto
&&
588 mlxsw_sp_prefix_usage_eq(&lpm_tree
->prefix_usage
,
592 return mlxsw_sp_lpm_tree_create(mlxsw_sp
, prefix_usage
, proto
);
595 static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree
*lpm_tree
)
597 lpm_tree
->ref_count
++;
600 static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp
*mlxsw_sp
,
601 struct mlxsw_sp_lpm_tree
*lpm_tree
)
603 if (--lpm_tree
->ref_count
== 0)
604 mlxsw_sp_lpm_tree_destroy(mlxsw_sp
, lpm_tree
);
607 #define MLXSW_SP_LPM_TREE_MIN 1 /* tree 0 is reserved */
609 static int mlxsw_sp_lpm_init(struct mlxsw_sp
*mlxsw_sp
)
611 struct mlxsw_sp_lpm_tree
*lpm_tree
;
615 if (!MLXSW_CORE_RES_VALID(mlxsw_sp
->core
, MAX_LPM_TREES
))
618 max_trees
= MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_LPM_TREES
);
619 mlxsw_sp
->router
->lpm
.tree_count
= max_trees
- MLXSW_SP_LPM_TREE_MIN
;
620 mlxsw_sp
->router
->lpm
.trees
= kcalloc(mlxsw_sp
->router
->lpm
.tree_count
,
621 sizeof(struct mlxsw_sp_lpm_tree
),
623 if (!mlxsw_sp
->router
->lpm
.trees
)
626 for (i
= 0; i
< mlxsw_sp
->router
->lpm
.tree_count
; i
++) {
627 lpm_tree
= &mlxsw_sp
->router
->lpm
.trees
[i
];
628 lpm_tree
->id
= i
+ MLXSW_SP_LPM_TREE_MIN
;
634 static void mlxsw_sp_lpm_fini(struct mlxsw_sp
*mlxsw_sp
)
636 kfree(mlxsw_sp
->router
->lpm
.trees
);
639 static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr
*vr
)
641 return !!vr
->fib4
|| !!vr
->fib6
;
644 static struct mlxsw_sp_vr
*mlxsw_sp_vr_find_unused(struct mlxsw_sp
*mlxsw_sp
)
646 struct mlxsw_sp_vr
*vr
;
649 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
650 vr
= &mlxsw_sp
->router
->vrs
[i
];
651 if (!mlxsw_sp_vr_is_used(vr
))
657 static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp
*mlxsw_sp
,
658 const struct mlxsw_sp_fib
*fib
, u8 tree_id
)
660 char raltb_pl
[MLXSW_REG_RALTB_LEN
];
662 mlxsw_reg_raltb_pack(raltb_pl
, fib
->vr
->id
,
663 (enum mlxsw_reg_ralxx_protocol
) fib
->proto
,
665 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(raltb
), raltb_pl
);
668 static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp
*mlxsw_sp
,
669 const struct mlxsw_sp_fib
*fib
)
671 char raltb_pl
[MLXSW_REG_RALTB_LEN
];
673 /* Bind to tree 0 which is default */
674 mlxsw_reg_raltb_pack(raltb_pl
, fib
->vr
->id
,
675 (enum mlxsw_reg_ralxx_protocol
) fib
->proto
, 0);
676 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(raltb
), raltb_pl
);
679 static u32
mlxsw_sp_fix_tb_id(u32 tb_id
)
681 /* For our purpose, squash main and local table into one */
682 if (tb_id
== RT_TABLE_LOCAL
)
683 tb_id
= RT_TABLE_MAIN
;
687 static struct mlxsw_sp_vr
*mlxsw_sp_vr_find(struct mlxsw_sp
*mlxsw_sp
,
690 struct mlxsw_sp_vr
*vr
;
693 tb_id
= mlxsw_sp_fix_tb_id(tb_id
);
695 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
696 vr
= &mlxsw_sp
->router
->vrs
[i
];
697 if (mlxsw_sp_vr_is_used(vr
) && vr
->tb_id
== tb_id
)
703 static struct mlxsw_sp_fib
*mlxsw_sp_vr_fib(const struct mlxsw_sp_vr
*vr
,
704 enum mlxsw_sp_l3proto proto
)
707 case MLXSW_SP_L3_PROTO_IPV4
:
709 case MLXSW_SP_L3_PROTO_IPV6
:
715 static struct mlxsw_sp_vr
*mlxsw_sp_vr_create(struct mlxsw_sp
*mlxsw_sp
,
718 struct mlxsw_sp_vr
*vr
;
721 vr
= mlxsw_sp_vr_find_unused(mlxsw_sp
);
723 return ERR_PTR(-EBUSY
);
724 vr
->fib4
= mlxsw_sp_fib_create(vr
, MLXSW_SP_L3_PROTO_IPV4
);
725 if (IS_ERR(vr
->fib4
))
726 return ERR_CAST(vr
->fib4
);
727 vr
->fib6
= mlxsw_sp_fib_create(vr
, MLXSW_SP_L3_PROTO_IPV6
);
728 if (IS_ERR(vr
->fib6
)) {
729 err
= PTR_ERR(vr
->fib6
);
730 goto err_fib6_create
;
736 mlxsw_sp_fib_destroy(vr
->fib4
);
741 static void mlxsw_sp_vr_destroy(struct mlxsw_sp_vr
*vr
)
743 mlxsw_sp_fib_destroy(vr
->fib6
);
745 mlxsw_sp_fib_destroy(vr
->fib4
);
749 static struct mlxsw_sp_vr
*mlxsw_sp_vr_get(struct mlxsw_sp
*mlxsw_sp
, u32 tb_id
)
751 struct mlxsw_sp_vr
*vr
;
753 tb_id
= mlxsw_sp_fix_tb_id(tb_id
);
754 vr
= mlxsw_sp_vr_find(mlxsw_sp
, tb_id
);
756 vr
= mlxsw_sp_vr_create(mlxsw_sp
, tb_id
);
760 static void mlxsw_sp_vr_put(struct mlxsw_sp_vr
*vr
)
762 if (!vr
->rif_count
&& list_empty(&vr
->fib4
->node_list
) &&
763 list_empty(&vr
->fib6
->node_list
))
764 mlxsw_sp_vr_destroy(vr
);
768 mlxsw_sp_vr_lpm_tree_should_replace(struct mlxsw_sp_vr
*vr
,
769 enum mlxsw_sp_l3proto proto
, u8 tree_id
)
771 struct mlxsw_sp_fib
*fib
= mlxsw_sp_vr_fib(vr
, proto
);
773 if (!mlxsw_sp_vr_is_used(vr
))
775 if (fib
->lpm_tree
&& fib
->lpm_tree
->id
== tree_id
)
780 static int mlxsw_sp_vr_lpm_tree_replace(struct mlxsw_sp
*mlxsw_sp
,
781 struct mlxsw_sp_fib
*fib
,
782 struct mlxsw_sp_lpm_tree
*new_tree
)
784 struct mlxsw_sp_lpm_tree
*old_tree
= fib
->lpm_tree
;
787 err
= mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp
, fib
, new_tree
->id
);
790 fib
->lpm_tree
= new_tree
;
791 mlxsw_sp_lpm_tree_hold(new_tree
);
792 mlxsw_sp_lpm_tree_put(mlxsw_sp
, old_tree
);
796 static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp
*mlxsw_sp
,
797 struct mlxsw_sp_fib
*fib
,
798 struct mlxsw_sp_lpm_tree
*new_tree
)
800 struct mlxsw_sp_lpm_tree
*old_tree
= fib
->lpm_tree
;
801 enum mlxsw_sp_l3proto proto
= fib
->proto
;
802 u8 old_id
, new_id
= new_tree
->id
;
803 struct mlxsw_sp_vr
*vr
;
808 old_id
= old_tree
->id
;
810 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
811 vr
= &mlxsw_sp
->router
->vrs
[i
];
812 if (!mlxsw_sp_vr_lpm_tree_should_replace(vr
, proto
, old_id
))
814 err
= mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp
,
815 mlxsw_sp_vr_fib(vr
, proto
),
818 goto err_tree_replace
;
824 for (i
--; i
>= 0; i
--) {
825 if (!mlxsw_sp_vr_lpm_tree_should_replace(vr
, proto
, new_id
))
827 mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp
,
828 mlxsw_sp_vr_fib(vr
, proto
),
834 err
= mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp
, fib
, new_tree
->id
);
837 fib
->lpm_tree
= new_tree
;
838 mlxsw_sp_lpm_tree_hold(new_tree
);
843 mlxsw_sp_vrs_prefixes(struct mlxsw_sp
*mlxsw_sp
,
844 enum mlxsw_sp_l3proto proto
,
845 struct mlxsw_sp_prefix_usage
*req_prefix_usage
)
849 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
850 struct mlxsw_sp_vr
*vr
= &mlxsw_sp
->router
->vrs
[i
];
851 struct mlxsw_sp_fib
*fib
= mlxsw_sp_vr_fib(vr
, proto
);
852 unsigned char prefix
;
854 if (!mlxsw_sp_vr_is_used(vr
))
856 mlxsw_sp_prefix_usage_for_each(prefix
, &fib
->prefix_usage
)
857 mlxsw_sp_prefix_usage_set(req_prefix_usage
, prefix
);
861 static int mlxsw_sp_vrs_init(struct mlxsw_sp
*mlxsw_sp
)
863 struct mlxsw_sp_vr
*vr
;
867 if (!MLXSW_CORE_RES_VALID(mlxsw_sp
->core
, MAX_VRS
))
870 max_vrs
= MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
);
871 mlxsw_sp
->router
->vrs
= kcalloc(max_vrs
, sizeof(struct mlxsw_sp_vr
),
873 if (!mlxsw_sp
->router
->vrs
)
876 for (i
= 0; i
< max_vrs
; i
++) {
877 vr
= &mlxsw_sp
->router
->vrs
[i
];
884 static void mlxsw_sp_router_fib_flush(struct mlxsw_sp
*mlxsw_sp
);
886 static void mlxsw_sp_vrs_fini(struct mlxsw_sp
*mlxsw_sp
)
888 /* At this stage we're guaranteed not to have new incoming
889 * FIB notifications and the work queue is free from FIBs
890 * sitting on top of mlxsw netdevs. However, we can still
891 * have other FIBs queued. Flush the queue before flushing
892 * the device's tables. No need for locks, as we're the only
895 mlxsw_core_flush_owq();
896 mlxsw_sp_router_fib_flush(mlxsw_sp
);
897 kfree(mlxsw_sp
->router
->vrs
);
900 static struct net_device
*
901 __mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device
*ol_dev
)
903 struct ip_tunnel
*tun
= netdev_priv(ol_dev
);
904 struct net
*net
= dev_net(ol_dev
);
906 return __dev_get_by_index(net
, tun
->parms
.link
);
909 static u32
mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device
*ol_dev
)
911 struct net_device
*d
= __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev
);
914 return l3mdev_fib_table(d
) ? : RT_TABLE_MAIN
;
916 return l3mdev_fib_table(ol_dev
) ? : RT_TABLE_MAIN
;
919 static struct mlxsw_sp_rif
*
920 mlxsw_sp_rif_create(struct mlxsw_sp
*mlxsw_sp
,
921 const struct mlxsw_sp_rif_params
*params
);
923 static struct mlxsw_sp_rif_ipip_lb
*
924 mlxsw_sp_ipip_ol_ipip_lb_create(struct mlxsw_sp
*mlxsw_sp
,
925 enum mlxsw_sp_ipip_type ipipt
,
926 struct net_device
*ol_dev
)
928 struct mlxsw_sp_rif_params_ipip_lb lb_params
;
929 const struct mlxsw_sp_ipip_ops
*ipip_ops
;
930 struct mlxsw_sp_rif
*rif
;
932 ipip_ops
= mlxsw_sp
->router
->ipip_ops_arr
[ipipt
];
933 lb_params
= (struct mlxsw_sp_rif_params_ipip_lb
) {
934 .common
.dev
= ol_dev
,
936 .lb_config
= ipip_ops
->ol_loopback_config(mlxsw_sp
, ol_dev
),
939 rif
= mlxsw_sp_rif_create(mlxsw_sp
, &lb_params
.common
);
941 return ERR_CAST(rif
);
942 return container_of(rif
, struct mlxsw_sp_rif_ipip_lb
, common
);
945 static struct mlxsw_sp_ipip_entry
*
946 mlxsw_sp_ipip_entry_alloc(struct mlxsw_sp
*mlxsw_sp
,
947 enum mlxsw_sp_ipip_type ipipt
,
948 struct net_device
*ol_dev
)
950 struct mlxsw_sp_ipip_entry
*ipip_entry
;
951 struct mlxsw_sp_ipip_entry
*ret
= NULL
;
953 ipip_entry
= kzalloc(sizeof(*ipip_entry
), GFP_KERNEL
);
955 return ERR_PTR(-ENOMEM
);
957 ipip_entry
->ol_lb
= mlxsw_sp_ipip_ol_ipip_lb_create(mlxsw_sp
, ipipt
,
959 if (IS_ERR(ipip_entry
->ol_lb
)) {
960 ret
= ERR_CAST(ipip_entry
->ol_lb
);
961 goto err_ol_ipip_lb_create
;
964 ipip_entry
->ipipt
= ipipt
;
965 ipip_entry
->ol_dev
= ol_dev
;
969 err_ol_ipip_lb_create
:
975 mlxsw_sp_ipip_entry_destroy(struct mlxsw_sp_ipip_entry
*ipip_entry
)
977 WARN_ON(ipip_entry
->ref_count
> 0);
978 mlxsw_sp_rif_destroy(&ipip_entry
->ol_lb
->common
);
983 mlxsw_sp_ipip_netdev_saddr4(const struct net_device
*ol_dev
)
985 struct ip_tunnel
*tun
= netdev_priv(ol_dev
);
987 return tun
->parms
.iph
.saddr
;
990 union mlxsw_sp_l3addr
991 mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto
,
992 const struct net_device
*ol_dev
)
995 case MLXSW_SP_L3_PROTO_IPV4
:
996 return (union mlxsw_sp_l3addr
) {
997 .addr4
= mlxsw_sp_ipip_netdev_saddr4(ol_dev
),
999 case MLXSW_SP_L3_PROTO_IPV6
:
1004 return (union mlxsw_sp_l3addr
) {
1009 static bool mlxsw_sp_l3addr_eq(const union mlxsw_sp_l3addr
*addr1
,
1010 const union mlxsw_sp_l3addr
*addr2
)
1012 return !memcmp(addr1
, addr2
, sizeof(*addr1
));
1016 mlxsw_sp_ipip_entry_saddr_matches(struct mlxsw_sp
*mlxsw_sp
,
1017 const enum mlxsw_sp_l3proto ul_proto
,
1018 union mlxsw_sp_l3addr saddr
,
1020 struct mlxsw_sp_ipip_entry
*ipip_entry
)
1022 u32 tun_ul_tb_id
= mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry
->ol_dev
);
1023 enum mlxsw_sp_ipip_type ipipt
= ipip_entry
->ipipt
;
1024 union mlxsw_sp_l3addr tun_saddr
;
1026 if (mlxsw_sp
->router
->ipip_ops_arr
[ipipt
]->ul_proto
!= ul_proto
)
1029 tun_saddr
= mlxsw_sp_ipip_netdev_saddr(ul_proto
, ipip_entry
->ol_dev
);
1030 return tun_ul_tb_id
== ul_tb_id
&&
1031 mlxsw_sp_l3addr_eq(&tun_saddr
, &saddr
);
1034 static struct mlxsw_sp_ipip_entry
*
1035 mlxsw_sp_ipip_entry_get(struct mlxsw_sp
*mlxsw_sp
,
1036 enum mlxsw_sp_ipip_type ipipt
,
1037 struct net_device
*ol_dev
)
1039 u32 ul_tb_id
= mlxsw_sp_ipip_dev_ul_tb_id(ol_dev
);
1040 struct mlxsw_sp_router
*router
= mlxsw_sp
->router
;
1041 struct mlxsw_sp_ipip_entry
*ipip_entry
;
1042 enum mlxsw_sp_l3proto ul_proto
;
1043 union mlxsw_sp_l3addr saddr
;
1045 list_for_each_entry(ipip_entry
, &mlxsw_sp
->router
->ipip_list
,
1047 if (ipip_entry
->ol_dev
== ol_dev
)
1050 /* The configuration where several tunnels have the same local
1051 * address in the same underlay table needs special treatment in
1052 * the HW. That is currently not implemented in the driver.
1054 ul_proto
= router
->ipip_ops_arr
[ipip_entry
->ipipt
]->ul_proto
;
1055 saddr
= mlxsw_sp_ipip_netdev_saddr(ul_proto
, ol_dev
);
1056 if (mlxsw_sp_ipip_entry_saddr_matches(mlxsw_sp
, ul_proto
, saddr
,
1057 ul_tb_id
, ipip_entry
))
1058 return ERR_PTR(-EEXIST
);
1061 ipip_entry
= mlxsw_sp_ipip_entry_alloc(mlxsw_sp
, ipipt
, ol_dev
);
1062 if (IS_ERR(ipip_entry
))
1065 list_add_tail(&ipip_entry
->ipip_list_node
,
1066 &mlxsw_sp
->router
->ipip_list
);
1069 ++ipip_entry
->ref_count
;
1074 mlxsw_sp_ipip_entry_put(struct mlxsw_sp
*mlxsw_sp
,
1075 struct mlxsw_sp_ipip_entry
*ipip_entry
)
1077 if (--ipip_entry
->ref_count
== 0) {
1078 list_del(&ipip_entry
->ipip_list_node
);
1079 mlxsw_sp_ipip_entry_destroy(ipip_entry
);
1083 struct mlxsw_sp_neigh_key
{
1084 struct neighbour
*n
;
1087 struct mlxsw_sp_neigh_entry
{
1088 struct list_head rif_list_node
;
1089 struct rhash_head ht_node
;
1090 struct mlxsw_sp_neigh_key key
;
1093 unsigned char ha
[ETH_ALEN
];
1094 struct list_head nexthop_list
; /* list of nexthops using
1097 struct list_head nexthop_neighs_list_node
;
1098 unsigned int counter_index
;
1102 static const struct rhashtable_params mlxsw_sp_neigh_ht_params
= {
1103 .key_offset
= offsetof(struct mlxsw_sp_neigh_entry
, key
),
1104 .head_offset
= offsetof(struct mlxsw_sp_neigh_entry
, ht_node
),
1105 .key_len
= sizeof(struct mlxsw_sp_neigh_key
),
1108 struct mlxsw_sp_neigh_entry
*
1109 mlxsw_sp_rif_neigh_next(struct mlxsw_sp_rif
*rif
,
1110 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1113 if (list_empty(&rif
->neigh_list
))
1116 return list_first_entry(&rif
->neigh_list
,
1117 typeof(*neigh_entry
),
1120 if (neigh_entry
->rif_list_node
.next
== &rif
->neigh_list
)
1122 return list_next_entry(neigh_entry
, rif_list_node
);
1125 int mlxsw_sp_neigh_entry_type(struct mlxsw_sp_neigh_entry
*neigh_entry
)
1127 return neigh_entry
->key
.n
->tbl
->family
;
1131 mlxsw_sp_neigh_entry_ha(struct mlxsw_sp_neigh_entry
*neigh_entry
)
1133 return neigh_entry
->ha
;
1136 u32
mlxsw_sp_neigh4_entry_dip(struct mlxsw_sp_neigh_entry
*neigh_entry
)
1138 struct neighbour
*n
;
1140 n
= neigh_entry
->key
.n
;
1141 return ntohl(*((__be32
*) n
->primary_key
));
1145 mlxsw_sp_neigh6_entry_dip(struct mlxsw_sp_neigh_entry
*neigh_entry
)
1147 struct neighbour
*n
;
1149 n
= neigh_entry
->key
.n
;
1150 return (struct in6_addr
*) &n
->primary_key
;
1153 int mlxsw_sp_neigh_counter_get(struct mlxsw_sp
*mlxsw_sp
,
1154 struct mlxsw_sp_neigh_entry
*neigh_entry
,
1157 if (!neigh_entry
->counter_valid
)
1160 return mlxsw_sp_flow_counter_get(mlxsw_sp
, neigh_entry
->counter_index
,
1164 static struct mlxsw_sp_neigh_entry
*
1165 mlxsw_sp_neigh_entry_alloc(struct mlxsw_sp
*mlxsw_sp
, struct neighbour
*n
,
1168 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1170 neigh_entry
= kzalloc(sizeof(*neigh_entry
), GFP_KERNEL
);
1174 neigh_entry
->key
.n
= n
;
1175 neigh_entry
->rif
= rif
;
1176 INIT_LIST_HEAD(&neigh_entry
->nexthop_list
);
1181 static void mlxsw_sp_neigh_entry_free(struct mlxsw_sp_neigh_entry
*neigh_entry
)
1187 mlxsw_sp_neigh_entry_insert(struct mlxsw_sp
*mlxsw_sp
,
1188 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1190 return rhashtable_insert_fast(&mlxsw_sp
->router
->neigh_ht
,
1191 &neigh_entry
->ht_node
,
1192 mlxsw_sp_neigh_ht_params
);
1196 mlxsw_sp_neigh_entry_remove(struct mlxsw_sp
*mlxsw_sp
,
1197 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1199 rhashtable_remove_fast(&mlxsw_sp
->router
->neigh_ht
,
1200 &neigh_entry
->ht_node
,
1201 mlxsw_sp_neigh_ht_params
);
1205 mlxsw_sp_neigh_counter_should_alloc(struct mlxsw_sp
*mlxsw_sp
,
1206 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1208 struct devlink
*devlink
;
1209 const char *table_name
;
1211 switch (mlxsw_sp_neigh_entry_type(neigh_entry
)) {
1213 table_name
= MLXSW_SP_DPIPE_TABLE_NAME_HOST4
;
1216 table_name
= MLXSW_SP_DPIPE_TABLE_NAME_HOST6
;
1223 devlink
= priv_to_devlink(mlxsw_sp
->core
);
1224 return devlink_dpipe_table_counter_enabled(devlink
, table_name
);
1228 mlxsw_sp_neigh_counter_alloc(struct mlxsw_sp
*mlxsw_sp
,
1229 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1231 if (!mlxsw_sp_neigh_counter_should_alloc(mlxsw_sp
, neigh_entry
))
1234 if (mlxsw_sp_flow_counter_alloc(mlxsw_sp
, &neigh_entry
->counter_index
))
1237 neigh_entry
->counter_valid
= true;
1241 mlxsw_sp_neigh_counter_free(struct mlxsw_sp
*mlxsw_sp
,
1242 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1244 if (!neigh_entry
->counter_valid
)
1246 mlxsw_sp_flow_counter_free(mlxsw_sp
,
1247 neigh_entry
->counter_index
);
1248 neigh_entry
->counter_valid
= false;
1251 static struct mlxsw_sp_neigh_entry
*
1252 mlxsw_sp_neigh_entry_create(struct mlxsw_sp
*mlxsw_sp
, struct neighbour
*n
)
1254 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1255 struct mlxsw_sp_rif
*rif
;
1258 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, n
->dev
);
1260 return ERR_PTR(-EINVAL
);
1262 neigh_entry
= mlxsw_sp_neigh_entry_alloc(mlxsw_sp
, n
, rif
->rif_index
);
1264 return ERR_PTR(-ENOMEM
);
1266 err
= mlxsw_sp_neigh_entry_insert(mlxsw_sp
, neigh_entry
);
1268 goto err_neigh_entry_insert
;
1270 mlxsw_sp_neigh_counter_alloc(mlxsw_sp
, neigh_entry
);
1271 list_add(&neigh_entry
->rif_list_node
, &rif
->neigh_list
);
1275 err_neigh_entry_insert
:
1276 mlxsw_sp_neigh_entry_free(neigh_entry
);
1277 return ERR_PTR(err
);
1281 mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp
*mlxsw_sp
,
1282 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1284 list_del(&neigh_entry
->rif_list_node
);
1285 mlxsw_sp_neigh_counter_free(mlxsw_sp
, neigh_entry
);
1286 mlxsw_sp_neigh_entry_remove(mlxsw_sp
, neigh_entry
);
1287 mlxsw_sp_neigh_entry_free(neigh_entry
);
1290 static struct mlxsw_sp_neigh_entry
*
1291 mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp
*mlxsw_sp
, struct neighbour
*n
)
1293 struct mlxsw_sp_neigh_key key
;
1296 return rhashtable_lookup_fast(&mlxsw_sp
->router
->neigh_ht
,
1297 &key
, mlxsw_sp_neigh_ht_params
);
1301 mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp
*mlxsw_sp
)
1303 unsigned long interval
;
1305 #if IS_ENABLED(CONFIG_IPV6)
1306 interval
= min_t(unsigned long,
1307 NEIGH_VAR(&arp_tbl
.parms
, DELAY_PROBE_TIME
),
1308 NEIGH_VAR(&nd_tbl
.parms
, DELAY_PROBE_TIME
));
1310 interval
= NEIGH_VAR(&arp_tbl
.parms
, DELAY_PROBE_TIME
);
1312 mlxsw_sp
->router
->neighs_update
.interval
= jiffies_to_msecs(interval
);
1315 static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp
*mlxsw_sp
,
1319 struct net_device
*dev
;
1320 struct neighbour
*n
;
1325 mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl
, ent_index
, &rif
, &dip
);
1327 if (!mlxsw_sp
->router
->rifs
[rif
]) {
1328 dev_err_ratelimited(mlxsw_sp
->bus_info
->dev
, "Incorrect RIF in neighbour entry\n");
1333 dev
= mlxsw_sp
->router
->rifs
[rif
]->dev
;
1334 n
= neigh_lookup(&arp_tbl
, &dipn
, dev
);
1336 netdev_err(dev
, "Failed to find matching neighbour for IP=%pI4h\n",
1341 netdev_dbg(dev
, "Updating neighbour with IP=%pI4h\n", &dip
);
1342 neigh_event_send(n
, NULL
);
1346 #if IS_ENABLED(CONFIG_IPV6)
1347 static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp
*mlxsw_sp
,
1351 struct net_device
*dev
;
1352 struct neighbour
*n
;
1353 struct in6_addr dip
;
1356 mlxsw_reg_rauhtd_ent_ipv6_unpack(rauhtd_pl
, rec_index
, &rif
,
1359 if (!mlxsw_sp
->router
->rifs
[rif
]) {
1360 dev_err_ratelimited(mlxsw_sp
->bus_info
->dev
, "Incorrect RIF in neighbour entry\n");
1364 dev
= mlxsw_sp
->router
->rifs
[rif
]->dev
;
1365 n
= neigh_lookup(&nd_tbl
, &dip
, dev
);
1367 netdev_err(dev
, "Failed to find matching neighbour for IP=%pI6c\n",
1372 netdev_dbg(dev
, "Updating neighbour with IP=%pI6c\n", &dip
);
1373 neigh_event_send(n
, NULL
);
1377 static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp
*mlxsw_sp
,
1384 static void mlxsw_sp_router_neigh_rec_ipv4_process(struct mlxsw_sp
*mlxsw_sp
,
1391 num_entries
= mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl
,
1393 /* Hardware starts counting at 0, so add 1. */
1396 /* Each record consists of several neighbour entries. */
1397 for (i
= 0; i
< num_entries
; i
++) {
1400 ent_index
= rec_index
* MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC
+ i
;
1401 mlxsw_sp_router_neigh_ent_ipv4_process(mlxsw_sp
, rauhtd_pl
,
1407 static void mlxsw_sp_router_neigh_rec_ipv6_process(struct mlxsw_sp
*mlxsw_sp
,
1411 /* One record contains one entry. */
1412 mlxsw_sp_router_neigh_ent_ipv6_process(mlxsw_sp
, rauhtd_pl
,
1416 static void mlxsw_sp_router_neigh_rec_process(struct mlxsw_sp
*mlxsw_sp
,
1417 char *rauhtd_pl
, int rec_index
)
1419 switch (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl
, rec_index
)) {
1420 case MLXSW_REG_RAUHTD_TYPE_IPV4
:
1421 mlxsw_sp_router_neigh_rec_ipv4_process(mlxsw_sp
, rauhtd_pl
,
1424 case MLXSW_REG_RAUHTD_TYPE_IPV6
:
1425 mlxsw_sp_router_neigh_rec_ipv6_process(mlxsw_sp
, rauhtd_pl
,
1431 static bool mlxsw_sp_router_rauhtd_is_full(char *rauhtd_pl
)
1433 u8 num_rec
, last_rec_index
, num_entries
;
1435 num_rec
= mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl
);
1436 last_rec_index
= num_rec
- 1;
1438 if (num_rec
< MLXSW_REG_RAUHTD_REC_MAX_NUM
)
1440 if (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl
, last_rec_index
) ==
1441 MLXSW_REG_RAUHTD_TYPE_IPV6
)
1444 num_entries
= mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl
,
1446 if (++num_entries
== MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC
)
1452 __mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp
*mlxsw_sp
,
1454 enum mlxsw_reg_rauhtd_type type
)
1459 /* Make sure the neighbour's netdev isn't removed in the
1464 mlxsw_reg_rauhtd_pack(rauhtd_pl
, type
);
1465 err
= mlxsw_reg_query(mlxsw_sp
->core
, MLXSW_REG(rauhtd
),
1468 dev_err_ratelimited(mlxsw_sp
->bus_info
->dev
, "Failed to dump neighbour talbe\n");
1471 num_rec
= mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl
);
1472 for (i
= 0; i
< num_rec
; i
++)
1473 mlxsw_sp_router_neigh_rec_process(mlxsw_sp
, rauhtd_pl
,
1475 } while (mlxsw_sp_router_rauhtd_is_full(rauhtd_pl
));
1481 static int mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp
*mlxsw_sp
)
1483 enum mlxsw_reg_rauhtd_type type
;
1487 rauhtd_pl
= kmalloc(MLXSW_REG_RAUHTD_LEN
, GFP_KERNEL
);
1491 type
= MLXSW_REG_RAUHTD_TYPE_IPV4
;
1492 err
= __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp
, rauhtd_pl
, type
);
1496 type
= MLXSW_REG_RAUHTD_TYPE_IPV6
;
1497 err
= __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp
, rauhtd_pl
, type
);
1503 static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp
*mlxsw_sp
)
1505 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1507 /* Take RTNL mutex here to prevent lists from changes */
1509 list_for_each_entry(neigh_entry
, &mlxsw_sp
->router
->nexthop_neighs_list
,
1510 nexthop_neighs_list_node
)
1511 /* If this neigh have nexthops, make the kernel think this neigh
1512 * is active regardless of the traffic.
1514 neigh_event_send(neigh_entry
->key
.n
, NULL
);
1519 mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp
*mlxsw_sp
)
1521 unsigned long interval
= mlxsw_sp
->router
->neighs_update
.interval
;
1523 mlxsw_core_schedule_dw(&mlxsw_sp
->router
->neighs_update
.dw
,
1524 msecs_to_jiffies(interval
));
1527 static void mlxsw_sp_router_neighs_update_work(struct work_struct
*work
)
1529 struct mlxsw_sp_router
*router
;
1532 router
= container_of(work
, struct mlxsw_sp_router
,
1533 neighs_update
.dw
.work
);
1534 err
= mlxsw_sp_router_neighs_update_rauhtd(router
->mlxsw_sp
);
1536 dev_err(router
->mlxsw_sp
->bus_info
->dev
, "Could not update kernel for neigh activity");
1538 mlxsw_sp_router_neighs_update_nh(router
->mlxsw_sp
);
1540 mlxsw_sp_router_neighs_update_work_schedule(router
->mlxsw_sp
);
1543 static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct
*work
)
1545 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1546 struct mlxsw_sp_router
*router
;
1548 router
= container_of(work
, struct mlxsw_sp_router
,
1549 nexthop_probe_dw
.work
);
1550 /* Iterate over nexthop neighbours, find those who are unresolved and
1551 * send arp on them. This solves the chicken-egg problem when
1552 * the nexthop wouldn't get offloaded until the neighbor is resolved
1553 * but it wouldn't get resolved ever in case traffic is flowing in HW
1554 * using different nexthop.
1556 * Take RTNL mutex here to prevent lists from changes.
1559 list_for_each_entry(neigh_entry
, &router
->nexthop_neighs_list
,
1560 nexthop_neighs_list_node
)
1561 if (!neigh_entry
->connected
)
1562 neigh_event_send(neigh_entry
->key
.n
, NULL
);
1565 mlxsw_core_schedule_dw(&router
->nexthop_probe_dw
,
1566 MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL
);
1570 mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp
*mlxsw_sp
,
1571 struct mlxsw_sp_neigh_entry
*neigh_entry
,
1574 static enum mlxsw_reg_rauht_op
mlxsw_sp_rauht_op(bool adding
)
1576 return adding
? MLXSW_REG_RAUHT_OP_WRITE_ADD
:
1577 MLXSW_REG_RAUHT_OP_WRITE_DELETE
;
1581 mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp
*mlxsw_sp
,
1582 struct mlxsw_sp_neigh_entry
*neigh_entry
,
1583 enum mlxsw_reg_rauht_op op
)
1585 struct neighbour
*n
= neigh_entry
->key
.n
;
1586 u32 dip
= ntohl(*((__be32
*) n
->primary_key
));
1587 char rauht_pl
[MLXSW_REG_RAUHT_LEN
];
1589 mlxsw_reg_rauht_pack4(rauht_pl
, op
, neigh_entry
->rif
, neigh_entry
->ha
,
1591 if (neigh_entry
->counter_valid
)
1592 mlxsw_reg_rauht_pack_counter(rauht_pl
,
1593 neigh_entry
->counter_index
);
1594 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(rauht
), rauht_pl
);
1598 mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp
*mlxsw_sp
,
1599 struct mlxsw_sp_neigh_entry
*neigh_entry
,
1600 enum mlxsw_reg_rauht_op op
)
1602 struct neighbour
*n
= neigh_entry
->key
.n
;
1603 char rauht_pl
[MLXSW_REG_RAUHT_LEN
];
1604 const char *dip
= n
->primary_key
;
1606 mlxsw_reg_rauht_pack6(rauht_pl
, op
, neigh_entry
->rif
, neigh_entry
->ha
,
1608 if (neigh_entry
->counter_valid
)
1609 mlxsw_reg_rauht_pack_counter(rauht_pl
,
1610 neigh_entry
->counter_index
);
1611 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(rauht
), rauht_pl
);
1614 bool mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry
*neigh_entry
)
1616 struct neighbour
*n
= neigh_entry
->key
.n
;
1618 /* Packets with a link-local destination address are trapped
1619 * after LPM lookup and never reach the neighbour table, so
1620 * there is no need to program such neighbours to the device.
1622 if (ipv6_addr_type((struct in6_addr
*) &n
->primary_key
) &
1623 IPV6_ADDR_LINKLOCAL
)
1629 mlxsw_sp_neigh_entry_update(struct mlxsw_sp
*mlxsw_sp
,
1630 struct mlxsw_sp_neigh_entry
*neigh_entry
,
1633 if (!adding
&& !neigh_entry
->connected
)
1635 neigh_entry
->connected
= adding
;
1636 if (neigh_entry
->key
.n
->tbl
->family
== AF_INET
) {
1637 mlxsw_sp_router_neigh_entry_op4(mlxsw_sp
, neigh_entry
,
1638 mlxsw_sp_rauht_op(adding
));
1639 } else if (neigh_entry
->key
.n
->tbl
->family
== AF_INET6
) {
1640 if (mlxsw_sp_neigh_ipv6_ignore(neigh_entry
))
1642 mlxsw_sp_router_neigh_entry_op6(mlxsw_sp
, neigh_entry
,
1643 mlxsw_sp_rauht_op(adding
));
1650 mlxsw_sp_neigh_entry_counter_update(struct mlxsw_sp
*mlxsw_sp
,
1651 struct mlxsw_sp_neigh_entry
*neigh_entry
,
1655 mlxsw_sp_neigh_counter_alloc(mlxsw_sp
, neigh_entry
);
1657 mlxsw_sp_neigh_counter_free(mlxsw_sp
, neigh_entry
);
1658 mlxsw_sp_neigh_entry_update(mlxsw_sp
, neigh_entry
, true);
1661 struct mlxsw_sp_neigh_event_work
{
1662 struct work_struct work
;
1663 struct mlxsw_sp
*mlxsw_sp
;
1664 struct neighbour
*n
;
1667 static void mlxsw_sp_router_neigh_event_work(struct work_struct
*work
)
1669 struct mlxsw_sp_neigh_event_work
*neigh_work
=
1670 container_of(work
, struct mlxsw_sp_neigh_event_work
, work
);
1671 struct mlxsw_sp
*mlxsw_sp
= neigh_work
->mlxsw_sp
;
1672 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1673 struct neighbour
*n
= neigh_work
->n
;
1674 unsigned char ha
[ETH_ALEN
];
1675 bool entry_connected
;
1678 /* If these parameters are changed after we release the lock,
1679 * then we are guaranteed to receive another event letting us
1682 read_lock_bh(&n
->lock
);
1683 memcpy(ha
, n
->ha
, ETH_ALEN
);
1684 nud_state
= n
->nud_state
;
1686 read_unlock_bh(&n
->lock
);
1689 entry_connected
= nud_state
& NUD_VALID
&& !dead
;
1690 neigh_entry
= mlxsw_sp_neigh_entry_lookup(mlxsw_sp
, n
);
1691 if (!entry_connected
&& !neigh_entry
)
1694 neigh_entry
= mlxsw_sp_neigh_entry_create(mlxsw_sp
, n
);
1695 if (IS_ERR(neigh_entry
))
1699 memcpy(neigh_entry
->ha
, ha
, ETH_ALEN
);
1700 mlxsw_sp_neigh_entry_update(mlxsw_sp
, neigh_entry
, entry_connected
);
1701 mlxsw_sp_nexthop_neigh_update(mlxsw_sp
, neigh_entry
, !entry_connected
);
1703 if (!neigh_entry
->connected
&& list_empty(&neigh_entry
->nexthop_list
))
1704 mlxsw_sp_neigh_entry_destroy(mlxsw_sp
, neigh_entry
);
1712 int mlxsw_sp_router_netevent_event(struct notifier_block
*unused
,
1713 unsigned long event
, void *ptr
)
1715 struct mlxsw_sp_neigh_event_work
*neigh_work
;
1716 struct mlxsw_sp_port
*mlxsw_sp_port
;
1717 struct mlxsw_sp
*mlxsw_sp
;
1718 unsigned long interval
;
1719 struct neigh_parms
*p
;
1720 struct neighbour
*n
;
1723 case NETEVENT_DELAY_PROBE_TIME_UPDATE
:
1726 /* We don't care about changes in the default table. */
1727 if (!p
->dev
|| (p
->tbl
->family
!= AF_INET
&&
1728 p
->tbl
->family
!= AF_INET6
))
1731 /* We are in atomic context and can't take RTNL mutex,
1732 * so use RCU variant to walk the device chain.
1734 mlxsw_sp_port
= mlxsw_sp_port_lower_dev_hold(p
->dev
);
1738 mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
1739 interval
= jiffies_to_msecs(NEIGH_VAR(p
, DELAY_PROBE_TIME
));
1740 mlxsw_sp
->router
->neighs_update
.interval
= interval
;
1742 mlxsw_sp_port_dev_put(mlxsw_sp_port
);
1744 case NETEVENT_NEIGH_UPDATE
:
1747 if (n
->tbl
->family
!= AF_INET
&& n
->tbl
->family
!= AF_INET6
)
1750 mlxsw_sp_port
= mlxsw_sp_port_lower_dev_hold(n
->dev
);
1754 neigh_work
= kzalloc(sizeof(*neigh_work
), GFP_ATOMIC
);
1756 mlxsw_sp_port_dev_put(mlxsw_sp_port
);
1760 INIT_WORK(&neigh_work
->work
, mlxsw_sp_router_neigh_event_work
);
1761 neigh_work
->mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
1764 /* Take a reference to ensure the neighbour won't be
1765 * destructed until we drop the reference in delayed
1769 mlxsw_core_schedule_work(&neigh_work
->work
);
1770 mlxsw_sp_port_dev_put(mlxsw_sp_port
);
1777 static int mlxsw_sp_neigh_init(struct mlxsw_sp
*mlxsw_sp
)
1781 err
= rhashtable_init(&mlxsw_sp
->router
->neigh_ht
,
1782 &mlxsw_sp_neigh_ht_params
);
1786 /* Initialize the polling interval according to the default
1789 mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp
);
1791 /* Create the delayed works for the activity_update */
1792 INIT_DELAYED_WORK(&mlxsw_sp
->router
->neighs_update
.dw
,
1793 mlxsw_sp_router_neighs_update_work
);
1794 INIT_DELAYED_WORK(&mlxsw_sp
->router
->nexthop_probe_dw
,
1795 mlxsw_sp_router_probe_unresolved_nexthops
);
1796 mlxsw_core_schedule_dw(&mlxsw_sp
->router
->neighs_update
.dw
, 0);
1797 mlxsw_core_schedule_dw(&mlxsw_sp
->router
->nexthop_probe_dw
, 0);
1801 static void mlxsw_sp_neigh_fini(struct mlxsw_sp
*mlxsw_sp
)
1803 cancel_delayed_work_sync(&mlxsw_sp
->router
->neighs_update
.dw
);
1804 cancel_delayed_work_sync(&mlxsw_sp
->router
->nexthop_probe_dw
);
1805 rhashtable_destroy(&mlxsw_sp
->router
->neigh_ht
);
1808 static void mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp
*mlxsw_sp
,
1809 struct mlxsw_sp_rif
*rif
)
1811 struct mlxsw_sp_neigh_entry
*neigh_entry
, *tmp
;
1813 list_for_each_entry_safe(neigh_entry
, tmp
, &rif
->neigh_list
,
1815 mlxsw_sp_neigh_entry_update(mlxsw_sp
, neigh_entry
, false);
1816 mlxsw_sp_neigh_entry_destroy(mlxsw_sp
, neigh_entry
);
1820 enum mlxsw_sp_nexthop_type
{
1821 MLXSW_SP_NEXTHOP_TYPE_ETH
,
1822 MLXSW_SP_NEXTHOP_TYPE_IPIP
,
1825 struct mlxsw_sp_nexthop_key
{
1826 struct fib_nh
*fib_nh
;
1829 struct mlxsw_sp_nexthop
{
1830 struct list_head neigh_list_node
; /* member of neigh entry list */
1831 struct list_head rif_list_node
;
1832 struct mlxsw_sp_nexthop_group
*nh_grp
; /* pointer back to the group
1835 struct rhash_head ht_node
;
1836 struct mlxsw_sp_nexthop_key key
;
1837 unsigned char gw_addr
[sizeof(struct in6_addr
)];
1839 struct mlxsw_sp_rif
*rif
;
1840 u8 should_offload
:1, /* set indicates this neigh is connected and
1841 * should be put to KVD linear area of this group.
1843 offloaded
:1, /* set in case the neigh is actually put into
1844 * KVD linear area of this group.
1846 update
:1; /* set indicates that MAC of this neigh should be
1849 enum mlxsw_sp_nexthop_type type
;
1851 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1852 struct mlxsw_sp_ipip_entry
*ipip_entry
;
1856 struct mlxsw_sp_nexthop_group
{
1858 struct rhash_head ht_node
;
1859 struct list_head fib_list
; /* list of fib entries that use this group */
1860 struct neigh_table
*neigh_tbl
;
1861 u8 adj_index_valid
:1,
1862 gateway
:1; /* routes using the group use a gateway */
1866 struct mlxsw_sp_nexthop nexthops
[0];
1867 #define nh_rif nexthops[0].rif
1870 static struct fib_info
*
1871 mlxsw_sp_nexthop4_group_fi(const struct mlxsw_sp_nexthop_group
*nh_grp
)
1873 return nh_grp
->priv
;
1876 struct mlxsw_sp_nexthop_group_cmp_arg
{
1877 enum mlxsw_sp_l3proto proto
;
1879 struct fib_info
*fi
;
1880 struct mlxsw_sp_fib6_entry
*fib6_entry
;
1885 mlxsw_sp_nexthop6_group_has_nexthop(const struct mlxsw_sp_nexthop_group
*nh_grp
,
1886 const struct in6_addr
*gw
, int ifindex
)
1890 for (i
= 0; i
< nh_grp
->count
; i
++) {
1891 const struct mlxsw_sp_nexthop
*nh
;
1893 nh
= &nh_grp
->nexthops
[i
];
1894 if (nh
->ifindex
== ifindex
&&
1895 ipv6_addr_equal(gw
, (struct in6_addr
*) nh
->gw_addr
))
1903 mlxsw_sp_nexthop6_group_cmp(const struct mlxsw_sp_nexthop_group
*nh_grp
,
1904 const struct mlxsw_sp_fib6_entry
*fib6_entry
)
1906 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
1908 if (nh_grp
->count
!= fib6_entry
->nrt6
)
1911 list_for_each_entry(mlxsw_sp_rt6
, &fib6_entry
->rt6_list
, list
) {
1912 struct in6_addr
*gw
;
1915 ifindex
= mlxsw_sp_rt6
->rt
->dst
.dev
->ifindex
;
1916 gw
= &mlxsw_sp_rt6
->rt
->rt6i_gateway
;
1917 if (!mlxsw_sp_nexthop6_group_has_nexthop(nh_grp
, gw
, ifindex
))
1925 mlxsw_sp_nexthop_group_cmp(struct rhashtable_compare_arg
*arg
, const void *ptr
)
1927 const struct mlxsw_sp_nexthop_group_cmp_arg
*cmp_arg
= arg
->key
;
1928 const struct mlxsw_sp_nexthop_group
*nh_grp
= ptr
;
1930 switch (cmp_arg
->proto
) {
1931 case MLXSW_SP_L3_PROTO_IPV4
:
1932 return cmp_arg
->fi
!= mlxsw_sp_nexthop4_group_fi(nh_grp
);
1933 case MLXSW_SP_L3_PROTO_IPV6
:
1934 return !mlxsw_sp_nexthop6_group_cmp(nh_grp
,
1935 cmp_arg
->fib6_entry
);
1943 mlxsw_sp_nexthop_group_type(const struct mlxsw_sp_nexthop_group
*nh_grp
)
1945 return nh_grp
->neigh_tbl
->family
;
1948 static u32
mlxsw_sp_nexthop_group_hash_obj(const void *data
, u32 len
, u32 seed
)
1950 const struct mlxsw_sp_nexthop_group
*nh_grp
= data
;
1951 const struct mlxsw_sp_nexthop
*nh
;
1952 struct fib_info
*fi
;
1956 switch (mlxsw_sp_nexthop_group_type(nh_grp
)) {
1958 fi
= mlxsw_sp_nexthop4_group_fi(nh_grp
);
1959 return jhash(&fi
, sizeof(fi
), seed
);
1961 val
= nh_grp
->count
;
1962 for (i
= 0; i
< nh_grp
->count
; i
++) {
1963 nh
= &nh_grp
->nexthops
[i
];
1966 return jhash(&val
, sizeof(val
), seed
);
1974 mlxsw_sp_nexthop6_group_hash(struct mlxsw_sp_fib6_entry
*fib6_entry
, u32 seed
)
1976 unsigned int val
= fib6_entry
->nrt6
;
1977 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
1978 struct net_device
*dev
;
1980 list_for_each_entry(mlxsw_sp_rt6
, &fib6_entry
->rt6_list
, list
) {
1981 dev
= mlxsw_sp_rt6
->rt
->dst
.dev
;
1982 val
^= dev
->ifindex
;
1985 return jhash(&val
, sizeof(val
), seed
);
1989 mlxsw_sp_nexthop_group_hash(const void *data
, u32 len
, u32 seed
)
1991 const struct mlxsw_sp_nexthop_group_cmp_arg
*cmp_arg
= data
;
1993 switch (cmp_arg
->proto
) {
1994 case MLXSW_SP_L3_PROTO_IPV4
:
1995 return jhash(&cmp_arg
->fi
, sizeof(cmp_arg
->fi
), seed
);
1996 case MLXSW_SP_L3_PROTO_IPV6
:
1997 return mlxsw_sp_nexthop6_group_hash(cmp_arg
->fib6_entry
, seed
);
2004 static const struct rhashtable_params mlxsw_sp_nexthop_group_ht_params
= {
2005 .head_offset
= offsetof(struct mlxsw_sp_nexthop_group
, ht_node
),
2006 .hashfn
= mlxsw_sp_nexthop_group_hash
,
2007 .obj_hashfn
= mlxsw_sp_nexthop_group_hash_obj
,
2008 .obj_cmpfn
= mlxsw_sp_nexthop_group_cmp
,
2011 static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp
*mlxsw_sp
,
2012 struct mlxsw_sp_nexthop_group
*nh_grp
)
2014 if (mlxsw_sp_nexthop_group_type(nh_grp
) == AF_INET6
&&
2018 return rhashtable_insert_fast(&mlxsw_sp
->router
->nexthop_group_ht
,
2020 mlxsw_sp_nexthop_group_ht_params
);
2023 static void mlxsw_sp_nexthop_group_remove(struct mlxsw_sp
*mlxsw_sp
,
2024 struct mlxsw_sp_nexthop_group
*nh_grp
)
2026 if (mlxsw_sp_nexthop_group_type(nh_grp
) == AF_INET6
&&
2030 rhashtable_remove_fast(&mlxsw_sp
->router
->nexthop_group_ht
,
2032 mlxsw_sp_nexthop_group_ht_params
);
2035 static struct mlxsw_sp_nexthop_group
*
2036 mlxsw_sp_nexthop4_group_lookup(struct mlxsw_sp
*mlxsw_sp
,
2037 struct fib_info
*fi
)
2039 struct mlxsw_sp_nexthop_group_cmp_arg cmp_arg
;
2041 cmp_arg
.proto
= MLXSW_SP_L3_PROTO_IPV4
;
2043 return rhashtable_lookup_fast(&mlxsw_sp
->router
->nexthop_group_ht
,
2045 mlxsw_sp_nexthop_group_ht_params
);
2048 static struct mlxsw_sp_nexthop_group
*
2049 mlxsw_sp_nexthop6_group_lookup(struct mlxsw_sp
*mlxsw_sp
,
2050 struct mlxsw_sp_fib6_entry
*fib6_entry
)
2052 struct mlxsw_sp_nexthop_group_cmp_arg cmp_arg
;
2054 cmp_arg
.proto
= MLXSW_SP_L3_PROTO_IPV6
;
2055 cmp_arg
.fib6_entry
= fib6_entry
;
2056 return rhashtable_lookup_fast(&mlxsw_sp
->router
->nexthop_group_ht
,
2058 mlxsw_sp_nexthop_group_ht_params
);
2061 static const struct rhashtable_params mlxsw_sp_nexthop_ht_params
= {
2062 .key_offset
= offsetof(struct mlxsw_sp_nexthop
, key
),
2063 .head_offset
= offsetof(struct mlxsw_sp_nexthop
, ht_node
),
2064 .key_len
= sizeof(struct mlxsw_sp_nexthop_key
),
2067 static int mlxsw_sp_nexthop_insert(struct mlxsw_sp
*mlxsw_sp
,
2068 struct mlxsw_sp_nexthop
*nh
)
2070 return rhashtable_insert_fast(&mlxsw_sp
->router
->nexthop_ht
,
2071 &nh
->ht_node
, mlxsw_sp_nexthop_ht_params
);
2074 static void mlxsw_sp_nexthop_remove(struct mlxsw_sp
*mlxsw_sp
,
2075 struct mlxsw_sp_nexthop
*nh
)
2077 rhashtable_remove_fast(&mlxsw_sp
->router
->nexthop_ht
, &nh
->ht_node
,
2078 mlxsw_sp_nexthop_ht_params
);
2081 static struct mlxsw_sp_nexthop
*
2082 mlxsw_sp_nexthop_lookup(struct mlxsw_sp
*mlxsw_sp
,
2083 struct mlxsw_sp_nexthop_key key
)
2085 return rhashtable_lookup_fast(&mlxsw_sp
->router
->nexthop_ht
, &key
,
2086 mlxsw_sp_nexthop_ht_params
);
2089 static int mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp
*mlxsw_sp
,
2090 const struct mlxsw_sp_fib
*fib
,
2091 u32 adj_index
, u16 ecmp_size
,
2095 char raleu_pl
[MLXSW_REG_RALEU_LEN
];
2097 mlxsw_reg_raleu_pack(raleu_pl
,
2098 (enum mlxsw_reg_ralxx_protocol
) fib
->proto
,
2099 fib
->vr
->id
, adj_index
, ecmp_size
, new_adj_index
,
2101 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(raleu
), raleu_pl
);
2104 static int mlxsw_sp_adj_index_mass_update(struct mlxsw_sp
*mlxsw_sp
,
2105 struct mlxsw_sp_nexthop_group
*nh_grp
,
2106 u32 old_adj_index
, u16 old_ecmp_size
)
2108 struct mlxsw_sp_fib_entry
*fib_entry
;
2109 struct mlxsw_sp_fib
*fib
= NULL
;
2112 list_for_each_entry(fib_entry
, &nh_grp
->fib_list
, nexthop_group_node
) {
2113 if (fib
== fib_entry
->fib_node
->fib
)
2115 fib
= fib_entry
->fib_node
->fib
;
2116 err
= mlxsw_sp_adj_index_mass_update_vr(mlxsw_sp
, fib
,
2127 static int mlxsw_sp_nexthop_mac_update(struct mlxsw_sp
*mlxsw_sp
, u32 adj_index
,
2128 struct mlxsw_sp_nexthop
*nh
)
2130 struct mlxsw_sp_neigh_entry
*neigh_entry
= nh
->neigh_entry
;
2131 char ratr_pl
[MLXSW_REG_RATR_LEN
];
2133 mlxsw_reg_ratr_pack(ratr_pl
, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY
,
2134 true, MLXSW_REG_RATR_TYPE_ETHERNET
,
2135 adj_index
, neigh_entry
->rif
);
2136 mlxsw_reg_ratr_eth_entry_pack(ratr_pl
, neigh_entry
->ha
);
2137 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ratr
), ratr_pl
);
2140 static int mlxsw_sp_nexthop_ipip_update(struct mlxsw_sp
*mlxsw_sp
,
2142 struct mlxsw_sp_nexthop
*nh
)
2144 const struct mlxsw_sp_ipip_ops
*ipip_ops
;
2146 ipip_ops
= mlxsw_sp
->router
->ipip_ops_arr
[nh
->ipip_entry
->ipipt
];
2147 return ipip_ops
->nexthop_update(mlxsw_sp
, adj_index
, nh
->ipip_entry
);
2151 mlxsw_sp_nexthop_group_update(struct mlxsw_sp
*mlxsw_sp
,
2152 struct mlxsw_sp_nexthop_group
*nh_grp
,
2155 u32 adj_index
= nh_grp
->adj_index
; /* base */
2156 struct mlxsw_sp_nexthop
*nh
;
2160 for (i
= 0; i
< nh_grp
->count
; i
++) {
2161 nh
= &nh_grp
->nexthops
[i
];
2163 if (!nh
->should_offload
) {
2168 if (nh
->update
|| reallocate
) {
2170 case MLXSW_SP_NEXTHOP_TYPE_ETH
:
2171 err
= mlxsw_sp_nexthop_mac_update
2172 (mlxsw_sp
, adj_index
, nh
);
2174 case MLXSW_SP_NEXTHOP_TYPE_IPIP
:
2175 err
= mlxsw_sp_nexthop_ipip_update
2176 (mlxsw_sp
, adj_index
, nh
);
2189 static int mlxsw_sp_fib_entry_update(struct mlxsw_sp
*mlxsw_sp
,
2190 struct mlxsw_sp_fib_entry
*fib_entry
);
2193 mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node
*fib_node
,
2194 const struct mlxsw_sp_fib_entry
*fib_entry
);
2197 mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp
*mlxsw_sp
,
2198 struct mlxsw_sp_nexthop_group
*nh_grp
)
2200 struct mlxsw_sp_fib_entry
*fib_entry
;
2203 list_for_each_entry(fib_entry
, &nh_grp
->fib_list
, nexthop_group_node
) {
2204 if (!mlxsw_sp_fib_node_entry_is_first(fib_entry
->fib_node
,
2207 err
= mlxsw_sp_fib_entry_update(mlxsw_sp
, fib_entry
);
2215 mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry
*fib_entry
,
2216 enum mlxsw_reg_ralue_op op
, int err
);
2219 mlxsw_sp_nexthop_fib_entries_refresh(struct mlxsw_sp_nexthop_group
*nh_grp
)
2221 enum mlxsw_reg_ralue_op op
= MLXSW_REG_RALUE_OP_WRITE_WRITE
;
2222 struct mlxsw_sp_fib_entry
*fib_entry
;
2224 list_for_each_entry(fib_entry
, &nh_grp
->fib_list
, nexthop_group_node
) {
2225 if (!mlxsw_sp_fib_node_entry_is_first(fib_entry
->fib_node
,
2228 mlxsw_sp_fib_entry_offload_refresh(fib_entry
, op
, 0);
2233 mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp
*mlxsw_sp
,
2234 struct mlxsw_sp_nexthop_group
*nh_grp
)
2236 struct mlxsw_sp_nexthop
*nh
;
2237 bool offload_change
= false;
2240 bool old_adj_index_valid
;
2246 if (!nh_grp
->gateway
) {
2247 mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp
, nh_grp
);
2251 for (i
= 0; i
< nh_grp
->count
; i
++) {
2252 nh
= &nh_grp
->nexthops
[i
];
2254 if (nh
->should_offload
!= nh
->offloaded
) {
2255 offload_change
= true;
2256 if (nh
->should_offload
)
2259 if (nh
->should_offload
)
2262 if (!offload_change
) {
2263 /* Nothing was added or removed, so no need to reallocate. Just
2264 * update MAC on existing adjacency indexes.
2266 err
= mlxsw_sp_nexthop_group_update(mlxsw_sp
, nh_grp
, false);
2268 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to update neigh MAC in adjacency table.\n");
2274 /* No neigh of this group is connected so we just set
2275 * the trap and let everthing flow through kernel.
2279 err
= mlxsw_sp_kvdl_alloc(mlxsw_sp
, ecmp_size
, &adj_index
);
2281 /* We ran out of KVD linear space, just set the
2282 * trap and let everything flow through kernel.
2284 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to allocate KVD linear area for nexthop group.\n");
2287 old_adj_index_valid
= nh_grp
->adj_index_valid
;
2288 old_adj_index
= nh_grp
->adj_index
;
2289 old_ecmp_size
= nh_grp
->ecmp_size
;
2290 nh_grp
->adj_index_valid
= 1;
2291 nh_grp
->adj_index
= adj_index
;
2292 nh_grp
->ecmp_size
= ecmp_size
;
2293 err
= mlxsw_sp_nexthop_group_update(mlxsw_sp
, nh_grp
, true);
2295 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to update neigh MAC in adjacency table.\n");
2299 if (!old_adj_index_valid
) {
2300 /* The trap was set for fib entries, so we have to call
2301 * fib entry update to unset it and use adjacency index.
2303 err
= mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp
, nh_grp
);
2305 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to add adjacency index to fib entries.\n");
2311 err
= mlxsw_sp_adj_index_mass_update(mlxsw_sp
, nh_grp
,
2312 old_adj_index
, old_ecmp_size
);
2313 mlxsw_sp_kvdl_free(mlxsw_sp
, old_adj_index
);
2315 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to mass-update adjacency index for nexthop group.\n");
2319 /* Offload state within the group changed, so update the flags. */
2320 mlxsw_sp_nexthop_fib_entries_refresh(nh_grp
);
2325 old_adj_index_valid
= nh_grp
->adj_index_valid
;
2326 nh_grp
->adj_index_valid
= 0;
2327 for (i
= 0; i
< nh_grp
->count
; i
++) {
2328 nh
= &nh_grp
->nexthops
[i
];
2331 err
= mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp
, nh_grp
);
2333 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to set traps for fib entries.\n");
2334 if (old_adj_index_valid
)
2335 mlxsw_sp_kvdl_free(mlxsw_sp
, nh_grp
->adj_index
);
2338 static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop
*nh
,
2342 nh
->should_offload
= 1;
2343 else if (nh
->offloaded
)
2344 nh
->should_offload
= 0;
2349 mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp
*mlxsw_sp
,
2350 struct mlxsw_sp_neigh_entry
*neigh_entry
,
2353 struct mlxsw_sp_nexthop
*nh
;
2355 list_for_each_entry(nh
, &neigh_entry
->nexthop_list
,
2357 __mlxsw_sp_nexthop_neigh_update(nh
, removing
);
2358 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh
->nh_grp
);
2362 static void mlxsw_sp_nexthop_rif_init(struct mlxsw_sp_nexthop
*nh
,
2363 struct mlxsw_sp_rif
*rif
)
2369 list_add(&nh
->rif_list_node
, &rif
->nexthop_list
);
2372 static void mlxsw_sp_nexthop_rif_fini(struct mlxsw_sp_nexthop
*nh
)
2377 list_del(&nh
->rif_list_node
);
2381 static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp
*mlxsw_sp
,
2382 struct mlxsw_sp_nexthop
*nh
)
2384 struct mlxsw_sp_neigh_entry
*neigh_entry
;
2385 struct neighbour
*n
;
2389 if (!nh
->nh_grp
->gateway
|| nh
->neigh_entry
)
2392 /* Take a reference of neigh here ensuring that neigh would
2393 * not be destructed before the nexthop entry is finished.
2394 * The reference is taken either in neigh_lookup() or
2395 * in neigh_create() in case n is not found.
2397 n
= neigh_lookup(nh
->nh_grp
->neigh_tbl
, &nh
->gw_addr
, nh
->rif
->dev
);
2399 n
= neigh_create(nh
->nh_grp
->neigh_tbl
, &nh
->gw_addr
,
2403 neigh_event_send(n
, NULL
);
2405 neigh_entry
= mlxsw_sp_neigh_entry_lookup(mlxsw_sp
, n
);
2407 neigh_entry
= mlxsw_sp_neigh_entry_create(mlxsw_sp
, n
);
2408 if (IS_ERR(neigh_entry
)) {
2410 goto err_neigh_entry_create
;
2414 /* If that is the first nexthop connected to that neigh, add to
2415 * nexthop_neighs_list
2417 if (list_empty(&neigh_entry
->nexthop_list
))
2418 list_add_tail(&neigh_entry
->nexthop_neighs_list_node
,
2419 &mlxsw_sp
->router
->nexthop_neighs_list
);
2421 nh
->neigh_entry
= neigh_entry
;
2422 list_add_tail(&nh
->neigh_list_node
, &neigh_entry
->nexthop_list
);
2423 read_lock_bh(&n
->lock
);
2424 nud_state
= n
->nud_state
;
2426 read_unlock_bh(&n
->lock
);
2427 __mlxsw_sp_nexthop_neigh_update(nh
, !(nud_state
& NUD_VALID
&& !dead
));
2431 err_neigh_entry_create
:
2436 static void mlxsw_sp_nexthop_neigh_fini(struct mlxsw_sp
*mlxsw_sp
,
2437 struct mlxsw_sp_nexthop
*nh
)
2439 struct mlxsw_sp_neigh_entry
*neigh_entry
= nh
->neigh_entry
;
2440 struct neighbour
*n
;
2444 n
= neigh_entry
->key
.n
;
2446 __mlxsw_sp_nexthop_neigh_update(nh
, true);
2447 list_del(&nh
->neigh_list_node
);
2448 nh
->neigh_entry
= NULL
;
2450 /* If that is the last nexthop connected to that neigh, remove from
2451 * nexthop_neighs_list
2453 if (list_empty(&neigh_entry
->nexthop_list
))
2454 list_del(&neigh_entry
->nexthop_neighs_list_node
);
2456 if (!neigh_entry
->connected
&& list_empty(&neigh_entry
->nexthop_list
))
2457 mlxsw_sp_neigh_entry_destroy(mlxsw_sp
, neigh_entry
);
2462 static bool mlxsw_sp_netdev_ipip_type(const struct mlxsw_sp
*mlxsw_sp
,
2463 const struct net_device
*dev
,
2464 enum mlxsw_sp_ipip_type
*p_type
)
2466 struct mlxsw_sp_router
*router
= mlxsw_sp
->router
;
2467 const struct mlxsw_sp_ipip_ops
*ipip_ops
;
2468 enum mlxsw_sp_ipip_type ipipt
;
2470 for (ipipt
= 0; ipipt
< MLXSW_SP_IPIP_TYPE_MAX
; ++ipipt
) {
2471 ipip_ops
= router
->ipip_ops_arr
[ipipt
];
2472 if (dev
->type
== ipip_ops
->dev_type
) {
2481 static int mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp
*mlxsw_sp
,
2482 enum mlxsw_sp_ipip_type ipipt
,
2483 struct mlxsw_sp_nexthop
*nh
,
2484 struct net_device
*ol_dev
)
2486 if (!nh
->nh_grp
->gateway
|| nh
->ipip_entry
)
2489 nh
->ipip_entry
= mlxsw_sp_ipip_entry_get(mlxsw_sp
, ipipt
, ol_dev
);
2490 if (IS_ERR(nh
->ipip_entry
))
2491 return PTR_ERR(nh
->ipip_entry
);
2493 __mlxsw_sp_nexthop_neigh_update(nh
, false);
2497 static void mlxsw_sp_nexthop_ipip_fini(struct mlxsw_sp
*mlxsw_sp
,
2498 struct mlxsw_sp_nexthop
*nh
)
2500 struct mlxsw_sp_ipip_entry
*ipip_entry
= nh
->ipip_entry
;
2505 __mlxsw_sp_nexthop_neigh_update(nh
, true);
2506 mlxsw_sp_ipip_entry_put(mlxsw_sp
, ipip_entry
);
2507 nh
->ipip_entry
= NULL
;
2510 static bool mlxsw_sp_nexthop4_ipip_type(const struct mlxsw_sp
*mlxsw_sp
,
2511 const struct fib_nh
*fib_nh
,
2512 enum mlxsw_sp_ipip_type
*p_ipipt
)
2514 struct net_device
*dev
= fib_nh
->nh_dev
;
2517 fib_nh
->nh_parent
->fib_type
== RTN_UNICAST
&&
2518 mlxsw_sp_netdev_ipip_type(mlxsw_sp
, dev
, p_ipipt
);
2521 static void mlxsw_sp_nexthop_type_fini(struct mlxsw_sp
*mlxsw_sp
,
2522 struct mlxsw_sp_nexthop
*nh
)
2525 case MLXSW_SP_NEXTHOP_TYPE_ETH
:
2526 mlxsw_sp_nexthop_neigh_fini(mlxsw_sp
, nh
);
2527 mlxsw_sp_nexthop_rif_fini(nh
);
2529 case MLXSW_SP_NEXTHOP_TYPE_IPIP
:
2530 mlxsw_sp_nexthop_ipip_fini(mlxsw_sp
, nh
);
2535 static int mlxsw_sp_nexthop4_type_init(struct mlxsw_sp
*mlxsw_sp
,
2536 struct mlxsw_sp_nexthop
*nh
,
2537 struct fib_nh
*fib_nh
)
2539 struct mlxsw_sp_router
*router
= mlxsw_sp
->router
;
2540 struct net_device
*dev
= fib_nh
->nh_dev
;
2541 enum mlxsw_sp_ipip_type ipipt
;
2542 struct mlxsw_sp_rif
*rif
;
2545 if (mlxsw_sp_nexthop4_ipip_type(mlxsw_sp
, fib_nh
, &ipipt
) &&
2546 router
->ipip_ops_arr
[ipipt
]->can_offload(mlxsw_sp
, dev
,
2547 MLXSW_SP_L3_PROTO_IPV4
)) {
2548 nh
->type
= MLXSW_SP_NEXTHOP_TYPE_IPIP
;
2549 return mlxsw_sp_nexthop_ipip_init(mlxsw_sp
, ipipt
, nh
, dev
);
2552 nh
->type
= MLXSW_SP_NEXTHOP_TYPE_ETH
;
2553 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, dev
);
2557 mlxsw_sp_nexthop_rif_init(nh
, rif
);
2558 err
= mlxsw_sp_nexthop_neigh_init(mlxsw_sp
, nh
);
2560 goto err_neigh_init
;
2565 mlxsw_sp_nexthop_rif_fini(nh
);
2569 static void mlxsw_sp_nexthop4_type_fini(struct mlxsw_sp
*mlxsw_sp
,
2570 struct mlxsw_sp_nexthop
*nh
)
2572 mlxsw_sp_nexthop_type_fini(mlxsw_sp
, nh
);
2575 static int mlxsw_sp_nexthop4_init(struct mlxsw_sp
*mlxsw_sp
,
2576 struct mlxsw_sp_nexthop_group
*nh_grp
,
2577 struct mlxsw_sp_nexthop
*nh
,
2578 struct fib_nh
*fib_nh
)
2580 struct net_device
*dev
= fib_nh
->nh_dev
;
2581 struct in_device
*in_dev
;
2584 nh
->nh_grp
= nh_grp
;
2585 nh
->key
.fib_nh
= fib_nh
;
2586 memcpy(&nh
->gw_addr
, &fib_nh
->nh_gw
, sizeof(fib_nh
->nh_gw
));
2587 err
= mlxsw_sp_nexthop_insert(mlxsw_sp
, nh
);
2594 in_dev
= __in_dev_get_rtnl(dev
);
2595 if (in_dev
&& IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev
) &&
2596 fib_nh
->nh_flags
& RTNH_F_LINKDOWN
)
2599 err
= mlxsw_sp_nexthop4_type_init(mlxsw_sp
, nh
, fib_nh
);
2601 goto err_nexthop_neigh_init
;
2605 err_nexthop_neigh_init
:
2606 mlxsw_sp_nexthop_remove(mlxsw_sp
, nh
);
2610 static void mlxsw_sp_nexthop4_fini(struct mlxsw_sp
*mlxsw_sp
,
2611 struct mlxsw_sp_nexthop
*nh
)
2613 mlxsw_sp_nexthop4_type_fini(mlxsw_sp
, nh
);
2614 mlxsw_sp_nexthop_remove(mlxsw_sp
, nh
);
2617 static void mlxsw_sp_nexthop4_event(struct mlxsw_sp
*mlxsw_sp
,
2618 unsigned long event
, struct fib_nh
*fib_nh
)
2620 struct mlxsw_sp_nexthop_key key
;
2621 struct mlxsw_sp_nexthop
*nh
;
2623 if (mlxsw_sp
->router
->aborted
)
2626 key
.fib_nh
= fib_nh
;
2627 nh
= mlxsw_sp_nexthop_lookup(mlxsw_sp
, key
);
2628 if (WARN_ON_ONCE(!nh
))
2632 case FIB_EVENT_NH_ADD
:
2633 mlxsw_sp_nexthop4_type_init(mlxsw_sp
, nh
, fib_nh
);
2635 case FIB_EVENT_NH_DEL
:
2636 mlxsw_sp_nexthop4_type_fini(mlxsw_sp
, nh
);
2640 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh
->nh_grp
);
2643 static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp
*mlxsw_sp
,
2644 struct mlxsw_sp_rif
*rif
)
2646 struct mlxsw_sp_nexthop
*nh
, *tmp
;
2648 list_for_each_entry_safe(nh
, tmp
, &rif
->nexthop_list
, rif_list_node
) {
2649 mlxsw_sp_nexthop_type_fini(mlxsw_sp
, nh
);
2650 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh
->nh_grp
);
2654 static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp
*mlxsw_sp
,
2655 const struct fib_info
*fi
)
2657 return fi
->fib_nh
->nh_scope
== RT_SCOPE_LINK
||
2658 mlxsw_sp_nexthop4_ipip_type(mlxsw_sp
, fi
->fib_nh
, NULL
);
2661 static struct mlxsw_sp_nexthop_group
*
2662 mlxsw_sp_nexthop4_group_create(struct mlxsw_sp
*mlxsw_sp
, struct fib_info
*fi
)
2664 struct mlxsw_sp_nexthop_group
*nh_grp
;
2665 struct mlxsw_sp_nexthop
*nh
;
2666 struct fib_nh
*fib_nh
;
2671 alloc_size
= sizeof(*nh_grp
) +
2672 fi
->fib_nhs
* sizeof(struct mlxsw_sp_nexthop
);
2673 nh_grp
= kzalloc(alloc_size
, GFP_KERNEL
);
2675 return ERR_PTR(-ENOMEM
);
2677 INIT_LIST_HEAD(&nh_grp
->fib_list
);
2678 nh_grp
->neigh_tbl
= &arp_tbl
;
2680 nh_grp
->gateway
= mlxsw_sp_fi_is_gateway(mlxsw_sp
, fi
);
2681 nh_grp
->count
= fi
->fib_nhs
;
2683 for (i
= 0; i
< nh_grp
->count
; i
++) {
2684 nh
= &nh_grp
->nexthops
[i
];
2685 fib_nh
= &fi
->fib_nh
[i
];
2686 err
= mlxsw_sp_nexthop4_init(mlxsw_sp
, nh_grp
, nh
, fib_nh
);
2688 goto err_nexthop4_init
;
2690 err
= mlxsw_sp_nexthop_group_insert(mlxsw_sp
, nh_grp
);
2692 goto err_nexthop_group_insert
;
2693 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh_grp
);
2696 err_nexthop_group_insert
:
2698 for (i
--; i
>= 0; i
--) {
2699 nh
= &nh_grp
->nexthops
[i
];
2700 mlxsw_sp_nexthop4_fini(mlxsw_sp
, nh
);
2704 return ERR_PTR(err
);
2708 mlxsw_sp_nexthop4_group_destroy(struct mlxsw_sp
*mlxsw_sp
,
2709 struct mlxsw_sp_nexthop_group
*nh_grp
)
2711 struct mlxsw_sp_nexthop
*nh
;
2714 mlxsw_sp_nexthop_group_remove(mlxsw_sp
, nh_grp
);
2715 for (i
= 0; i
< nh_grp
->count
; i
++) {
2716 nh
= &nh_grp
->nexthops
[i
];
2717 mlxsw_sp_nexthop4_fini(mlxsw_sp
, nh
);
2719 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh_grp
);
2720 WARN_ON_ONCE(nh_grp
->adj_index_valid
);
2721 fib_info_put(mlxsw_sp_nexthop4_group_fi(nh_grp
));
2725 static int mlxsw_sp_nexthop4_group_get(struct mlxsw_sp
*mlxsw_sp
,
2726 struct mlxsw_sp_fib_entry
*fib_entry
,
2727 struct fib_info
*fi
)
2729 struct mlxsw_sp_nexthop_group
*nh_grp
;
2731 nh_grp
= mlxsw_sp_nexthop4_group_lookup(mlxsw_sp
, fi
);
2733 nh_grp
= mlxsw_sp_nexthop4_group_create(mlxsw_sp
, fi
);
2735 return PTR_ERR(nh_grp
);
2737 list_add_tail(&fib_entry
->nexthop_group_node
, &nh_grp
->fib_list
);
2738 fib_entry
->nh_group
= nh_grp
;
2742 static void mlxsw_sp_nexthop4_group_put(struct mlxsw_sp
*mlxsw_sp
,
2743 struct mlxsw_sp_fib_entry
*fib_entry
)
2745 struct mlxsw_sp_nexthop_group
*nh_grp
= fib_entry
->nh_group
;
2747 list_del(&fib_entry
->nexthop_group_node
);
2748 if (!list_empty(&nh_grp
->fib_list
))
2750 mlxsw_sp_nexthop4_group_destroy(mlxsw_sp
, nh_grp
);
2754 mlxsw_sp_fib4_entry_should_offload(const struct mlxsw_sp_fib_entry
*fib_entry
)
2756 struct mlxsw_sp_fib4_entry
*fib4_entry
;
2758 fib4_entry
= container_of(fib_entry
, struct mlxsw_sp_fib4_entry
,
2760 return !fib4_entry
->tos
;
2764 mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry
*fib_entry
)
2766 struct mlxsw_sp_nexthop_group
*nh_group
= fib_entry
->nh_group
;
2768 switch (fib_entry
->fib_node
->fib
->proto
) {
2769 case MLXSW_SP_L3_PROTO_IPV4
:
2770 if (!mlxsw_sp_fib4_entry_should_offload(fib_entry
))
2773 case MLXSW_SP_L3_PROTO_IPV6
:
2777 switch (fib_entry
->type
) {
2778 case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE
:
2779 return !!nh_group
->adj_index_valid
;
2780 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
:
2781 return !!nh_group
->nh_rif
;
2787 static struct mlxsw_sp_nexthop
*
2788 mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group
*nh_grp
,
2789 const struct mlxsw_sp_rt6
*mlxsw_sp_rt6
)
2793 for (i
= 0; i
< nh_grp
->count
; i
++) {
2794 struct mlxsw_sp_nexthop
*nh
= &nh_grp
->nexthops
[i
];
2795 struct rt6_info
*rt
= mlxsw_sp_rt6
->rt
;
2797 if (nh
->rif
&& nh
->rif
->dev
== rt
->dst
.dev
&&
2798 ipv6_addr_equal((const struct in6_addr
*) &nh
->gw_addr
,
2808 mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry
*fib_entry
)
2810 struct mlxsw_sp_nexthop_group
*nh_grp
= fib_entry
->nh_group
;
2813 if (fib_entry
->type
== MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
) {
2814 nh_grp
->nexthops
->key
.fib_nh
->nh_flags
|= RTNH_F_OFFLOAD
;
2818 for (i
= 0; i
< nh_grp
->count
; i
++) {
2819 struct mlxsw_sp_nexthop
*nh
= &nh_grp
->nexthops
[i
];
2822 nh
->key
.fib_nh
->nh_flags
|= RTNH_F_OFFLOAD
;
2824 nh
->key
.fib_nh
->nh_flags
&= ~RTNH_F_OFFLOAD
;
2829 mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry
*fib_entry
)
2831 struct mlxsw_sp_nexthop_group
*nh_grp
= fib_entry
->nh_group
;
2834 for (i
= 0; i
< nh_grp
->count
; i
++) {
2835 struct mlxsw_sp_nexthop
*nh
= &nh_grp
->nexthops
[i
];
2837 nh
->key
.fib_nh
->nh_flags
&= ~RTNH_F_OFFLOAD
;
2842 mlxsw_sp_fib6_entry_offload_set(struct mlxsw_sp_fib_entry
*fib_entry
)
2844 struct mlxsw_sp_fib6_entry
*fib6_entry
;
2845 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
2847 fib6_entry
= container_of(fib_entry
, struct mlxsw_sp_fib6_entry
,
2850 if (fib_entry
->type
== MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
) {
2851 list_first_entry(&fib6_entry
->rt6_list
, struct mlxsw_sp_rt6
,
2852 list
)->rt
->rt6i_nh_flags
|= RTNH_F_OFFLOAD
;
2856 list_for_each_entry(mlxsw_sp_rt6
, &fib6_entry
->rt6_list
, list
) {
2857 struct mlxsw_sp_nexthop_group
*nh_grp
= fib_entry
->nh_group
;
2858 struct mlxsw_sp_nexthop
*nh
;
2860 nh
= mlxsw_sp_rt6_nexthop(nh_grp
, mlxsw_sp_rt6
);
2861 if (nh
&& nh
->offloaded
)
2862 mlxsw_sp_rt6
->rt
->rt6i_nh_flags
|= RTNH_F_OFFLOAD
;
2864 mlxsw_sp_rt6
->rt
->rt6i_nh_flags
&= ~RTNH_F_OFFLOAD
;
2869 mlxsw_sp_fib6_entry_offload_unset(struct mlxsw_sp_fib_entry
*fib_entry
)
2871 struct mlxsw_sp_fib6_entry
*fib6_entry
;
2872 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
2874 fib6_entry
= container_of(fib_entry
, struct mlxsw_sp_fib6_entry
,
2876 list_for_each_entry(mlxsw_sp_rt6
, &fib6_entry
->rt6_list
, list
) {
2877 struct rt6_info
*rt
= mlxsw_sp_rt6
->rt
;
2879 rt
->rt6i_nh_flags
&= ~RTNH_F_OFFLOAD
;
2883 static void mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry
*fib_entry
)
2885 switch (fib_entry
->fib_node
->fib
->proto
) {
2886 case MLXSW_SP_L3_PROTO_IPV4
:
2887 mlxsw_sp_fib4_entry_offload_set(fib_entry
);
2889 case MLXSW_SP_L3_PROTO_IPV6
:
2890 mlxsw_sp_fib6_entry_offload_set(fib_entry
);
2896 mlxsw_sp_fib_entry_offload_unset(struct mlxsw_sp_fib_entry
*fib_entry
)
2898 switch (fib_entry
->fib_node
->fib
->proto
) {
2899 case MLXSW_SP_L3_PROTO_IPV4
:
2900 mlxsw_sp_fib4_entry_offload_unset(fib_entry
);
2902 case MLXSW_SP_L3_PROTO_IPV6
:
2903 mlxsw_sp_fib6_entry_offload_unset(fib_entry
);
2909 mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry
*fib_entry
,
2910 enum mlxsw_reg_ralue_op op
, int err
)
2913 case MLXSW_REG_RALUE_OP_WRITE_DELETE
:
2914 return mlxsw_sp_fib_entry_offload_unset(fib_entry
);
2915 case MLXSW_REG_RALUE_OP_WRITE_WRITE
:
2918 if (mlxsw_sp_fib_entry_should_offload(fib_entry
))
2919 mlxsw_sp_fib_entry_offload_set(fib_entry
);
2920 else if (!mlxsw_sp_fib_entry_should_offload(fib_entry
))
2921 mlxsw_sp_fib_entry_offload_unset(fib_entry
);
2929 mlxsw_sp_fib_entry_ralue_pack(char *ralue_pl
,
2930 const struct mlxsw_sp_fib_entry
*fib_entry
,
2931 enum mlxsw_reg_ralue_op op
)
2933 struct mlxsw_sp_fib
*fib
= fib_entry
->fib_node
->fib
;
2934 enum mlxsw_reg_ralxx_protocol proto
;
2937 proto
= (enum mlxsw_reg_ralxx_protocol
) fib
->proto
;
2939 switch (fib
->proto
) {
2940 case MLXSW_SP_L3_PROTO_IPV4
:
2941 p_dip
= (u32
*) fib_entry
->fib_node
->key
.addr
;
2942 mlxsw_reg_ralue_pack4(ralue_pl
, proto
, op
, fib
->vr
->id
,
2943 fib_entry
->fib_node
->key
.prefix_len
,
2946 case MLXSW_SP_L3_PROTO_IPV6
:
2947 mlxsw_reg_ralue_pack6(ralue_pl
, proto
, op
, fib
->vr
->id
,
2948 fib_entry
->fib_node
->key
.prefix_len
,
2949 fib_entry
->fib_node
->key
.addr
);
2954 static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp
*mlxsw_sp
,
2955 struct mlxsw_sp_fib_entry
*fib_entry
,
2956 enum mlxsw_reg_ralue_op op
)
2958 char ralue_pl
[MLXSW_REG_RALUE_LEN
];
2959 enum mlxsw_reg_ralue_trap_action trap_action
;
2961 u32 adjacency_index
= 0;
2964 /* In case the nexthop group adjacency index is valid, use it
2965 * with provided ECMP size. Otherwise, setup trap and pass
2966 * traffic to kernel.
2968 if (mlxsw_sp_fib_entry_should_offload(fib_entry
)) {
2969 trap_action
= MLXSW_REG_RALUE_TRAP_ACTION_NOP
;
2970 adjacency_index
= fib_entry
->nh_group
->adj_index
;
2971 ecmp_size
= fib_entry
->nh_group
->ecmp_size
;
2973 trap_action
= MLXSW_REG_RALUE_TRAP_ACTION_TRAP
;
2974 trap_id
= MLXSW_TRAP_ID_RTR_INGRESS0
;
2977 mlxsw_sp_fib_entry_ralue_pack(ralue_pl
, fib_entry
, op
);
2978 mlxsw_reg_ralue_act_remote_pack(ralue_pl
, trap_action
, trap_id
,
2979 adjacency_index
, ecmp_size
);
2980 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralue
), ralue_pl
);
2983 static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp
*mlxsw_sp
,
2984 struct mlxsw_sp_fib_entry
*fib_entry
,
2985 enum mlxsw_reg_ralue_op op
)
2987 struct mlxsw_sp_rif
*rif
= fib_entry
->nh_group
->nh_rif
;
2988 enum mlxsw_reg_ralue_trap_action trap_action
;
2989 char ralue_pl
[MLXSW_REG_RALUE_LEN
];
2993 if (mlxsw_sp_fib_entry_should_offload(fib_entry
)) {
2994 trap_action
= MLXSW_REG_RALUE_TRAP_ACTION_NOP
;
2995 rif_index
= rif
->rif_index
;
2997 trap_action
= MLXSW_REG_RALUE_TRAP_ACTION_TRAP
;
2998 trap_id
= MLXSW_TRAP_ID_RTR_INGRESS0
;
3001 mlxsw_sp_fib_entry_ralue_pack(ralue_pl
, fib_entry
, op
);
3002 mlxsw_reg_ralue_act_local_pack(ralue_pl
, trap_action
, trap_id
,
3004 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralue
), ralue_pl
);
3007 static int mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp
*mlxsw_sp
,
3008 struct mlxsw_sp_fib_entry
*fib_entry
,
3009 enum mlxsw_reg_ralue_op op
)
3011 char ralue_pl
[MLXSW_REG_RALUE_LEN
];
3013 mlxsw_sp_fib_entry_ralue_pack(ralue_pl
, fib_entry
, op
);
3014 mlxsw_reg_ralue_act_ip2me_pack(ralue_pl
);
3015 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralue
), ralue_pl
);
3018 static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp
*mlxsw_sp
,
3019 struct mlxsw_sp_fib_entry
*fib_entry
,
3020 enum mlxsw_reg_ralue_op op
)
3022 switch (fib_entry
->type
) {
3023 case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE
:
3024 return mlxsw_sp_fib_entry_op_remote(mlxsw_sp
, fib_entry
, op
);
3025 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
:
3026 return mlxsw_sp_fib_entry_op_local(mlxsw_sp
, fib_entry
, op
);
3027 case MLXSW_SP_FIB_ENTRY_TYPE_TRAP
:
3028 return mlxsw_sp_fib_entry_op_trap(mlxsw_sp
, fib_entry
, op
);
3033 static int mlxsw_sp_fib_entry_op(struct mlxsw_sp
*mlxsw_sp
,
3034 struct mlxsw_sp_fib_entry
*fib_entry
,
3035 enum mlxsw_reg_ralue_op op
)
3037 int err
= __mlxsw_sp_fib_entry_op(mlxsw_sp
, fib_entry
, op
);
3039 mlxsw_sp_fib_entry_offload_refresh(fib_entry
, op
, err
);
3044 static int mlxsw_sp_fib_entry_update(struct mlxsw_sp
*mlxsw_sp
,
3045 struct mlxsw_sp_fib_entry
*fib_entry
)
3047 return mlxsw_sp_fib_entry_op(mlxsw_sp
, fib_entry
,
3048 MLXSW_REG_RALUE_OP_WRITE_WRITE
);
3051 static int mlxsw_sp_fib_entry_del(struct mlxsw_sp
*mlxsw_sp
,
3052 struct mlxsw_sp_fib_entry
*fib_entry
)
3054 return mlxsw_sp_fib_entry_op(mlxsw_sp
, fib_entry
,
3055 MLXSW_REG_RALUE_OP_WRITE_DELETE
);
3059 mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp
*mlxsw_sp
,
3060 const struct fib_entry_notifier_info
*fen_info
,
3061 struct mlxsw_sp_fib_entry
*fib_entry
)
3063 struct fib_info
*fi
= fen_info
->fi
;
3065 switch (fen_info
->type
) {
3066 case RTN_BROADCAST
: /* fall through */
3068 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_TRAP
;
3070 case RTN_UNREACHABLE
: /* fall through */
3071 case RTN_BLACKHOLE
: /* fall through */
3073 /* Packets hitting these routes need to be trapped, but
3074 * can do so with a lower priority than packets directed
3075 * at the host, so use action type local instead of trap.
3077 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
;
3080 if (mlxsw_sp_fi_is_gateway(mlxsw_sp
, fi
))
3081 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_REMOTE
;
3083 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
;
3090 static struct mlxsw_sp_fib4_entry
*
3091 mlxsw_sp_fib4_entry_create(struct mlxsw_sp
*mlxsw_sp
,
3092 struct mlxsw_sp_fib_node
*fib_node
,
3093 const struct fib_entry_notifier_info
*fen_info
)
3095 struct mlxsw_sp_fib4_entry
*fib4_entry
;
3096 struct mlxsw_sp_fib_entry
*fib_entry
;
3099 fib4_entry
= kzalloc(sizeof(*fib4_entry
), GFP_KERNEL
);
3101 return ERR_PTR(-ENOMEM
);
3102 fib_entry
= &fib4_entry
->common
;
3104 err
= mlxsw_sp_fib4_entry_type_set(mlxsw_sp
, fen_info
, fib_entry
);
3106 goto err_fib4_entry_type_set
;
3108 err
= mlxsw_sp_nexthop4_group_get(mlxsw_sp
, fib_entry
, fen_info
->fi
);
3110 goto err_nexthop4_group_get
;
3112 fib4_entry
->prio
= fen_info
->fi
->fib_priority
;
3113 fib4_entry
->tb_id
= fen_info
->tb_id
;
3114 fib4_entry
->type
= fen_info
->type
;
3115 fib4_entry
->tos
= fen_info
->tos
;
3117 fib_entry
->fib_node
= fib_node
;
3121 err_nexthop4_group_get
:
3122 err_fib4_entry_type_set
:
3124 return ERR_PTR(err
);
3127 static void mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp
*mlxsw_sp
,
3128 struct mlxsw_sp_fib4_entry
*fib4_entry
)
3130 mlxsw_sp_nexthop4_group_put(mlxsw_sp
, &fib4_entry
->common
);
3134 static struct mlxsw_sp_fib_node
*
3135 mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib
*fib
, const void *addr
,
3136 size_t addr_len
, unsigned char prefix_len
);
3138 static struct mlxsw_sp_fib4_entry
*
3139 mlxsw_sp_fib4_entry_lookup(struct mlxsw_sp
*mlxsw_sp
,
3140 const struct fib_entry_notifier_info
*fen_info
)
3142 struct mlxsw_sp_fib4_entry
*fib4_entry
;
3143 struct mlxsw_sp_fib_node
*fib_node
;
3144 struct mlxsw_sp_fib
*fib
;
3145 struct mlxsw_sp_vr
*vr
;
3147 vr
= mlxsw_sp_vr_find(mlxsw_sp
, fen_info
->tb_id
);
3150 fib
= mlxsw_sp_vr_fib(vr
, MLXSW_SP_L3_PROTO_IPV4
);
3152 fib_node
= mlxsw_sp_fib_node_lookup(fib
, &fen_info
->dst
,
3153 sizeof(fen_info
->dst
),
3158 list_for_each_entry(fib4_entry
, &fib_node
->entry_list
, common
.list
) {
3159 if (fib4_entry
->tb_id
== fen_info
->tb_id
&&
3160 fib4_entry
->tos
== fen_info
->tos
&&
3161 fib4_entry
->type
== fen_info
->type
&&
3162 mlxsw_sp_nexthop4_group_fi(fib4_entry
->common
.nh_group
) ==
3171 static const struct rhashtable_params mlxsw_sp_fib_ht_params
= {
3172 .key_offset
= offsetof(struct mlxsw_sp_fib_node
, key
),
3173 .head_offset
= offsetof(struct mlxsw_sp_fib_node
, ht_node
),
3174 .key_len
= sizeof(struct mlxsw_sp_fib_key
),
3175 .automatic_shrinking
= true,
3178 static int mlxsw_sp_fib_node_insert(struct mlxsw_sp_fib
*fib
,
3179 struct mlxsw_sp_fib_node
*fib_node
)
3181 return rhashtable_insert_fast(&fib
->ht
, &fib_node
->ht_node
,
3182 mlxsw_sp_fib_ht_params
);
3185 static void mlxsw_sp_fib_node_remove(struct mlxsw_sp_fib
*fib
,
3186 struct mlxsw_sp_fib_node
*fib_node
)
3188 rhashtable_remove_fast(&fib
->ht
, &fib_node
->ht_node
,
3189 mlxsw_sp_fib_ht_params
);
3192 static struct mlxsw_sp_fib_node
*
3193 mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib
*fib
, const void *addr
,
3194 size_t addr_len
, unsigned char prefix_len
)
3196 struct mlxsw_sp_fib_key key
;
3198 memset(&key
, 0, sizeof(key
));
3199 memcpy(key
.addr
, addr
, addr_len
);
3200 key
.prefix_len
= prefix_len
;
3201 return rhashtable_lookup_fast(&fib
->ht
, &key
, mlxsw_sp_fib_ht_params
);
3204 static struct mlxsw_sp_fib_node
*
3205 mlxsw_sp_fib_node_create(struct mlxsw_sp_fib
*fib
, const void *addr
,
3206 size_t addr_len
, unsigned char prefix_len
)
3208 struct mlxsw_sp_fib_node
*fib_node
;
3210 fib_node
= kzalloc(sizeof(*fib_node
), GFP_KERNEL
);
3214 INIT_LIST_HEAD(&fib_node
->entry_list
);
3215 list_add(&fib_node
->list
, &fib
->node_list
);
3216 memcpy(fib_node
->key
.addr
, addr
, addr_len
);
3217 fib_node
->key
.prefix_len
= prefix_len
;
3222 static void mlxsw_sp_fib_node_destroy(struct mlxsw_sp_fib_node
*fib_node
)
3224 list_del(&fib_node
->list
);
3225 WARN_ON(!list_empty(&fib_node
->entry_list
));
3230 mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node
*fib_node
,
3231 const struct mlxsw_sp_fib_entry
*fib_entry
)
3233 return list_first_entry(&fib_node
->entry_list
,
3234 struct mlxsw_sp_fib_entry
, list
) == fib_entry
;
3237 static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp
*mlxsw_sp
,
3238 struct mlxsw_sp_fib
*fib
,
3239 struct mlxsw_sp_fib_node
*fib_node
)
3241 struct mlxsw_sp_prefix_usage req_prefix_usage
= {{ 0 } };
3242 struct mlxsw_sp_lpm_tree
*lpm_tree
;
3245 /* Since the tree is shared between all virtual routers we must
3246 * make sure it contains all the required prefix lengths. This
3247 * can be computed by either adding the new prefix length to the
3248 * existing prefix usage of a bound tree, or by aggregating the
3249 * prefix lengths across all virtual routers and adding the new
3253 mlxsw_sp_prefix_usage_cpy(&req_prefix_usage
,
3254 &fib
->lpm_tree
->prefix_usage
);
3256 mlxsw_sp_vrs_prefixes(mlxsw_sp
, fib
->proto
, &req_prefix_usage
);
3257 mlxsw_sp_prefix_usage_set(&req_prefix_usage
, fib_node
->key
.prefix_len
);
3259 lpm_tree
= mlxsw_sp_lpm_tree_get(mlxsw_sp
, &req_prefix_usage
,
3261 if (IS_ERR(lpm_tree
))
3262 return PTR_ERR(lpm_tree
);
3264 if (fib
->lpm_tree
&& fib
->lpm_tree
->id
== lpm_tree
->id
)
3267 err
= mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp
, fib
, lpm_tree
);
3274 static void mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp
*mlxsw_sp
,
3275 struct mlxsw_sp_fib
*fib
)
3277 struct mlxsw_sp_prefix_usage req_prefix_usage
= {{ 0 } };
3278 struct mlxsw_sp_lpm_tree
*lpm_tree
;
3280 /* Aggregate prefix lengths across all virtual routers to make
3281 * sure we only have used prefix lengths in the LPM tree.
3283 mlxsw_sp_vrs_prefixes(mlxsw_sp
, fib
->proto
, &req_prefix_usage
);
3284 lpm_tree
= mlxsw_sp_lpm_tree_get(mlxsw_sp
, &req_prefix_usage
,
3286 if (IS_ERR(lpm_tree
))
3288 mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp
, fib
, lpm_tree
);
3291 if (!mlxsw_sp_prefix_usage_none(&fib
->prefix_usage
))
3293 mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp
, fib
);
3294 mlxsw_sp_lpm_tree_put(mlxsw_sp
, fib
->lpm_tree
);
3295 fib
->lpm_tree
= NULL
;
3298 static void mlxsw_sp_fib_node_prefix_inc(struct mlxsw_sp_fib_node
*fib_node
)
3300 unsigned char prefix_len
= fib_node
->key
.prefix_len
;
3301 struct mlxsw_sp_fib
*fib
= fib_node
->fib
;
3303 if (fib
->prefix_ref_count
[prefix_len
]++ == 0)
3304 mlxsw_sp_prefix_usage_set(&fib
->prefix_usage
, prefix_len
);
3307 static void mlxsw_sp_fib_node_prefix_dec(struct mlxsw_sp_fib_node
*fib_node
)
3309 unsigned char prefix_len
= fib_node
->key
.prefix_len
;
3310 struct mlxsw_sp_fib
*fib
= fib_node
->fib
;
3312 if (--fib
->prefix_ref_count
[prefix_len
] == 0)
3313 mlxsw_sp_prefix_usage_clear(&fib
->prefix_usage
, prefix_len
);
3316 static int mlxsw_sp_fib_node_init(struct mlxsw_sp
*mlxsw_sp
,
3317 struct mlxsw_sp_fib_node
*fib_node
,
3318 struct mlxsw_sp_fib
*fib
)
3322 err
= mlxsw_sp_fib_node_insert(fib
, fib_node
);
3325 fib_node
->fib
= fib
;
3327 err
= mlxsw_sp_fib_lpm_tree_link(mlxsw_sp
, fib
, fib_node
);
3329 goto err_fib_lpm_tree_link
;
3331 mlxsw_sp_fib_node_prefix_inc(fib_node
);
3335 err_fib_lpm_tree_link
:
3336 fib_node
->fib
= NULL
;
3337 mlxsw_sp_fib_node_remove(fib
, fib_node
);
3341 static void mlxsw_sp_fib_node_fini(struct mlxsw_sp
*mlxsw_sp
,
3342 struct mlxsw_sp_fib_node
*fib_node
)
3344 struct mlxsw_sp_fib
*fib
= fib_node
->fib
;
3346 mlxsw_sp_fib_node_prefix_dec(fib_node
);
3347 mlxsw_sp_fib_lpm_tree_unlink(mlxsw_sp
, fib
);
3348 fib_node
->fib
= NULL
;
3349 mlxsw_sp_fib_node_remove(fib
, fib_node
);
3352 static struct mlxsw_sp_fib_node
*
3353 mlxsw_sp_fib_node_get(struct mlxsw_sp
*mlxsw_sp
, u32 tb_id
, const void *addr
,
3354 size_t addr_len
, unsigned char prefix_len
,
3355 enum mlxsw_sp_l3proto proto
)
3357 struct mlxsw_sp_fib_node
*fib_node
;
3358 struct mlxsw_sp_fib
*fib
;
3359 struct mlxsw_sp_vr
*vr
;
3362 vr
= mlxsw_sp_vr_get(mlxsw_sp
, tb_id
);
3364 return ERR_CAST(vr
);
3365 fib
= mlxsw_sp_vr_fib(vr
, proto
);
3367 fib_node
= mlxsw_sp_fib_node_lookup(fib
, addr
, addr_len
, prefix_len
);
3371 fib_node
= mlxsw_sp_fib_node_create(fib
, addr
, addr_len
, prefix_len
);
3374 goto err_fib_node_create
;
3377 err
= mlxsw_sp_fib_node_init(mlxsw_sp
, fib_node
, fib
);
3379 goto err_fib_node_init
;
3384 mlxsw_sp_fib_node_destroy(fib_node
);
3385 err_fib_node_create
:
3386 mlxsw_sp_vr_put(vr
);
3387 return ERR_PTR(err
);
3390 static void mlxsw_sp_fib_node_put(struct mlxsw_sp
*mlxsw_sp
,
3391 struct mlxsw_sp_fib_node
*fib_node
)
3393 struct mlxsw_sp_vr
*vr
= fib_node
->fib
->vr
;
3395 if (!list_empty(&fib_node
->entry_list
))
3397 mlxsw_sp_fib_node_fini(mlxsw_sp
, fib_node
);
3398 mlxsw_sp_fib_node_destroy(fib_node
);
3399 mlxsw_sp_vr_put(vr
);
3402 static struct mlxsw_sp_fib4_entry
*
3403 mlxsw_sp_fib4_node_entry_find(const struct mlxsw_sp_fib_node
*fib_node
,
3404 const struct mlxsw_sp_fib4_entry
*new4_entry
)
3406 struct mlxsw_sp_fib4_entry
*fib4_entry
;
3408 list_for_each_entry(fib4_entry
, &fib_node
->entry_list
, common
.list
) {
3409 if (fib4_entry
->tb_id
> new4_entry
->tb_id
)
3411 if (fib4_entry
->tb_id
!= new4_entry
->tb_id
)
3413 if (fib4_entry
->tos
> new4_entry
->tos
)
3415 if (fib4_entry
->prio
>= new4_entry
->prio
||
3416 fib4_entry
->tos
< new4_entry
->tos
)
3424 mlxsw_sp_fib4_node_list_append(struct mlxsw_sp_fib4_entry
*fib4_entry
,
3425 struct mlxsw_sp_fib4_entry
*new4_entry
)
3427 struct mlxsw_sp_fib_node
*fib_node
;
3429 if (WARN_ON(!fib4_entry
))
3432 fib_node
= fib4_entry
->common
.fib_node
;
3433 list_for_each_entry_from(fib4_entry
, &fib_node
->entry_list
,
3435 if (fib4_entry
->tb_id
!= new4_entry
->tb_id
||
3436 fib4_entry
->tos
!= new4_entry
->tos
||
3437 fib4_entry
->prio
!= new4_entry
->prio
)
3441 list_add_tail(&new4_entry
->common
.list
, &fib4_entry
->common
.list
);
3446 mlxsw_sp_fib4_node_list_insert(struct mlxsw_sp_fib4_entry
*new4_entry
,
3447 bool replace
, bool append
)
3449 struct mlxsw_sp_fib_node
*fib_node
= new4_entry
->common
.fib_node
;
3450 struct mlxsw_sp_fib4_entry
*fib4_entry
;
3452 fib4_entry
= mlxsw_sp_fib4_node_entry_find(fib_node
, new4_entry
);
3455 return mlxsw_sp_fib4_node_list_append(fib4_entry
, new4_entry
);
3456 if (replace
&& WARN_ON(!fib4_entry
))
3459 /* Insert new entry before replaced one, so that we can later
3460 * remove the second.
3463 list_add_tail(&new4_entry
->common
.list
,
3464 &fib4_entry
->common
.list
);
3466 struct mlxsw_sp_fib4_entry
*last
;
3468 list_for_each_entry(last
, &fib_node
->entry_list
, common
.list
) {
3469 if (new4_entry
->tb_id
> last
->tb_id
)
3475 list_add(&new4_entry
->common
.list
,
3476 &fib4_entry
->common
.list
);
3478 list_add(&new4_entry
->common
.list
,
3479 &fib_node
->entry_list
);
3486 mlxsw_sp_fib4_node_list_remove(struct mlxsw_sp_fib4_entry
*fib4_entry
)
3488 list_del(&fib4_entry
->common
.list
);
3491 static int mlxsw_sp_fib_node_entry_add(struct mlxsw_sp
*mlxsw_sp
,
3492 struct mlxsw_sp_fib_entry
*fib_entry
)
3494 struct mlxsw_sp_fib_node
*fib_node
= fib_entry
->fib_node
;
3496 if (!mlxsw_sp_fib_node_entry_is_first(fib_node
, fib_entry
))
3499 /* To prevent packet loss, overwrite the previously offloaded
3502 if (!list_is_singular(&fib_node
->entry_list
)) {
3503 enum mlxsw_reg_ralue_op op
= MLXSW_REG_RALUE_OP_WRITE_DELETE
;
3504 struct mlxsw_sp_fib_entry
*n
= list_next_entry(fib_entry
, list
);
3506 mlxsw_sp_fib_entry_offload_refresh(n
, op
, 0);
3509 return mlxsw_sp_fib_entry_update(mlxsw_sp
, fib_entry
);
3512 static void mlxsw_sp_fib_node_entry_del(struct mlxsw_sp
*mlxsw_sp
,
3513 struct mlxsw_sp_fib_entry
*fib_entry
)
3515 struct mlxsw_sp_fib_node
*fib_node
= fib_entry
->fib_node
;
3517 if (!mlxsw_sp_fib_node_entry_is_first(fib_node
, fib_entry
))
3520 /* Promote the next entry by overwriting the deleted entry */
3521 if (!list_is_singular(&fib_node
->entry_list
)) {
3522 struct mlxsw_sp_fib_entry
*n
= list_next_entry(fib_entry
, list
);
3523 enum mlxsw_reg_ralue_op op
= MLXSW_REG_RALUE_OP_WRITE_DELETE
;
3525 mlxsw_sp_fib_entry_update(mlxsw_sp
, n
);
3526 mlxsw_sp_fib_entry_offload_refresh(fib_entry
, op
, 0);
3530 mlxsw_sp_fib_entry_del(mlxsw_sp
, fib_entry
);
3533 static int mlxsw_sp_fib4_node_entry_link(struct mlxsw_sp
*mlxsw_sp
,
3534 struct mlxsw_sp_fib4_entry
*fib4_entry
,
3535 bool replace
, bool append
)
3539 err
= mlxsw_sp_fib4_node_list_insert(fib4_entry
, replace
, append
);
3543 err
= mlxsw_sp_fib_node_entry_add(mlxsw_sp
, &fib4_entry
->common
);
3545 goto err_fib_node_entry_add
;
3549 err_fib_node_entry_add
:
3550 mlxsw_sp_fib4_node_list_remove(fib4_entry
);
3555 mlxsw_sp_fib4_node_entry_unlink(struct mlxsw_sp
*mlxsw_sp
,
3556 struct mlxsw_sp_fib4_entry
*fib4_entry
)
3558 mlxsw_sp_fib_node_entry_del(mlxsw_sp
, &fib4_entry
->common
);
3559 mlxsw_sp_fib4_node_list_remove(fib4_entry
);
3562 static void mlxsw_sp_fib4_entry_replace(struct mlxsw_sp
*mlxsw_sp
,
3563 struct mlxsw_sp_fib4_entry
*fib4_entry
,
3566 struct mlxsw_sp_fib_node
*fib_node
= fib4_entry
->common
.fib_node
;
3567 struct mlxsw_sp_fib4_entry
*replaced
;
3572 /* We inserted the new entry before replaced one */
3573 replaced
= list_next_entry(fib4_entry
, common
.list
);
3575 mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp
, replaced
);
3576 mlxsw_sp_fib4_entry_destroy(mlxsw_sp
, replaced
);
3577 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
3581 mlxsw_sp_router_fib4_add(struct mlxsw_sp
*mlxsw_sp
,
3582 const struct fib_entry_notifier_info
*fen_info
,
3583 bool replace
, bool append
)
3585 struct mlxsw_sp_fib4_entry
*fib4_entry
;
3586 struct mlxsw_sp_fib_node
*fib_node
;
3589 if (mlxsw_sp
->router
->aborted
)
3592 fib_node
= mlxsw_sp_fib_node_get(mlxsw_sp
, fen_info
->tb_id
,
3593 &fen_info
->dst
, sizeof(fen_info
->dst
),
3595 MLXSW_SP_L3_PROTO_IPV4
);
3596 if (IS_ERR(fib_node
)) {
3597 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to get FIB node\n");
3598 return PTR_ERR(fib_node
);
3601 fib4_entry
= mlxsw_sp_fib4_entry_create(mlxsw_sp
, fib_node
, fen_info
);
3602 if (IS_ERR(fib4_entry
)) {
3603 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to create FIB entry\n");
3604 err
= PTR_ERR(fib4_entry
);
3605 goto err_fib4_entry_create
;
3608 err
= mlxsw_sp_fib4_node_entry_link(mlxsw_sp
, fib4_entry
, replace
,
3611 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to link FIB entry to node\n");
3612 goto err_fib4_node_entry_link
;
3615 mlxsw_sp_fib4_entry_replace(mlxsw_sp
, fib4_entry
, replace
);
3619 err_fib4_node_entry_link
:
3620 mlxsw_sp_fib4_entry_destroy(mlxsw_sp
, fib4_entry
);
3621 err_fib4_entry_create
:
3622 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
3626 static void mlxsw_sp_router_fib4_del(struct mlxsw_sp
*mlxsw_sp
,
3627 struct fib_entry_notifier_info
*fen_info
)
3629 struct mlxsw_sp_fib4_entry
*fib4_entry
;
3630 struct mlxsw_sp_fib_node
*fib_node
;
3632 if (mlxsw_sp
->router
->aborted
)
3635 fib4_entry
= mlxsw_sp_fib4_entry_lookup(mlxsw_sp
, fen_info
);
3636 if (WARN_ON(!fib4_entry
))
3638 fib_node
= fib4_entry
->common
.fib_node
;
3640 mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp
, fib4_entry
);
3641 mlxsw_sp_fib4_entry_destroy(mlxsw_sp
, fib4_entry
);
3642 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
3645 static bool mlxsw_sp_fib6_rt_should_ignore(const struct rt6_info
*rt
)
3647 /* Packets with link-local destination IP arriving to the router
3648 * are trapped to the CPU, so no need to program specific routes
3651 if (ipv6_addr_type(&rt
->rt6i_dst
.addr
) & IPV6_ADDR_LINKLOCAL
)
3654 /* Multicast routes aren't supported, so ignore them. Neighbour
3655 * Discovery packets are specifically trapped.
3657 if (ipv6_addr_type(&rt
->rt6i_dst
.addr
) & IPV6_ADDR_MULTICAST
)
3660 /* Cloned routes are irrelevant in the forwarding path. */
3661 if (rt
->rt6i_flags
& RTF_CACHE
)
3667 static struct mlxsw_sp_rt6
*mlxsw_sp_rt6_create(struct rt6_info
*rt
)
3669 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
3671 mlxsw_sp_rt6
= kzalloc(sizeof(*mlxsw_sp_rt6
), GFP_KERNEL
);
3673 return ERR_PTR(-ENOMEM
);
3675 /* In case of route replace, replaced route is deleted with
3676 * no notification. Take reference to prevent accessing freed
3679 mlxsw_sp_rt6
->rt
= rt
;
3682 return mlxsw_sp_rt6
;
3685 #if IS_ENABLED(CONFIG_IPV6)
3686 static void mlxsw_sp_rt6_release(struct rt6_info
*rt
)
3691 static void mlxsw_sp_rt6_release(struct rt6_info
*rt
)
3696 static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6
*mlxsw_sp_rt6
)
3698 mlxsw_sp_rt6_release(mlxsw_sp_rt6
->rt
);
3699 kfree(mlxsw_sp_rt6
);
3702 static bool mlxsw_sp_fib6_rt_can_mp(const struct rt6_info
*rt
)
3704 /* RTF_CACHE routes are ignored */
3705 return (rt
->rt6i_flags
& (RTF_GATEWAY
| RTF_ADDRCONF
)) == RTF_GATEWAY
;
3708 static struct rt6_info
*
3709 mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry
*fib6_entry
)
3711 return list_first_entry(&fib6_entry
->rt6_list
, struct mlxsw_sp_rt6
,
3715 static struct mlxsw_sp_fib6_entry
*
3716 mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node
*fib_node
,
3717 const struct rt6_info
*nrt
, bool replace
)
3719 struct mlxsw_sp_fib6_entry
*fib6_entry
;
3721 if (!mlxsw_sp_fib6_rt_can_mp(nrt
) || replace
)
3724 list_for_each_entry(fib6_entry
, &fib_node
->entry_list
, common
.list
) {
3725 struct rt6_info
*rt
= mlxsw_sp_fib6_entry_rt(fib6_entry
);
3727 /* RT6_TABLE_LOCAL and RT6_TABLE_MAIN share the same
3730 if (rt
->rt6i_table
->tb6_id
> nrt
->rt6i_table
->tb6_id
)
3732 if (rt
->rt6i_table
->tb6_id
!= nrt
->rt6i_table
->tb6_id
)
3734 if (rt
->rt6i_metric
< nrt
->rt6i_metric
)
3736 if (rt
->rt6i_metric
== nrt
->rt6i_metric
&&
3737 mlxsw_sp_fib6_rt_can_mp(rt
))
3739 if (rt
->rt6i_metric
> nrt
->rt6i_metric
)
3746 static struct mlxsw_sp_rt6
*
3747 mlxsw_sp_fib6_entry_rt_find(const struct mlxsw_sp_fib6_entry
*fib6_entry
,
3748 const struct rt6_info
*rt
)
3750 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
3752 list_for_each_entry(mlxsw_sp_rt6
, &fib6_entry
->rt6_list
, list
) {
3753 if (mlxsw_sp_rt6
->rt
== rt
)
3754 return mlxsw_sp_rt6
;
3760 static bool mlxsw_sp_nexthop6_ipip_type(const struct mlxsw_sp
*mlxsw_sp
,
3761 const struct rt6_info
*rt
,
3762 enum mlxsw_sp_ipip_type
*ret
)
3764 return rt
->dst
.dev
&&
3765 mlxsw_sp_netdev_ipip_type(mlxsw_sp
, rt
->dst
.dev
, ret
);
3768 static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp
*mlxsw_sp
,
3769 struct mlxsw_sp_nexthop_group
*nh_grp
,
3770 struct mlxsw_sp_nexthop
*nh
,
3771 const struct rt6_info
*rt
)
3773 struct mlxsw_sp_router
*router
= mlxsw_sp
->router
;
3774 struct net_device
*dev
= rt
->dst
.dev
;
3775 enum mlxsw_sp_ipip_type ipipt
;
3776 struct mlxsw_sp_rif
*rif
;
3779 if (mlxsw_sp_nexthop6_ipip_type(mlxsw_sp
, rt
, &ipipt
) &&
3780 router
->ipip_ops_arr
[ipipt
]->can_offload(mlxsw_sp
, dev
,
3781 MLXSW_SP_L3_PROTO_IPV6
)) {
3782 nh
->type
= MLXSW_SP_NEXTHOP_TYPE_IPIP
;
3783 return mlxsw_sp_nexthop_ipip_init(mlxsw_sp
, ipipt
, nh
, dev
);
3786 nh
->type
= MLXSW_SP_NEXTHOP_TYPE_ETH
;
3787 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, dev
);
3790 mlxsw_sp_nexthop_rif_init(nh
, rif
);
3792 err
= mlxsw_sp_nexthop_neigh_init(mlxsw_sp
, nh
);
3794 goto err_nexthop_neigh_init
;
3798 err_nexthop_neigh_init
:
3799 mlxsw_sp_nexthop_rif_fini(nh
);
3803 static void mlxsw_sp_nexthop6_type_fini(struct mlxsw_sp
*mlxsw_sp
,
3804 struct mlxsw_sp_nexthop
*nh
)
3806 mlxsw_sp_nexthop_type_fini(mlxsw_sp
, nh
);
3809 static int mlxsw_sp_nexthop6_init(struct mlxsw_sp
*mlxsw_sp
,
3810 struct mlxsw_sp_nexthop_group
*nh_grp
,
3811 struct mlxsw_sp_nexthop
*nh
,
3812 const struct rt6_info
*rt
)
3814 struct net_device
*dev
= rt
->dst
.dev
;
3816 nh
->nh_grp
= nh_grp
;
3817 memcpy(&nh
->gw_addr
, &rt
->rt6i_gateway
, sizeof(nh
->gw_addr
));
3821 nh
->ifindex
= dev
->ifindex
;
3823 return mlxsw_sp_nexthop6_type_init(mlxsw_sp
, nh_grp
, nh
, rt
);
3826 static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp
*mlxsw_sp
,
3827 struct mlxsw_sp_nexthop
*nh
)
3829 mlxsw_sp_nexthop6_type_fini(mlxsw_sp
, nh
);
3832 static bool mlxsw_sp_rt6_is_gateway(const struct mlxsw_sp
*mlxsw_sp
,
3833 const struct rt6_info
*rt
)
3835 return rt
->rt6i_flags
& RTF_GATEWAY
||
3836 mlxsw_sp_nexthop6_ipip_type(mlxsw_sp
, rt
, NULL
);
3839 static struct mlxsw_sp_nexthop_group
*
3840 mlxsw_sp_nexthop6_group_create(struct mlxsw_sp
*mlxsw_sp
,
3841 struct mlxsw_sp_fib6_entry
*fib6_entry
)
3843 struct mlxsw_sp_nexthop_group
*nh_grp
;
3844 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
3845 struct mlxsw_sp_nexthop
*nh
;
3850 alloc_size
= sizeof(*nh_grp
) +
3851 fib6_entry
->nrt6
* sizeof(struct mlxsw_sp_nexthop
);
3852 nh_grp
= kzalloc(alloc_size
, GFP_KERNEL
);
3854 return ERR_PTR(-ENOMEM
);
3855 INIT_LIST_HEAD(&nh_grp
->fib_list
);
3856 #if IS_ENABLED(CONFIG_IPV6)
3857 nh_grp
->neigh_tbl
= &nd_tbl
;
3859 mlxsw_sp_rt6
= list_first_entry(&fib6_entry
->rt6_list
,
3860 struct mlxsw_sp_rt6
, list
);
3861 nh_grp
->gateway
= mlxsw_sp_rt6_is_gateway(mlxsw_sp
, mlxsw_sp_rt6
->rt
);
3862 nh_grp
->count
= fib6_entry
->nrt6
;
3863 for (i
= 0; i
< nh_grp
->count
; i
++) {
3864 struct rt6_info
*rt
= mlxsw_sp_rt6
->rt
;
3866 nh
= &nh_grp
->nexthops
[i
];
3867 err
= mlxsw_sp_nexthop6_init(mlxsw_sp
, nh_grp
, nh
, rt
);
3869 goto err_nexthop6_init
;
3870 mlxsw_sp_rt6
= list_next_entry(mlxsw_sp_rt6
, list
);
3873 err
= mlxsw_sp_nexthop_group_insert(mlxsw_sp
, nh_grp
);
3875 goto err_nexthop_group_insert
;
3877 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh_grp
);
3880 err_nexthop_group_insert
:
3882 for (i
--; i
>= 0; i
--) {
3883 nh
= &nh_grp
->nexthops
[i
];
3884 mlxsw_sp_nexthop6_fini(mlxsw_sp
, nh
);
3887 return ERR_PTR(err
);
3891 mlxsw_sp_nexthop6_group_destroy(struct mlxsw_sp
*mlxsw_sp
,
3892 struct mlxsw_sp_nexthop_group
*nh_grp
)
3894 struct mlxsw_sp_nexthop
*nh
;
3895 int i
= nh_grp
->count
;
3897 mlxsw_sp_nexthop_group_remove(mlxsw_sp
, nh_grp
);
3898 for (i
--; i
>= 0; i
--) {
3899 nh
= &nh_grp
->nexthops
[i
];
3900 mlxsw_sp_nexthop6_fini(mlxsw_sp
, nh
);
3902 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh_grp
);
3903 WARN_ON(nh_grp
->adj_index_valid
);
3907 static int mlxsw_sp_nexthop6_group_get(struct mlxsw_sp
*mlxsw_sp
,
3908 struct mlxsw_sp_fib6_entry
*fib6_entry
)
3910 struct mlxsw_sp_nexthop_group
*nh_grp
;
3912 nh_grp
= mlxsw_sp_nexthop6_group_lookup(mlxsw_sp
, fib6_entry
);
3914 nh_grp
= mlxsw_sp_nexthop6_group_create(mlxsw_sp
, fib6_entry
);
3916 return PTR_ERR(nh_grp
);
3919 list_add_tail(&fib6_entry
->common
.nexthop_group_node
,
3921 fib6_entry
->common
.nh_group
= nh_grp
;
3926 static void mlxsw_sp_nexthop6_group_put(struct mlxsw_sp
*mlxsw_sp
,
3927 struct mlxsw_sp_fib_entry
*fib_entry
)
3929 struct mlxsw_sp_nexthop_group
*nh_grp
= fib_entry
->nh_group
;
3931 list_del(&fib_entry
->nexthop_group_node
);
3932 if (!list_empty(&nh_grp
->fib_list
))
3934 mlxsw_sp_nexthop6_group_destroy(mlxsw_sp
, nh_grp
);
3938 mlxsw_sp_nexthop6_group_update(struct mlxsw_sp
*mlxsw_sp
,
3939 struct mlxsw_sp_fib6_entry
*fib6_entry
)
3941 struct mlxsw_sp_nexthop_group
*old_nh_grp
= fib6_entry
->common
.nh_group
;
3944 fib6_entry
->common
.nh_group
= NULL
;
3945 list_del(&fib6_entry
->common
.nexthop_group_node
);
3947 err
= mlxsw_sp_nexthop6_group_get(mlxsw_sp
, fib6_entry
);
3949 goto err_nexthop6_group_get
;
3951 /* In case this entry is offloaded, then the adjacency index
3952 * currently associated with it in the device's table is that
3953 * of the old group. Start using the new one instead.
3955 err
= mlxsw_sp_fib_node_entry_add(mlxsw_sp
, &fib6_entry
->common
);
3957 goto err_fib_node_entry_add
;
3959 if (list_empty(&old_nh_grp
->fib_list
))
3960 mlxsw_sp_nexthop6_group_destroy(mlxsw_sp
, old_nh_grp
);
3964 err_fib_node_entry_add
:
3965 mlxsw_sp_nexthop6_group_put(mlxsw_sp
, &fib6_entry
->common
);
3966 err_nexthop6_group_get
:
3967 list_add_tail(&fib6_entry
->common
.nexthop_group_node
,
3968 &old_nh_grp
->fib_list
);
3969 fib6_entry
->common
.nh_group
= old_nh_grp
;
3974 mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp
*mlxsw_sp
,
3975 struct mlxsw_sp_fib6_entry
*fib6_entry
,
3976 struct rt6_info
*rt
)
3978 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
3981 mlxsw_sp_rt6
= mlxsw_sp_rt6_create(rt
);
3982 if (IS_ERR(mlxsw_sp_rt6
))
3983 return PTR_ERR(mlxsw_sp_rt6
);
3985 list_add_tail(&mlxsw_sp_rt6
->list
, &fib6_entry
->rt6_list
);
3988 err
= mlxsw_sp_nexthop6_group_update(mlxsw_sp
, fib6_entry
);
3990 goto err_nexthop6_group_update
;
3994 err_nexthop6_group_update
:
3996 list_del(&mlxsw_sp_rt6
->list
);
3997 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6
);
4002 mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp
*mlxsw_sp
,
4003 struct mlxsw_sp_fib6_entry
*fib6_entry
,
4004 struct rt6_info
*rt
)
4006 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
4008 mlxsw_sp_rt6
= mlxsw_sp_fib6_entry_rt_find(fib6_entry
, rt
);
4009 if (WARN_ON(!mlxsw_sp_rt6
))
4013 list_del(&mlxsw_sp_rt6
->list
);
4014 mlxsw_sp_nexthop6_group_update(mlxsw_sp
, fib6_entry
);
4015 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6
);
4018 static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp
*mlxsw_sp
,
4019 struct mlxsw_sp_fib_entry
*fib_entry
,
4020 const struct rt6_info
*rt
)
4022 /* Packets hitting RTF_REJECT routes need to be discarded by the
4023 * stack. We can rely on their destination device not having a
4024 * RIF (it's the loopback device) and can thus use action type
4025 * local, which will cause them to be trapped with a lower
4026 * priority than packets that need to be locally received.
4028 if (rt
->rt6i_flags
& (RTF_LOCAL
| RTF_ANYCAST
))
4029 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_TRAP
;
4030 else if (rt
->rt6i_flags
& RTF_REJECT
)
4031 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
;
4032 else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp
, rt
))
4033 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_REMOTE
;
4035 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
;
4039 mlxsw_sp_fib6_entry_rt_destroy_all(struct mlxsw_sp_fib6_entry
*fib6_entry
)
4041 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
, *tmp
;
4043 list_for_each_entry_safe(mlxsw_sp_rt6
, tmp
, &fib6_entry
->rt6_list
,
4046 list_del(&mlxsw_sp_rt6
->list
);
4047 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6
);
4051 static struct mlxsw_sp_fib6_entry
*
4052 mlxsw_sp_fib6_entry_create(struct mlxsw_sp
*mlxsw_sp
,
4053 struct mlxsw_sp_fib_node
*fib_node
,
4054 struct rt6_info
*rt
)
4056 struct mlxsw_sp_fib6_entry
*fib6_entry
;
4057 struct mlxsw_sp_fib_entry
*fib_entry
;
4058 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
4061 fib6_entry
= kzalloc(sizeof(*fib6_entry
), GFP_KERNEL
);
4063 return ERR_PTR(-ENOMEM
);
4064 fib_entry
= &fib6_entry
->common
;
4066 mlxsw_sp_rt6
= mlxsw_sp_rt6_create(rt
);
4067 if (IS_ERR(mlxsw_sp_rt6
)) {
4068 err
= PTR_ERR(mlxsw_sp_rt6
);
4069 goto err_rt6_create
;
4072 mlxsw_sp_fib6_entry_type_set(mlxsw_sp
, fib_entry
, mlxsw_sp_rt6
->rt
);
4074 INIT_LIST_HEAD(&fib6_entry
->rt6_list
);
4075 list_add_tail(&mlxsw_sp_rt6
->list
, &fib6_entry
->rt6_list
);
4076 fib6_entry
->nrt6
= 1;
4077 err
= mlxsw_sp_nexthop6_group_get(mlxsw_sp
, fib6_entry
);
4079 goto err_nexthop6_group_get
;
4081 fib_entry
->fib_node
= fib_node
;
4085 err_nexthop6_group_get
:
4086 list_del(&mlxsw_sp_rt6
->list
);
4087 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6
);
4090 return ERR_PTR(err
);
4093 static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp
*mlxsw_sp
,
4094 struct mlxsw_sp_fib6_entry
*fib6_entry
)
4096 mlxsw_sp_nexthop6_group_put(mlxsw_sp
, &fib6_entry
->common
);
4097 mlxsw_sp_fib6_entry_rt_destroy_all(fib6_entry
);
4098 WARN_ON(fib6_entry
->nrt6
);
4102 static struct mlxsw_sp_fib6_entry
*
4103 mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node
*fib_node
,
4104 const struct rt6_info
*nrt
, bool replace
)
4106 struct mlxsw_sp_fib6_entry
*fib6_entry
, *fallback
= NULL
;
4108 list_for_each_entry(fib6_entry
, &fib_node
->entry_list
, common
.list
) {
4109 struct rt6_info
*rt
= mlxsw_sp_fib6_entry_rt(fib6_entry
);
4111 if (rt
->rt6i_table
->tb6_id
> nrt
->rt6i_table
->tb6_id
)
4113 if (rt
->rt6i_table
->tb6_id
!= nrt
->rt6i_table
->tb6_id
)
4115 if (replace
&& rt
->rt6i_metric
== nrt
->rt6i_metric
) {
4116 if (mlxsw_sp_fib6_rt_can_mp(rt
) ==
4117 mlxsw_sp_fib6_rt_can_mp(nrt
))
4119 if (mlxsw_sp_fib6_rt_can_mp(nrt
))
4120 fallback
= fallback
?: fib6_entry
;
4122 if (rt
->rt6i_metric
> nrt
->rt6i_metric
)
4123 return fallback
?: fib6_entry
;
4130 mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry
*new6_entry
,
4133 struct mlxsw_sp_fib_node
*fib_node
= new6_entry
->common
.fib_node
;
4134 struct rt6_info
*nrt
= mlxsw_sp_fib6_entry_rt(new6_entry
);
4135 struct mlxsw_sp_fib6_entry
*fib6_entry
;
4137 fib6_entry
= mlxsw_sp_fib6_node_entry_find(fib_node
, nrt
, replace
);
4139 if (replace
&& WARN_ON(!fib6_entry
))
4143 list_add_tail(&new6_entry
->common
.list
,
4144 &fib6_entry
->common
.list
);
4146 struct mlxsw_sp_fib6_entry
*last
;
4148 list_for_each_entry(last
, &fib_node
->entry_list
, common
.list
) {
4149 struct rt6_info
*rt
= mlxsw_sp_fib6_entry_rt(last
);
4151 if (nrt
->rt6i_table
->tb6_id
> rt
->rt6i_table
->tb6_id
)
4157 list_add(&new6_entry
->common
.list
,
4158 &fib6_entry
->common
.list
);
4160 list_add(&new6_entry
->common
.list
,
4161 &fib_node
->entry_list
);
4168 mlxsw_sp_fib6_node_list_remove(struct mlxsw_sp_fib6_entry
*fib6_entry
)
4170 list_del(&fib6_entry
->common
.list
);
4173 static int mlxsw_sp_fib6_node_entry_link(struct mlxsw_sp
*mlxsw_sp
,
4174 struct mlxsw_sp_fib6_entry
*fib6_entry
,
4179 err
= mlxsw_sp_fib6_node_list_insert(fib6_entry
, replace
);
4183 err
= mlxsw_sp_fib_node_entry_add(mlxsw_sp
, &fib6_entry
->common
);
4185 goto err_fib_node_entry_add
;
4189 err_fib_node_entry_add
:
4190 mlxsw_sp_fib6_node_list_remove(fib6_entry
);
4195 mlxsw_sp_fib6_node_entry_unlink(struct mlxsw_sp
*mlxsw_sp
,
4196 struct mlxsw_sp_fib6_entry
*fib6_entry
)
4198 mlxsw_sp_fib_node_entry_del(mlxsw_sp
, &fib6_entry
->common
);
4199 mlxsw_sp_fib6_node_list_remove(fib6_entry
);
4202 static struct mlxsw_sp_fib6_entry
*
4203 mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp
*mlxsw_sp
,
4204 const struct rt6_info
*rt
)
4206 struct mlxsw_sp_fib6_entry
*fib6_entry
;
4207 struct mlxsw_sp_fib_node
*fib_node
;
4208 struct mlxsw_sp_fib
*fib
;
4209 struct mlxsw_sp_vr
*vr
;
4211 vr
= mlxsw_sp_vr_find(mlxsw_sp
, rt
->rt6i_table
->tb6_id
);
4214 fib
= mlxsw_sp_vr_fib(vr
, MLXSW_SP_L3_PROTO_IPV6
);
4216 fib_node
= mlxsw_sp_fib_node_lookup(fib
, &rt
->rt6i_dst
.addr
,
4217 sizeof(rt
->rt6i_dst
.addr
),
4222 list_for_each_entry(fib6_entry
, &fib_node
->entry_list
, common
.list
) {
4223 struct rt6_info
*iter_rt
= mlxsw_sp_fib6_entry_rt(fib6_entry
);
4225 if (rt
->rt6i_table
->tb6_id
== iter_rt
->rt6i_table
->tb6_id
&&
4226 rt
->rt6i_metric
== iter_rt
->rt6i_metric
&&
4227 mlxsw_sp_fib6_entry_rt_find(fib6_entry
, rt
))
4234 static void mlxsw_sp_fib6_entry_replace(struct mlxsw_sp
*mlxsw_sp
,
4235 struct mlxsw_sp_fib6_entry
*fib6_entry
,
4238 struct mlxsw_sp_fib_node
*fib_node
= fib6_entry
->common
.fib_node
;
4239 struct mlxsw_sp_fib6_entry
*replaced
;
4244 replaced
= list_next_entry(fib6_entry
, common
.list
);
4246 mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp
, replaced
);
4247 mlxsw_sp_fib6_entry_destroy(mlxsw_sp
, replaced
);
4248 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
4251 static int mlxsw_sp_router_fib6_add(struct mlxsw_sp
*mlxsw_sp
,
4252 struct rt6_info
*rt
, bool replace
)
4254 struct mlxsw_sp_fib6_entry
*fib6_entry
;
4255 struct mlxsw_sp_fib_node
*fib_node
;
4258 if (mlxsw_sp
->router
->aborted
)
4261 if (rt
->rt6i_src
.plen
)
4264 if (mlxsw_sp_fib6_rt_should_ignore(rt
))
4267 fib_node
= mlxsw_sp_fib_node_get(mlxsw_sp
, rt
->rt6i_table
->tb6_id
,
4269 sizeof(rt
->rt6i_dst
.addr
),
4271 MLXSW_SP_L3_PROTO_IPV6
);
4272 if (IS_ERR(fib_node
))
4273 return PTR_ERR(fib_node
);
4275 /* Before creating a new entry, try to append route to an existing
4278 fib6_entry
= mlxsw_sp_fib6_node_mp_entry_find(fib_node
, rt
, replace
);
4280 err
= mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp
, fib6_entry
, rt
);
4282 goto err_fib6_entry_nexthop_add
;
4286 fib6_entry
= mlxsw_sp_fib6_entry_create(mlxsw_sp
, fib_node
, rt
);
4287 if (IS_ERR(fib6_entry
)) {
4288 err
= PTR_ERR(fib6_entry
);
4289 goto err_fib6_entry_create
;
4292 err
= mlxsw_sp_fib6_node_entry_link(mlxsw_sp
, fib6_entry
, replace
);
4294 goto err_fib6_node_entry_link
;
4296 mlxsw_sp_fib6_entry_replace(mlxsw_sp
, fib6_entry
, replace
);
4300 err_fib6_node_entry_link
:
4301 mlxsw_sp_fib6_entry_destroy(mlxsw_sp
, fib6_entry
);
4302 err_fib6_entry_create
:
4303 err_fib6_entry_nexthop_add
:
4304 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
4308 static void mlxsw_sp_router_fib6_del(struct mlxsw_sp
*mlxsw_sp
,
4309 struct rt6_info
*rt
)
4311 struct mlxsw_sp_fib6_entry
*fib6_entry
;
4312 struct mlxsw_sp_fib_node
*fib_node
;
4314 if (mlxsw_sp
->router
->aborted
)
4317 if (mlxsw_sp_fib6_rt_should_ignore(rt
))
4320 fib6_entry
= mlxsw_sp_fib6_entry_lookup(mlxsw_sp
, rt
);
4321 if (WARN_ON(!fib6_entry
))
4324 /* If route is part of a multipath entry, but not the last one
4325 * removed, then only reduce its nexthop group.
4327 if (!list_is_singular(&fib6_entry
->rt6_list
)) {
4328 mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp
, fib6_entry
, rt
);
4332 fib_node
= fib6_entry
->common
.fib_node
;
4334 mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp
, fib6_entry
);
4335 mlxsw_sp_fib6_entry_destroy(mlxsw_sp
, fib6_entry
);
4336 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
4339 static int __mlxsw_sp_router_set_abort_trap(struct mlxsw_sp
*mlxsw_sp
,
4340 enum mlxsw_reg_ralxx_protocol proto
,
4343 char ralta_pl
[MLXSW_REG_RALTA_LEN
];
4344 char ralst_pl
[MLXSW_REG_RALST_LEN
];
4347 mlxsw_reg_ralta_pack(ralta_pl
, true, proto
, tree_id
);
4348 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralta
), ralta_pl
);
4352 mlxsw_reg_ralst_pack(ralst_pl
, 0xff, tree_id
);
4353 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralst
), ralst_pl
);
4357 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
4358 struct mlxsw_sp_vr
*vr
= &mlxsw_sp
->router
->vrs
[i
];
4359 char raltb_pl
[MLXSW_REG_RALTB_LEN
];
4360 char ralue_pl
[MLXSW_REG_RALUE_LEN
];
4362 mlxsw_reg_raltb_pack(raltb_pl
, vr
->id
, proto
, tree_id
);
4363 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(raltb
),
4368 mlxsw_reg_ralue_pack(ralue_pl
, proto
,
4369 MLXSW_REG_RALUE_OP_WRITE_WRITE
, vr
->id
, 0);
4370 mlxsw_reg_ralue_act_ip2me_pack(ralue_pl
);
4371 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralue
),
4380 static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp
*mlxsw_sp
)
4382 enum mlxsw_reg_ralxx_protocol proto
= MLXSW_REG_RALXX_PROTOCOL_IPV4
;
4385 err
= __mlxsw_sp_router_set_abort_trap(mlxsw_sp
, proto
,
4386 MLXSW_SP_LPM_TREE_MIN
);
4390 proto
= MLXSW_REG_RALXX_PROTOCOL_IPV6
;
4391 return __mlxsw_sp_router_set_abort_trap(mlxsw_sp
, proto
,
4392 MLXSW_SP_LPM_TREE_MIN
+ 1);
4395 static void mlxsw_sp_fib4_node_flush(struct mlxsw_sp
*mlxsw_sp
,
4396 struct mlxsw_sp_fib_node
*fib_node
)
4398 struct mlxsw_sp_fib4_entry
*fib4_entry
, *tmp
;
4400 list_for_each_entry_safe(fib4_entry
, tmp
, &fib_node
->entry_list
,
4402 bool do_break
= &tmp
->common
.list
== &fib_node
->entry_list
;
4404 mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp
, fib4_entry
);
4405 mlxsw_sp_fib4_entry_destroy(mlxsw_sp
, fib4_entry
);
4406 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
4407 /* Break when entry list is empty and node was freed.
4408 * Otherwise, we'll access freed memory in the next
4416 static void mlxsw_sp_fib6_node_flush(struct mlxsw_sp
*mlxsw_sp
,
4417 struct mlxsw_sp_fib_node
*fib_node
)
4419 struct mlxsw_sp_fib6_entry
*fib6_entry
, *tmp
;
4421 list_for_each_entry_safe(fib6_entry
, tmp
, &fib_node
->entry_list
,
4423 bool do_break
= &tmp
->common
.list
== &fib_node
->entry_list
;
4425 mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp
, fib6_entry
);
4426 mlxsw_sp_fib6_entry_destroy(mlxsw_sp
, fib6_entry
);
4427 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
4433 static void mlxsw_sp_fib_node_flush(struct mlxsw_sp
*mlxsw_sp
,
4434 struct mlxsw_sp_fib_node
*fib_node
)
4436 switch (fib_node
->fib
->proto
) {
4437 case MLXSW_SP_L3_PROTO_IPV4
:
4438 mlxsw_sp_fib4_node_flush(mlxsw_sp
, fib_node
);
4440 case MLXSW_SP_L3_PROTO_IPV6
:
4441 mlxsw_sp_fib6_node_flush(mlxsw_sp
, fib_node
);
4446 static void mlxsw_sp_vr_fib_flush(struct mlxsw_sp
*mlxsw_sp
,
4447 struct mlxsw_sp_vr
*vr
,
4448 enum mlxsw_sp_l3proto proto
)
4450 struct mlxsw_sp_fib
*fib
= mlxsw_sp_vr_fib(vr
, proto
);
4451 struct mlxsw_sp_fib_node
*fib_node
, *tmp
;
4453 list_for_each_entry_safe(fib_node
, tmp
, &fib
->node_list
, list
) {
4454 bool do_break
= &tmp
->list
== &fib
->node_list
;
4456 mlxsw_sp_fib_node_flush(mlxsw_sp
, fib_node
);
4462 static void mlxsw_sp_router_fib_flush(struct mlxsw_sp
*mlxsw_sp
)
4466 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
4467 struct mlxsw_sp_vr
*vr
= &mlxsw_sp
->router
->vrs
[i
];
4469 if (!mlxsw_sp_vr_is_used(vr
))
4471 mlxsw_sp_vr_fib_flush(mlxsw_sp
, vr
, MLXSW_SP_L3_PROTO_IPV4
);
4473 /* If virtual router was only used for IPv4, then it's no
4476 if (!mlxsw_sp_vr_is_used(vr
))
4478 mlxsw_sp_vr_fib_flush(mlxsw_sp
, vr
, MLXSW_SP_L3_PROTO_IPV6
);
4482 static void mlxsw_sp_router_fib_abort(struct mlxsw_sp
*mlxsw_sp
)
4486 if (mlxsw_sp
->router
->aborted
)
4488 dev_warn(mlxsw_sp
->bus_info
->dev
, "FIB abort triggered. Note that FIB entries are no longer being offloaded to this device.\n");
4489 mlxsw_sp_router_fib_flush(mlxsw_sp
);
4490 mlxsw_sp
->router
->aborted
= true;
4491 err
= mlxsw_sp_router_set_abort_trap(mlxsw_sp
);
4493 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to set abort trap.\n");
4496 struct mlxsw_sp_fib_event_work
{
4497 struct work_struct work
;
4499 struct fib6_entry_notifier_info fen6_info
;
4500 struct fib_entry_notifier_info fen_info
;
4501 struct fib_rule_notifier_info fr_info
;
4502 struct fib_nh_notifier_info fnh_info
;
4504 struct mlxsw_sp
*mlxsw_sp
;
4505 unsigned long event
;
4508 static void mlxsw_sp_router_fib4_event_work(struct work_struct
*work
)
4510 struct mlxsw_sp_fib_event_work
*fib_work
=
4511 container_of(work
, struct mlxsw_sp_fib_event_work
, work
);
4512 struct mlxsw_sp
*mlxsw_sp
= fib_work
->mlxsw_sp
;
4513 struct fib_rule
*rule
;
4514 bool replace
, append
;
4517 /* Protect internal structures from changes */
4519 switch (fib_work
->event
) {
4520 case FIB_EVENT_ENTRY_REPLACE
: /* fall through */
4521 case FIB_EVENT_ENTRY_APPEND
: /* fall through */
4522 case FIB_EVENT_ENTRY_ADD
:
4523 replace
= fib_work
->event
== FIB_EVENT_ENTRY_REPLACE
;
4524 append
= fib_work
->event
== FIB_EVENT_ENTRY_APPEND
;
4525 err
= mlxsw_sp_router_fib4_add(mlxsw_sp
, &fib_work
->fen_info
,
4528 mlxsw_sp_router_fib_abort(mlxsw_sp
);
4529 fib_info_put(fib_work
->fen_info
.fi
);
4531 case FIB_EVENT_ENTRY_DEL
:
4532 mlxsw_sp_router_fib4_del(mlxsw_sp
, &fib_work
->fen_info
);
4533 fib_info_put(fib_work
->fen_info
.fi
);
4535 case FIB_EVENT_RULE_ADD
: /* fall through */
4536 case FIB_EVENT_RULE_DEL
:
4537 rule
= fib_work
->fr_info
.rule
;
4538 if (!fib4_rule_default(rule
) && !rule
->l3mdev
)
4539 mlxsw_sp_router_fib_abort(mlxsw_sp
);
4542 case FIB_EVENT_NH_ADD
: /* fall through */
4543 case FIB_EVENT_NH_DEL
:
4544 mlxsw_sp_nexthop4_event(mlxsw_sp
, fib_work
->event
,
4545 fib_work
->fnh_info
.fib_nh
);
4546 fib_info_put(fib_work
->fnh_info
.fib_nh
->nh_parent
);
4553 static void mlxsw_sp_router_fib6_event_work(struct work_struct
*work
)
4555 struct mlxsw_sp_fib_event_work
*fib_work
=
4556 container_of(work
, struct mlxsw_sp_fib_event_work
, work
);
4557 struct mlxsw_sp
*mlxsw_sp
= fib_work
->mlxsw_sp
;
4558 struct fib_rule
*rule
;
4563 switch (fib_work
->event
) {
4564 case FIB_EVENT_ENTRY_REPLACE
: /* fall through */
4565 case FIB_EVENT_ENTRY_ADD
:
4566 replace
= fib_work
->event
== FIB_EVENT_ENTRY_REPLACE
;
4567 err
= mlxsw_sp_router_fib6_add(mlxsw_sp
,
4568 fib_work
->fen6_info
.rt
, replace
);
4570 mlxsw_sp_router_fib_abort(mlxsw_sp
);
4571 mlxsw_sp_rt6_release(fib_work
->fen6_info
.rt
);
4573 case FIB_EVENT_ENTRY_DEL
:
4574 mlxsw_sp_router_fib6_del(mlxsw_sp
, fib_work
->fen6_info
.rt
);
4575 mlxsw_sp_rt6_release(fib_work
->fen6_info
.rt
);
4577 case FIB_EVENT_RULE_ADD
: /* fall through */
4578 case FIB_EVENT_RULE_DEL
:
4579 rule
= fib_work
->fr_info
.rule
;
4580 if (!fib6_rule_default(rule
) && !rule
->l3mdev
)
4581 mlxsw_sp_router_fib_abort(mlxsw_sp
);
4589 static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work
*fib_work
,
4590 struct fib_notifier_info
*info
)
4592 switch (fib_work
->event
) {
4593 case FIB_EVENT_ENTRY_REPLACE
: /* fall through */
4594 case FIB_EVENT_ENTRY_APPEND
: /* fall through */
4595 case FIB_EVENT_ENTRY_ADD
: /* fall through */
4596 case FIB_EVENT_ENTRY_DEL
:
4597 memcpy(&fib_work
->fen_info
, info
, sizeof(fib_work
->fen_info
));
4598 /* Take referece on fib_info to prevent it from being
4599 * freed while work is queued. Release it afterwards.
4601 fib_info_hold(fib_work
->fen_info
.fi
);
4603 case FIB_EVENT_RULE_ADD
: /* fall through */
4604 case FIB_EVENT_RULE_DEL
:
4605 memcpy(&fib_work
->fr_info
, info
, sizeof(fib_work
->fr_info
));
4606 fib_rule_get(fib_work
->fr_info
.rule
);
4608 case FIB_EVENT_NH_ADD
: /* fall through */
4609 case FIB_EVENT_NH_DEL
:
4610 memcpy(&fib_work
->fnh_info
, info
, sizeof(fib_work
->fnh_info
));
4611 fib_info_hold(fib_work
->fnh_info
.fib_nh
->nh_parent
);
4616 static void mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work
*fib_work
,
4617 struct fib_notifier_info
*info
)
4619 switch (fib_work
->event
) {
4620 case FIB_EVENT_ENTRY_REPLACE
: /* fall through */
4621 case FIB_EVENT_ENTRY_ADD
: /* fall through */
4622 case FIB_EVENT_ENTRY_DEL
:
4623 memcpy(&fib_work
->fen6_info
, info
, sizeof(fib_work
->fen6_info
));
4624 rt6_hold(fib_work
->fen6_info
.rt
);
4626 case FIB_EVENT_RULE_ADD
: /* fall through */
4627 case FIB_EVENT_RULE_DEL
:
4628 memcpy(&fib_work
->fr_info
, info
, sizeof(fib_work
->fr_info
));
4629 fib_rule_get(fib_work
->fr_info
.rule
);
4634 /* Called with rcu_read_lock() */
4635 static int mlxsw_sp_router_fib_event(struct notifier_block
*nb
,
4636 unsigned long event
, void *ptr
)
4638 struct mlxsw_sp_fib_event_work
*fib_work
;
4639 struct fib_notifier_info
*info
= ptr
;
4640 struct mlxsw_sp_router
*router
;
4642 if (!net_eq(info
->net
, &init_net
))
4645 fib_work
= kzalloc(sizeof(*fib_work
), GFP_ATOMIC
);
4646 if (WARN_ON(!fib_work
))
4649 router
= container_of(nb
, struct mlxsw_sp_router
, fib_nb
);
4650 fib_work
->mlxsw_sp
= router
->mlxsw_sp
;
4651 fib_work
->event
= event
;
4653 switch (info
->family
) {
4655 INIT_WORK(&fib_work
->work
, mlxsw_sp_router_fib4_event_work
);
4656 mlxsw_sp_router_fib4_event(fib_work
, info
);
4659 INIT_WORK(&fib_work
->work
, mlxsw_sp_router_fib6_event_work
);
4660 mlxsw_sp_router_fib6_event(fib_work
, info
);
4664 mlxsw_core_schedule_work(&fib_work
->work
);
4669 static struct mlxsw_sp_rif
*
4670 mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp
*mlxsw_sp
,
4671 const struct net_device
*dev
)
4675 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
); i
++)
4676 if (mlxsw_sp
->router
->rifs
[i
] &&
4677 mlxsw_sp
->router
->rifs
[i
]->dev
== dev
)
4678 return mlxsw_sp
->router
->rifs
[i
];
4683 static int mlxsw_sp_router_rif_disable(struct mlxsw_sp
*mlxsw_sp
, u16 rif
)
4685 char ritr_pl
[MLXSW_REG_RITR_LEN
];
4688 mlxsw_reg_ritr_rif_pack(ritr_pl
, rif
);
4689 err
= mlxsw_reg_query(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
4690 if (WARN_ON_ONCE(err
))
4693 mlxsw_reg_ritr_enable_set(ritr_pl
, false);
4694 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
4697 static void mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp
*mlxsw_sp
,
4698 struct mlxsw_sp_rif
*rif
)
4700 mlxsw_sp_router_rif_disable(mlxsw_sp
, rif
->rif_index
);
4701 mlxsw_sp_nexthop_rif_gone_sync(mlxsw_sp
, rif
);
4702 mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp
, rif
);
4706 mlxsw_sp_rif_should_config(struct mlxsw_sp_rif
*rif
, struct net_device
*dev
,
4707 unsigned long event
)
4709 struct inet6_dev
*inet6_dev
;
4710 bool addr_list_empty
= true;
4711 struct in_device
*idev
;
4717 idev
= __in_dev_get_rtnl(dev
);
4718 if (idev
&& idev
->ifa_list
)
4719 addr_list_empty
= false;
4721 inet6_dev
= __in6_dev_get(dev
);
4722 if (addr_list_empty
&& inet6_dev
&&
4723 !list_empty(&inet6_dev
->addr_list
))
4724 addr_list_empty
= false;
4726 if (rif
&& addr_list_empty
&&
4727 !netif_is_l3_slave(rif
->dev
))
4729 /* It is possible we already removed the RIF ourselves
4730 * if it was assigned to a netdev that is now a bridge
4739 static enum mlxsw_sp_rif_type
4740 mlxsw_sp_dev_rif_type(const struct mlxsw_sp
*mlxsw_sp
,
4741 const struct net_device
*dev
)
4743 enum mlxsw_sp_fid_type type
;
4745 if (mlxsw_sp_netdev_ipip_type(mlxsw_sp
, dev
, NULL
))
4746 return MLXSW_SP_RIF_TYPE_IPIP_LB
;
4748 /* Otherwise RIF type is derived from the type of the underlying FID. */
4749 if (is_vlan_dev(dev
) && netif_is_bridge_master(vlan_dev_real_dev(dev
)))
4750 type
= MLXSW_SP_FID_TYPE_8021Q
;
4751 else if (netif_is_bridge_master(dev
) && br_vlan_enabled(dev
))
4752 type
= MLXSW_SP_FID_TYPE_8021Q
;
4753 else if (netif_is_bridge_master(dev
))
4754 type
= MLXSW_SP_FID_TYPE_8021D
;
4756 type
= MLXSW_SP_FID_TYPE_RFID
;
4758 return mlxsw_sp_fid_type_rif_type(mlxsw_sp
, type
);
4761 static int mlxsw_sp_rif_index_alloc(struct mlxsw_sp
*mlxsw_sp
, u16
*p_rif_index
)
4765 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
); i
++) {
4766 if (!mlxsw_sp
->router
->rifs
[i
]) {
4775 static struct mlxsw_sp_rif
*mlxsw_sp_rif_alloc(size_t rif_size
, u16 rif_index
,
4777 struct net_device
*l3_dev
)
4779 struct mlxsw_sp_rif
*rif
;
4781 rif
= kzalloc(rif_size
, GFP_KERNEL
);
4785 INIT_LIST_HEAD(&rif
->nexthop_list
);
4786 INIT_LIST_HEAD(&rif
->neigh_list
);
4787 ether_addr_copy(rif
->addr
, l3_dev
->dev_addr
);
4788 rif
->mtu
= l3_dev
->mtu
;
4791 rif
->rif_index
= rif_index
;
4796 struct mlxsw_sp_rif
*mlxsw_sp_rif_by_index(const struct mlxsw_sp
*mlxsw_sp
,
4799 return mlxsw_sp
->router
->rifs
[rif_index
];
4802 u16
mlxsw_sp_rif_index(const struct mlxsw_sp_rif
*rif
)
4804 return rif
->rif_index
;
4807 int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif
*rif
)
4809 return rif
->dev
->ifindex
;
4812 static struct mlxsw_sp_rif
*
4813 mlxsw_sp_rif_create(struct mlxsw_sp
*mlxsw_sp
,
4814 const struct mlxsw_sp_rif_params
*params
)
4816 u32 tb_id
= l3mdev_fib_table(params
->dev
);
4817 const struct mlxsw_sp_rif_ops
*ops
;
4818 struct mlxsw_sp_fid
*fid
= NULL
;
4819 enum mlxsw_sp_rif_type type
;
4820 struct mlxsw_sp_rif
*rif
;
4821 struct mlxsw_sp_vr
*vr
;
4825 type
= mlxsw_sp_dev_rif_type(mlxsw_sp
, params
->dev
);
4826 ops
= mlxsw_sp
->router
->rif_ops_arr
[type
];
4828 vr
= mlxsw_sp_vr_get(mlxsw_sp
, tb_id
? : RT_TABLE_MAIN
);
4830 return ERR_CAST(vr
);
4832 err
= mlxsw_sp_rif_index_alloc(mlxsw_sp
, &rif_index
);
4834 goto err_rif_index_alloc
;
4836 rif
= mlxsw_sp_rif_alloc(ops
->rif_size
, rif_index
, vr
->id
, params
->dev
);
4841 rif
->mlxsw_sp
= mlxsw_sp
;
4845 fid
= ops
->fid_get(rif
);
4854 ops
->setup(rif
, params
);
4856 err
= ops
->configure(rif
);
4860 mlxsw_sp_rif_counters_alloc(rif
);
4861 mlxsw_sp
->router
->rifs
[rif_index
] = rif
;
4868 mlxsw_sp_fid_put(fid
);
4872 err_rif_index_alloc
:
4873 mlxsw_sp_vr_put(vr
);
4874 return ERR_PTR(err
);
4877 void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif
*rif
)
4879 const struct mlxsw_sp_rif_ops
*ops
= rif
->ops
;
4880 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
4881 struct mlxsw_sp_fid
*fid
= rif
->fid
;
4882 struct mlxsw_sp_vr
*vr
;
4884 mlxsw_sp_router_rif_gone_sync(mlxsw_sp
, rif
);
4885 vr
= &mlxsw_sp
->router
->vrs
[rif
->vr_id
];
4888 mlxsw_sp
->router
->rifs
[rif
->rif_index
] = NULL
;
4889 mlxsw_sp_rif_counters_free(rif
);
4890 ops
->deconfigure(rif
);
4892 /* Loopback RIFs are not associated with a FID. */
4893 mlxsw_sp_fid_put(fid
);
4895 mlxsw_sp_vr_put(vr
);
4899 mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params
*params
,
4900 struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
)
4902 struct mlxsw_sp_port
*mlxsw_sp_port
= mlxsw_sp_port_vlan
->mlxsw_sp_port
;
4904 params
->vid
= mlxsw_sp_port_vlan
->vid
;
4905 params
->lag
= mlxsw_sp_port
->lagged
;
4907 params
->lag_id
= mlxsw_sp_port
->lag_id
;
4909 params
->system_port
= mlxsw_sp_port
->local_port
;
4913 mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
,
4914 struct net_device
*l3_dev
)
4916 struct mlxsw_sp_port
*mlxsw_sp_port
= mlxsw_sp_port_vlan
->mlxsw_sp_port
;
4917 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
4918 u16 vid
= mlxsw_sp_port_vlan
->vid
;
4919 struct mlxsw_sp_rif
*rif
;
4920 struct mlxsw_sp_fid
*fid
;
4923 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, l3_dev
);
4925 struct mlxsw_sp_rif_params params
= {
4929 mlxsw_sp_rif_subport_params_init(¶ms
, mlxsw_sp_port_vlan
);
4930 rif
= mlxsw_sp_rif_create(mlxsw_sp
, ¶ms
);
4932 return PTR_ERR(rif
);
4935 /* FID was already created, just take a reference */
4936 fid
= rif
->ops
->fid_get(rif
);
4937 err
= mlxsw_sp_fid_port_vid_map(fid
, mlxsw_sp_port
, vid
);
4939 goto err_fid_port_vid_map
;
4941 err
= mlxsw_sp_port_vid_learning_set(mlxsw_sp_port
, vid
, false);
4943 goto err_port_vid_learning_set
;
4945 err
= mlxsw_sp_port_vid_stp_set(mlxsw_sp_port
, vid
,
4946 BR_STATE_FORWARDING
);
4948 goto err_port_vid_stp_set
;
4950 mlxsw_sp_port_vlan
->fid
= fid
;
4954 err_port_vid_stp_set
:
4955 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port
, vid
, true);
4956 err_port_vid_learning_set
:
4957 mlxsw_sp_fid_port_vid_unmap(fid
, mlxsw_sp_port
, vid
);
4958 err_fid_port_vid_map
:
4959 mlxsw_sp_fid_put(fid
);
4964 mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
)
4966 struct mlxsw_sp_port
*mlxsw_sp_port
= mlxsw_sp_port_vlan
->mlxsw_sp_port
;
4967 struct mlxsw_sp_fid
*fid
= mlxsw_sp_port_vlan
->fid
;
4968 u16 vid
= mlxsw_sp_port_vlan
->vid
;
4970 if (WARN_ON(mlxsw_sp_fid_type(fid
) != MLXSW_SP_FID_TYPE_RFID
))
4973 mlxsw_sp_port_vlan
->fid
= NULL
;
4974 mlxsw_sp_port_vid_stp_set(mlxsw_sp_port
, vid
, BR_STATE_BLOCKING
);
4975 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port
, vid
, true);
4976 mlxsw_sp_fid_port_vid_unmap(fid
, mlxsw_sp_port
, vid
);
4977 /* If router port holds the last reference on the rFID, then the
4978 * associated Sub-port RIF will be destroyed.
4980 mlxsw_sp_fid_put(fid
);
4983 static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device
*l3_dev
,
4984 struct net_device
*port_dev
,
4985 unsigned long event
, u16 vid
)
4987 struct mlxsw_sp_port
*mlxsw_sp_port
= netdev_priv(port_dev
);
4988 struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
;
4990 mlxsw_sp_port_vlan
= mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port
, vid
);
4991 if (WARN_ON(!mlxsw_sp_port_vlan
))
4996 return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan
,
4999 mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan
);
5006 static int mlxsw_sp_inetaddr_port_event(struct net_device
*port_dev
,
5007 unsigned long event
)
5009 if (netif_is_bridge_port(port_dev
) ||
5010 netif_is_lag_port(port_dev
) ||
5011 netif_is_ovs_port(port_dev
))
5014 return mlxsw_sp_inetaddr_port_vlan_event(port_dev
, port_dev
, event
, 1);
5017 static int __mlxsw_sp_inetaddr_lag_event(struct net_device
*l3_dev
,
5018 struct net_device
*lag_dev
,
5019 unsigned long event
, u16 vid
)
5021 struct net_device
*port_dev
;
5022 struct list_head
*iter
;
5025 netdev_for_each_lower_dev(lag_dev
, port_dev
, iter
) {
5026 if (mlxsw_sp_port_dev_check(port_dev
)) {
5027 err
= mlxsw_sp_inetaddr_port_vlan_event(l3_dev
,
5038 static int mlxsw_sp_inetaddr_lag_event(struct net_device
*lag_dev
,
5039 unsigned long event
)
5041 if (netif_is_bridge_port(lag_dev
))
5044 return __mlxsw_sp_inetaddr_lag_event(lag_dev
, lag_dev
, event
, 1);
5047 static int mlxsw_sp_inetaddr_bridge_event(struct net_device
*l3_dev
,
5048 unsigned long event
)
5050 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_lower_get(l3_dev
);
5051 struct mlxsw_sp_rif_params params
= {
5054 struct mlxsw_sp_rif
*rif
;
5058 rif
= mlxsw_sp_rif_create(mlxsw_sp
, ¶ms
);
5060 return PTR_ERR(rif
);
5063 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, l3_dev
);
5064 mlxsw_sp_rif_destroy(rif
);
5071 static int mlxsw_sp_inetaddr_vlan_event(struct net_device
*vlan_dev
,
5072 unsigned long event
)
5074 struct net_device
*real_dev
= vlan_dev_real_dev(vlan_dev
);
5075 u16 vid
= vlan_dev_vlan_id(vlan_dev
);
5077 if (netif_is_bridge_port(vlan_dev
))
5080 if (mlxsw_sp_port_dev_check(real_dev
))
5081 return mlxsw_sp_inetaddr_port_vlan_event(vlan_dev
, real_dev
,
5083 else if (netif_is_lag_master(real_dev
))
5084 return __mlxsw_sp_inetaddr_lag_event(vlan_dev
, real_dev
, event
,
5086 else if (netif_is_bridge_master(real_dev
) && br_vlan_enabled(real_dev
))
5087 return mlxsw_sp_inetaddr_bridge_event(vlan_dev
, event
);
5092 static int __mlxsw_sp_inetaddr_event(struct net_device
*dev
,
5093 unsigned long event
)
5095 if (mlxsw_sp_port_dev_check(dev
))
5096 return mlxsw_sp_inetaddr_port_event(dev
, event
);
5097 else if (netif_is_lag_master(dev
))
5098 return mlxsw_sp_inetaddr_lag_event(dev
, event
);
5099 else if (netif_is_bridge_master(dev
))
5100 return mlxsw_sp_inetaddr_bridge_event(dev
, event
);
5101 else if (is_vlan_dev(dev
))
5102 return mlxsw_sp_inetaddr_vlan_event(dev
, event
);
5107 int mlxsw_sp_inetaddr_event(struct notifier_block
*unused
,
5108 unsigned long event
, void *ptr
)
5110 struct in_ifaddr
*ifa
= (struct in_ifaddr
*) ptr
;
5111 struct net_device
*dev
= ifa
->ifa_dev
->dev
;
5112 struct mlxsw_sp
*mlxsw_sp
;
5113 struct mlxsw_sp_rif
*rif
;
5116 mlxsw_sp
= mlxsw_sp_lower_get(dev
);
5120 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, dev
);
5121 if (!mlxsw_sp_rif_should_config(rif
, dev
, event
))
5124 err
= __mlxsw_sp_inetaddr_event(dev
, event
);
5126 return notifier_from_errno(err
);
5129 struct mlxsw_sp_inet6addr_event_work
{
5130 struct work_struct work
;
5131 struct net_device
*dev
;
5132 unsigned long event
;
5135 static void mlxsw_sp_inet6addr_event_work(struct work_struct
*work
)
5137 struct mlxsw_sp_inet6addr_event_work
*inet6addr_work
=
5138 container_of(work
, struct mlxsw_sp_inet6addr_event_work
, work
);
5139 struct net_device
*dev
= inet6addr_work
->dev
;
5140 unsigned long event
= inet6addr_work
->event
;
5141 struct mlxsw_sp
*mlxsw_sp
;
5142 struct mlxsw_sp_rif
*rif
;
5145 mlxsw_sp
= mlxsw_sp_lower_get(dev
);
5149 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, dev
);
5150 if (!mlxsw_sp_rif_should_config(rif
, dev
, event
))
5153 __mlxsw_sp_inetaddr_event(dev
, event
);
5157 kfree(inet6addr_work
);
5160 /* Called with rcu_read_lock() */
5161 int mlxsw_sp_inet6addr_event(struct notifier_block
*unused
,
5162 unsigned long event
, void *ptr
)
5164 struct inet6_ifaddr
*if6
= (struct inet6_ifaddr
*) ptr
;
5165 struct mlxsw_sp_inet6addr_event_work
*inet6addr_work
;
5166 struct net_device
*dev
= if6
->idev
->dev
;
5168 if (!mlxsw_sp_port_dev_lower_find_rcu(dev
))
5171 inet6addr_work
= kzalloc(sizeof(*inet6addr_work
), GFP_ATOMIC
);
5172 if (!inet6addr_work
)
5175 INIT_WORK(&inet6addr_work
->work
, mlxsw_sp_inet6addr_event_work
);
5176 inet6addr_work
->dev
= dev
;
5177 inet6addr_work
->event
= event
;
5179 mlxsw_core_schedule_work(&inet6addr_work
->work
);
5184 static int mlxsw_sp_rif_edit(struct mlxsw_sp
*mlxsw_sp
, u16 rif_index
,
5185 const char *mac
, int mtu
)
5187 char ritr_pl
[MLXSW_REG_RITR_LEN
];
5190 mlxsw_reg_ritr_rif_pack(ritr_pl
, rif_index
);
5191 err
= mlxsw_reg_query(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
5195 mlxsw_reg_ritr_mtu_set(ritr_pl
, mtu
);
5196 mlxsw_reg_ritr_if_mac_memcpy_to(ritr_pl
, mac
);
5197 mlxsw_reg_ritr_op_set(ritr_pl
, MLXSW_REG_RITR_RIF_CREATE
);
5198 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
5201 int mlxsw_sp_netdevice_router_port_event(struct net_device
*dev
)
5203 struct mlxsw_sp
*mlxsw_sp
;
5204 struct mlxsw_sp_rif
*rif
;
5208 mlxsw_sp
= mlxsw_sp_lower_get(dev
);
5212 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, dev
);
5215 fid_index
= mlxsw_sp_fid_index(rif
->fid
);
5217 err
= mlxsw_sp_rif_fdb_op(mlxsw_sp
, rif
->addr
, fid_index
, false);
5221 err
= mlxsw_sp_rif_edit(mlxsw_sp
, rif
->rif_index
, dev
->dev_addr
,
5226 err
= mlxsw_sp_rif_fdb_op(mlxsw_sp
, dev
->dev_addr
, fid_index
, true);
5228 goto err_rif_fdb_op
;
5230 ether_addr_copy(rif
->addr
, dev
->dev_addr
);
5231 rif
->mtu
= dev
->mtu
;
5233 netdev_dbg(dev
, "Updated RIF=%d\n", rif
->rif_index
);
5238 mlxsw_sp_rif_edit(mlxsw_sp
, rif
->rif_index
, rif
->addr
, rif
->mtu
);
5240 mlxsw_sp_rif_fdb_op(mlxsw_sp
, rif
->addr
, fid_index
, true);
5244 static int mlxsw_sp_port_vrf_join(struct mlxsw_sp
*mlxsw_sp
,
5245 struct net_device
*l3_dev
)
5247 struct mlxsw_sp_rif
*rif
;
5249 /* If netdev is already associated with a RIF, then we need to
5250 * destroy it and create a new one with the new virtual router ID.
5252 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, l3_dev
);
5254 __mlxsw_sp_inetaddr_event(l3_dev
, NETDEV_DOWN
);
5256 return __mlxsw_sp_inetaddr_event(l3_dev
, NETDEV_UP
);
5259 static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp
*mlxsw_sp
,
5260 struct net_device
*l3_dev
)
5262 struct mlxsw_sp_rif
*rif
;
5264 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, l3_dev
);
5267 __mlxsw_sp_inetaddr_event(l3_dev
, NETDEV_DOWN
);
5270 int mlxsw_sp_netdevice_vrf_event(struct net_device
*l3_dev
, unsigned long event
,
5271 struct netdev_notifier_changeupper_info
*info
)
5273 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_lower_get(l3_dev
);
5280 case NETDEV_PRECHANGEUPPER
:
5282 case NETDEV_CHANGEUPPER
:
5284 err
= mlxsw_sp_port_vrf_join(mlxsw_sp
, l3_dev
);
5286 mlxsw_sp_port_vrf_leave(mlxsw_sp
, l3_dev
);
5293 static struct mlxsw_sp_rif_subport
*
5294 mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif
*rif
)
5296 return container_of(rif
, struct mlxsw_sp_rif_subport
, common
);
5299 static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif
*rif
,
5300 const struct mlxsw_sp_rif_params
*params
)
5302 struct mlxsw_sp_rif_subport
*rif_subport
;
5304 rif_subport
= mlxsw_sp_rif_subport_rif(rif
);
5305 rif_subport
->vid
= params
->vid
;
5306 rif_subport
->lag
= params
->lag
;
5308 rif_subport
->lag_id
= params
->lag_id
;
5310 rif_subport
->system_port
= params
->system_port
;
5313 static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif
*rif
, bool enable
)
5315 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5316 struct mlxsw_sp_rif_subport
*rif_subport
;
5317 char ritr_pl
[MLXSW_REG_RITR_LEN
];
5319 rif_subport
= mlxsw_sp_rif_subport_rif(rif
);
5320 mlxsw_reg_ritr_pack(ritr_pl
, enable
, MLXSW_REG_RITR_SP_IF
,
5321 rif
->rif_index
, rif
->vr_id
, rif
->dev
->mtu
);
5322 mlxsw_reg_ritr_mac_pack(ritr_pl
, rif
->dev
->dev_addr
);
5323 mlxsw_reg_ritr_sp_if_pack(ritr_pl
, rif_subport
->lag
,
5324 rif_subport
->lag
? rif_subport
->lag_id
:
5325 rif_subport
->system_port
,
5328 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
5331 static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif
*rif
)
5335 err
= mlxsw_sp_rif_subport_op(rif
, true);
5339 err
= mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5340 mlxsw_sp_fid_index(rif
->fid
), true);
5342 goto err_rif_fdb_op
;
5344 mlxsw_sp_fid_rif_set(rif
->fid
, rif
);
5348 mlxsw_sp_rif_subport_op(rif
, false);
5352 static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif
*rif
)
5354 struct mlxsw_sp_fid
*fid
= rif
->fid
;
5356 mlxsw_sp_fid_rif_set(fid
, NULL
);
5357 mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5358 mlxsw_sp_fid_index(fid
), false);
5359 mlxsw_sp_rif_subport_op(rif
, false);
5362 static struct mlxsw_sp_fid
*
5363 mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif
*rif
)
5365 return mlxsw_sp_fid_rfid_get(rif
->mlxsw_sp
, rif
->rif_index
);
5368 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_subport_ops
= {
5369 .type
= MLXSW_SP_RIF_TYPE_SUBPORT
,
5370 .rif_size
= sizeof(struct mlxsw_sp_rif_subport
),
5371 .setup
= mlxsw_sp_rif_subport_setup
,
5372 .configure
= mlxsw_sp_rif_subport_configure
,
5373 .deconfigure
= mlxsw_sp_rif_subport_deconfigure
,
5374 .fid_get
= mlxsw_sp_rif_subport_fid_get
,
5377 static int mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif
*rif
,
5378 enum mlxsw_reg_ritr_if_type type
,
5379 u16 vid_fid
, bool enable
)
5381 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5382 char ritr_pl
[MLXSW_REG_RITR_LEN
];
5384 mlxsw_reg_ritr_pack(ritr_pl
, enable
, type
, rif
->rif_index
, rif
->vr_id
,
5386 mlxsw_reg_ritr_mac_pack(ritr_pl
, rif
->dev
->dev_addr
);
5387 mlxsw_reg_ritr_fid_set(ritr_pl
, type
, vid_fid
);
5389 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
5392 static u8
mlxsw_sp_router_port(const struct mlxsw_sp
*mlxsw_sp
)
5394 return mlxsw_core_max_ports(mlxsw_sp
->core
) + 1;
5397 static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif
*rif
)
5399 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5400 u16 vid
= mlxsw_sp_fid_8021q_vid(rif
->fid
);
5403 err
= mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_VLAN_IF
, vid
, true);
5407 err
= mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5408 mlxsw_sp_router_port(mlxsw_sp
), true);
5410 goto err_fid_mc_flood_set
;
5412 err
= mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5413 mlxsw_sp_router_port(mlxsw_sp
), true);
5415 goto err_fid_bc_flood_set
;
5417 err
= mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5418 mlxsw_sp_fid_index(rif
->fid
), true);
5420 goto err_rif_fdb_op
;
5422 mlxsw_sp_fid_rif_set(rif
->fid
, rif
);
5426 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5427 mlxsw_sp_router_port(mlxsw_sp
), false);
5428 err_fid_bc_flood_set
:
5429 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5430 mlxsw_sp_router_port(mlxsw_sp
), false);
5431 err_fid_mc_flood_set
:
5432 mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_VLAN_IF
, vid
, false);
5436 static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif
*rif
)
5438 u16 vid
= mlxsw_sp_fid_8021q_vid(rif
->fid
);
5439 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5440 struct mlxsw_sp_fid
*fid
= rif
->fid
;
5442 mlxsw_sp_fid_rif_set(fid
, NULL
);
5443 mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5444 mlxsw_sp_fid_index(fid
), false);
5445 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5446 mlxsw_sp_router_port(mlxsw_sp
), false);
5447 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5448 mlxsw_sp_router_port(mlxsw_sp
), false);
5449 mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_VLAN_IF
, vid
, false);
5452 static struct mlxsw_sp_fid
*
5453 mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif
*rif
)
5455 u16 vid
= is_vlan_dev(rif
->dev
) ? vlan_dev_vlan_id(rif
->dev
) : 1;
5457 return mlxsw_sp_fid_8021q_get(rif
->mlxsw_sp
, vid
);
5460 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_ops
= {
5461 .type
= MLXSW_SP_RIF_TYPE_VLAN
,
5462 .rif_size
= sizeof(struct mlxsw_sp_rif
),
5463 .configure
= mlxsw_sp_rif_vlan_configure
,
5464 .deconfigure
= mlxsw_sp_rif_vlan_deconfigure
,
5465 .fid_get
= mlxsw_sp_rif_vlan_fid_get
,
5468 static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif
*rif
)
5470 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5471 u16 fid_index
= mlxsw_sp_fid_index(rif
->fid
);
5474 err
= mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_FID_IF
, fid_index
,
5479 err
= mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5480 mlxsw_sp_router_port(mlxsw_sp
), true);
5482 goto err_fid_mc_flood_set
;
5484 err
= mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5485 mlxsw_sp_router_port(mlxsw_sp
), true);
5487 goto err_fid_bc_flood_set
;
5489 err
= mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5490 mlxsw_sp_fid_index(rif
->fid
), true);
5492 goto err_rif_fdb_op
;
5494 mlxsw_sp_fid_rif_set(rif
->fid
, rif
);
5498 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5499 mlxsw_sp_router_port(mlxsw_sp
), false);
5500 err_fid_bc_flood_set
:
5501 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5502 mlxsw_sp_router_port(mlxsw_sp
), false);
5503 err_fid_mc_flood_set
:
5504 mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_FID_IF
, fid_index
, false);
5508 static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif
*rif
)
5510 u16 fid_index
= mlxsw_sp_fid_index(rif
->fid
);
5511 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5512 struct mlxsw_sp_fid
*fid
= rif
->fid
;
5514 mlxsw_sp_fid_rif_set(fid
, NULL
);
5515 mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5516 mlxsw_sp_fid_index(fid
), false);
5517 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5518 mlxsw_sp_router_port(mlxsw_sp
), false);
5519 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5520 mlxsw_sp_router_port(mlxsw_sp
), false);
5521 mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_FID_IF
, fid_index
, false);
5524 static struct mlxsw_sp_fid
*
5525 mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif
*rif
)
5527 return mlxsw_sp_fid_8021d_get(rif
->mlxsw_sp
, rif
->dev
->ifindex
);
5530 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops
= {
5531 .type
= MLXSW_SP_RIF_TYPE_FID
,
5532 .rif_size
= sizeof(struct mlxsw_sp_rif
),
5533 .configure
= mlxsw_sp_rif_fid_configure
,
5534 .deconfigure
= mlxsw_sp_rif_fid_deconfigure
,
5535 .fid_get
= mlxsw_sp_rif_fid_fid_get
,
5538 static struct mlxsw_sp_rif_ipip_lb
*
5539 mlxsw_sp_rif_ipip_lb_rif(struct mlxsw_sp_rif
*rif
)
5541 return container_of(rif
, struct mlxsw_sp_rif_ipip_lb
, common
);
5545 mlxsw_sp_rif_ipip_lb_setup(struct mlxsw_sp_rif
*rif
,
5546 const struct mlxsw_sp_rif_params
*params
)
5548 struct mlxsw_sp_rif_params_ipip_lb
*params_lb
;
5549 struct mlxsw_sp_rif_ipip_lb
*rif_lb
;
5551 params_lb
= container_of(params
, struct mlxsw_sp_rif_params_ipip_lb
,
5553 rif_lb
= mlxsw_sp_rif_ipip_lb_rif(rif
);
5554 rif_lb
->lb_config
= params_lb
->lb_config
;
5558 mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb
*lb_rif
,
5559 struct mlxsw_sp_vr
*ul_vr
, bool enable
)
5561 struct mlxsw_sp_rif_ipip_lb_config lb_cf
= lb_rif
->lb_config
;
5562 struct mlxsw_sp_rif
*rif
= &lb_rif
->common
;
5563 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5564 char ritr_pl
[MLXSW_REG_RITR_LEN
];
5567 switch (lb_cf
.ul_protocol
) {
5568 case MLXSW_SP_L3_PROTO_IPV4
:
5569 saddr4
= be32_to_cpu(lb_cf
.saddr
.addr4
);
5570 mlxsw_reg_ritr_pack(ritr_pl
, enable
, MLXSW_REG_RITR_LOOPBACK_IF
,
5571 rif
->rif_index
, rif
->vr_id
, rif
->dev
->mtu
);
5572 mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl
, lb_cf
.lb_ipipt
,
5573 MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET
,
5574 ul_vr
->id
, saddr4
, lb_cf
.okey
);
5577 case MLXSW_SP_L3_PROTO_IPV6
:
5578 return -EAFNOSUPPORT
;
5581 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
5585 mlxsw_sp_rif_ipip_lb_configure(struct mlxsw_sp_rif
*rif
)
5587 struct mlxsw_sp_rif_ipip_lb
*lb_rif
= mlxsw_sp_rif_ipip_lb_rif(rif
);
5588 u32 ul_tb_id
= mlxsw_sp_ipip_dev_ul_tb_id(rif
->dev
);
5589 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5590 struct mlxsw_sp_vr
*ul_vr
;
5593 ul_vr
= mlxsw_sp_vr_get(mlxsw_sp
, ul_tb_id
);
5595 return PTR_ERR(ul_vr
);
5597 err
= mlxsw_sp_rif_ipip_lb_op(lb_rif
, ul_vr
, true);
5599 goto err_loopback_op
;
5601 lb_rif
->ul_vr_id
= ul_vr
->id
;
5606 mlxsw_sp_vr_put(ul_vr
);
5610 static void mlxsw_sp_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif
*rif
)
5612 struct mlxsw_sp_rif_ipip_lb
*lb_rif
= mlxsw_sp_rif_ipip_lb_rif(rif
);
5613 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5614 struct mlxsw_sp_vr
*ul_vr
;
5616 ul_vr
= &mlxsw_sp
->router
->vrs
[lb_rif
->ul_vr_id
];
5617 mlxsw_sp_rif_ipip_lb_op(lb_rif
, ul_vr
, false);
5620 mlxsw_sp_vr_put(ul_vr
);
5623 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_ipip_lb_ops
= {
5624 .type
= MLXSW_SP_RIF_TYPE_IPIP_LB
,
5625 .rif_size
= sizeof(struct mlxsw_sp_rif_ipip_lb
),
5626 .setup
= mlxsw_sp_rif_ipip_lb_setup
,
5627 .configure
= mlxsw_sp_rif_ipip_lb_configure
,
5628 .deconfigure
= mlxsw_sp_rif_ipip_lb_deconfigure
,
5631 static const struct mlxsw_sp_rif_ops
*mlxsw_sp_rif_ops_arr
[] = {
5632 [MLXSW_SP_RIF_TYPE_SUBPORT
] = &mlxsw_sp_rif_subport_ops
,
5633 [MLXSW_SP_RIF_TYPE_VLAN
] = &mlxsw_sp_rif_vlan_ops
,
5634 [MLXSW_SP_RIF_TYPE_FID
] = &mlxsw_sp_rif_fid_ops
,
5635 [MLXSW_SP_RIF_TYPE_IPIP_LB
] = &mlxsw_sp_rif_ipip_lb_ops
,
5638 static int mlxsw_sp_rifs_init(struct mlxsw_sp
*mlxsw_sp
)
5640 u64 max_rifs
= MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
);
5642 mlxsw_sp
->router
->rifs
= kcalloc(max_rifs
,
5643 sizeof(struct mlxsw_sp_rif
*),
5645 if (!mlxsw_sp
->router
->rifs
)
5648 mlxsw_sp
->router
->rif_ops_arr
= mlxsw_sp_rif_ops_arr
;
5653 static void mlxsw_sp_rifs_fini(struct mlxsw_sp
*mlxsw_sp
)
5657 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
); i
++)
5658 WARN_ON_ONCE(mlxsw_sp
->router
->rifs
[i
]);
5660 kfree(mlxsw_sp
->router
->rifs
);
5663 static int mlxsw_sp_ipips_init(struct mlxsw_sp
*mlxsw_sp
)
5665 mlxsw_sp
->router
->ipip_ops_arr
= mlxsw_sp_ipip_ops_arr
;
5666 INIT_LIST_HEAD(&mlxsw_sp
->router
->ipip_list
);
5670 static void mlxsw_sp_ipips_fini(struct mlxsw_sp
*mlxsw_sp
)
5672 WARN_ON(!list_empty(&mlxsw_sp
->router
->ipip_list
));
5675 static void mlxsw_sp_router_fib_dump_flush(struct notifier_block
*nb
)
5677 struct mlxsw_sp_router
*router
;
5679 /* Flush pending FIB notifications and then flush the device's
5680 * table before requesting another dump. The FIB notification
5681 * block is unregistered, so no need to take RTNL.
5683 mlxsw_core_flush_owq();
5684 router
= container_of(nb
, struct mlxsw_sp_router
, fib_nb
);
5685 mlxsw_sp_router_fib_flush(router
->mlxsw_sp
);
5688 static int __mlxsw_sp_router_init(struct mlxsw_sp
*mlxsw_sp
)
5690 char rgcr_pl
[MLXSW_REG_RGCR_LEN
];
5694 if (!MLXSW_CORE_RES_VALID(mlxsw_sp
->core
, MAX_RIFS
))
5696 max_rifs
= MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
);
5698 mlxsw_reg_rgcr_pack(rgcr_pl
, true, true);
5699 mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl
, max_rifs
);
5700 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(rgcr
), rgcr_pl
);
5706 static void __mlxsw_sp_router_fini(struct mlxsw_sp
*mlxsw_sp
)
5708 char rgcr_pl
[MLXSW_REG_RGCR_LEN
];
5710 mlxsw_reg_rgcr_pack(rgcr_pl
, false, false);
5711 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(rgcr
), rgcr_pl
);
5714 int mlxsw_sp_router_init(struct mlxsw_sp
*mlxsw_sp
)
5716 struct mlxsw_sp_router
*router
;
5719 router
= kzalloc(sizeof(*mlxsw_sp
->router
), GFP_KERNEL
);
5722 mlxsw_sp
->router
= router
;
5723 router
->mlxsw_sp
= mlxsw_sp
;
5725 INIT_LIST_HEAD(&mlxsw_sp
->router
->nexthop_neighs_list
);
5726 err
= __mlxsw_sp_router_init(mlxsw_sp
);
5728 goto err_router_init
;
5730 err
= mlxsw_sp_rifs_init(mlxsw_sp
);
5734 err
= mlxsw_sp_ipips_init(mlxsw_sp
);
5736 goto err_ipips_init
;
5738 err
= rhashtable_init(&mlxsw_sp
->router
->nexthop_ht
,
5739 &mlxsw_sp_nexthop_ht_params
);
5741 goto err_nexthop_ht_init
;
5743 err
= rhashtable_init(&mlxsw_sp
->router
->nexthop_group_ht
,
5744 &mlxsw_sp_nexthop_group_ht_params
);
5746 goto err_nexthop_group_ht_init
;
5748 err
= mlxsw_sp_lpm_init(mlxsw_sp
);
5752 err
= mlxsw_sp_vrs_init(mlxsw_sp
);
5756 err
= mlxsw_sp_neigh_init(mlxsw_sp
);
5758 goto err_neigh_init
;
5760 mlxsw_sp
->router
->fib_nb
.notifier_call
= mlxsw_sp_router_fib_event
;
5761 err
= register_fib_notifier(&mlxsw_sp
->router
->fib_nb
,
5762 mlxsw_sp_router_fib_dump_flush
);
5764 goto err_register_fib_notifier
;
5768 err_register_fib_notifier
:
5769 mlxsw_sp_neigh_fini(mlxsw_sp
);
5771 mlxsw_sp_vrs_fini(mlxsw_sp
);
5773 mlxsw_sp_lpm_fini(mlxsw_sp
);
5775 rhashtable_destroy(&mlxsw_sp
->router
->nexthop_group_ht
);
5776 err_nexthop_group_ht_init
:
5777 rhashtable_destroy(&mlxsw_sp
->router
->nexthop_ht
);
5778 err_nexthop_ht_init
:
5779 mlxsw_sp_ipips_fini(mlxsw_sp
);
5781 mlxsw_sp_rifs_fini(mlxsw_sp
);
5783 __mlxsw_sp_router_fini(mlxsw_sp
);
5785 kfree(mlxsw_sp
->router
);
5789 void mlxsw_sp_router_fini(struct mlxsw_sp
*mlxsw_sp
)
5791 unregister_fib_notifier(&mlxsw_sp
->router
->fib_nb
);
5792 mlxsw_sp_neigh_fini(mlxsw_sp
);
5793 mlxsw_sp_vrs_fini(mlxsw_sp
);
5794 mlxsw_sp_lpm_fini(mlxsw_sp
);
5795 rhashtable_destroy(&mlxsw_sp
->router
->nexthop_group_ht
);
5796 rhashtable_destroy(&mlxsw_sp
->router
->nexthop_ht
);
5797 mlxsw_sp_ipips_fini(mlxsw_sp
);
5798 mlxsw_sp_rifs_fini(mlxsw_sp
);
5799 __mlxsw_sp_router_fini(mlxsw_sp
);
5800 kfree(mlxsw_sp
->router
);