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
;
93 struct notifier_block fib_nb
;
94 const struct mlxsw_sp_rif_ops
**rif_ops_arr
;
95 const struct mlxsw_sp_ipip_ops
**ipip_ops_arr
;
99 struct list_head nexthop_list
;
100 struct list_head neigh_list
;
101 struct net_device
*dev
;
102 struct mlxsw_sp_fid
*fid
;
103 unsigned char addr
[ETH_ALEN
];
107 const struct mlxsw_sp_rif_ops
*ops
;
108 struct mlxsw_sp
*mlxsw_sp
;
110 unsigned int counter_ingress
;
111 bool counter_ingress_valid
;
112 unsigned int counter_egress
;
113 bool counter_egress_valid
;
116 struct mlxsw_sp_rif_params
{
117 struct net_device
*dev
;
126 struct mlxsw_sp_rif_subport
{
127 struct mlxsw_sp_rif common
;
136 struct mlxsw_sp_rif_ipip_lb
{
137 struct mlxsw_sp_rif common
;
138 struct mlxsw_sp_rif_ipip_lb_config lb_config
;
139 u16 ul_vr_id
; /* Reserved for Spectrum-2. */
142 struct mlxsw_sp_rif_params_ipip_lb
{
143 struct mlxsw_sp_rif_params common
;
144 struct mlxsw_sp_rif_ipip_lb_config lb_config
;
147 struct mlxsw_sp_rif_ops
{
148 enum mlxsw_sp_rif_type type
;
151 void (*setup
)(struct mlxsw_sp_rif
*rif
,
152 const struct mlxsw_sp_rif_params
*params
);
153 int (*configure
)(struct mlxsw_sp_rif
*rif
);
154 void (*deconfigure
)(struct mlxsw_sp_rif
*rif
);
155 struct mlxsw_sp_fid
* (*fid_get
)(struct mlxsw_sp_rif
*rif
);
158 static unsigned int *
159 mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif
*rif
,
160 enum mlxsw_sp_rif_counter_dir dir
)
163 case MLXSW_SP_RIF_COUNTER_EGRESS
:
164 return &rif
->counter_egress
;
165 case MLXSW_SP_RIF_COUNTER_INGRESS
:
166 return &rif
->counter_ingress
;
172 mlxsw_sp_rif_counter_valid_get(struct mlxsw_sp_rif
*rif
,
173 enum mlxsw_sp_rif_counter_dir dir
)
176 case MLXSW_SP_RIF_COUNTER_EGRESS
:
177 return rif
->counter_egress_valid
;
178 case MLXSW_SP_RIF_COUNTER_INGRESS
:
179 return rif
->counter_ingress_valid
;
185 mlxsw_sp_rif_counter_valid_set(struct mlxsw_sp_rif
*rif
,
186 enum mlxsw_sp_rif_counter_dir dir
,
190 case MLXSW_SP_RIF_COUNTER_EGRESS
:
191 rif
->counter_egress_valid
= valid
;
193 case MLXSW_SP_RIF_COUNTER_INGRESS
:
194 rif
->counter_ingress_valid
= valid
;
199 static int mlxsw_sp_rif_counter_edit(struct mlxsw_sp
*mlxsw_sp
, u16 rif_index
,
200 unsigned int counter_index
, bool enable
,
201 enum mlxsw_sp_rif_counter_dir dir
)
203 char ritr_pl
[MLXSW_REG_RITR_LEN
];
204 bool is_egress
= false;
207 if (dir
== MLXSW_SP_RIF_COUNTER_EGRESS
)
209 mlxsw_reg_ritr_rif_pack(ritr_pl
, rif_index
);
210 err
= mlxsw_reg_query(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
214 mlxsw_reg_ritr_counter_pack(ritr_pl
, counter_index
, enable
,
216 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
219 int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp
*mlxsw_sp
,
220 struct mlxsw_sp_rif
*rif
,
221 enum mlxsw_sp_rif_counter_dir dir
, u64
*cnt
)
223 char ricnt_pl
[MLXSW_REG_RICNT_LEN
];
224 unsigned int *p_counter_index
;
228 valid
= mlxsw_sp_rif_counter_valid_get(rif
, dir
);
232 p_counter_index
= mlxsw_sp_rif_p_counter_get(rif
, dir
);
233 if (!p_counter_index
)
235 mlxsw_reg_ricnt_pack(ricnt_pl
, *p_counter_index
,
236 MLXSW_REG_RICNT_OPCODE_NOP
);
237 err
= mlxsw_reg_query(mlxsw_sp
->core
, MLXSW_REG(ricnt
), ricnt_pl
);
240 *cnt
= mlxsw_reg_ricnt_good_unicast_packets_get(ricnt_pl
);
244 static int mlxsw_sp_rif_counter_clear(struct mlxsw_sp
*mlxsw_sp
,
245 unsigned int counter_index
)
247 char ricnt_pl
[MLXSW_REG_RICNT_LEN
];
249 mlxsw_reg_ricnt_pack(ricnt_pl
, counter_index
,
250 MLXSW_REG_RICNT_OPCODE_CLEAR
);
251 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ricnt
), ricnt_pl
);
254 int mlxsw_sp_rif_counter_alloc(struct mlxsw_sp
*mlxsw_sp
,
255 struct mlxsw_sp_rif
*rif
,
256 enum mlxsw_sp_rif_counter_dir dir
)
258 unsigned int *p_counter_index
;
261 p_counter_index
= mlxsw_sp_rif_p_counter_get(rif
, dir
);
262 if (!p_counter_index
)
264 err
= mlxsw_sp_counter_alloc(mlxsw_sp
, MLXSW_SP_COUNTER_SUB_POOL_RIF
,
269 err
= mlxsw_sp_rif_counter_clear(mlxsw_sp
, *p_counter_index
);
271 goto err_counter_clear
;
273 err
= mlxsw_sp_rif_counter_edit(mlxsw_sp
, rif
->rif_index
,
274 *p_counter_index
, true, dir
);
276 goto err_counter_edit
;
277 mlxsw_sp_rif_counter_valid_set(rif
, dir
, true);
282 mlxsw_sp_counter_free(mlxsw_sp
, MLXSW_SP_COUNTER_SUB_POOL_RIF
,
287 void mlxsw_sp_rif_counter_free(struct mlxsw_sp
*mlxsw_sp
,
288 struct mlxsw_sp_rif
*rif
,
289 enum mlxsw_sp_rif_counter_dir dir
)
291 unsigned int *p_counter_index
;
293 if (!mlxsw_sp_rif_counter_valid_get(rif
, dir
))
296 p_counter_index
= mlxsw_sp_rif_p_counter_get(rif
, dir
);
297 if (WARN_ON(!p_counter_index
))
299 mlxsw_sp_rif_counter_edit(mlxsw_sp
, rif
->rif_index
,
300 *p_counter_index
, false, dir
);
301 mlxsw_sp_counter_free(mlxsw_sp
, MLXSW_SP_COUNTER_SUB_POOL_RIF
,
303 mlxsw_sp_rif_counter_valid_set(rif
, dir
, false);
306 static void mlxsw_sp_rif_counters_alloc(struct mlxsw_sp_rif
*rif
)
308 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
309 struct devlink
*devlink
;
311 devlink
= priv_to_devlink(mlxsw_sp
->core
);
312 if (!devlink_dpipe_table_counter_enabled(devlink
,
313 MLXSW_SP_DPIPE_TABLE_NAME_ERIF
))
315 mlxsw_sp_rif_counter_alloc(mlxsw_sp
, rif
, MLXSW_SP_RIF_COUNTER_EGRESS
);
318 static void mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif
*rif
)
320 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
322 mlxsw_sp_rif_counter_free(mlxsw_sp
, rif
, MLXSW_SP_RIF_COUNTER_EGRESS
);
325 static struct mlxsw_sp_rif
*
326 mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp
*mlxsw_sp
,
327 const struct net_device
*dev
);
329 #define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE + 1)
331 struct mlxsw_sp_prefix_usage
{
332 DECLARE_BITMAP(b
, MLXSW_SP_PREFIX_COUNT
);
335 #define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \
336 for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
339 mlxsw_sp_prefix_usage_eq(struct mlxsw_sp_prefix_usage
*prefix_usage1
,
340 struct mlxsw_sp_prefix_usage
*prefix_usage2
)
342 return !memcmp(prefix_usage1
, prefix_usage2
, sizeof(*prefix_usage1
));
346 mlxsw_sp_prefix_usage_none(struct mlxsw_sp_prefix_usage
*prefix_usage
)
348 struct mlxsw_sp_prefix_usage prefix_usage_none
= {{ 0 } };
350 return mlxsw_sp_prefix_usage_eq(prefix_usage
, &prefix_usage_none
);
354 mlxsw_sp_prefix_usage_cpy(struct mlxsw_sp_prefix_usage
*prefix_usage1
,
355 struct mlxsw_sp_prefix_usage
*prefix_usage2
)
357 memcpy(prefix_usage1
, prefix_usage2
, sizeof(*prefix_usage1
));
361 mlxsw_sp_prefix_usage_set(struct mlxsw_sp_prefix_usage
*prefix_usage
,
362 unsigned char prefix_len
)
364 set_bit(prefix_len
, prefix_usage
->b
);
368 mlxsw_sp_prefix_usage_clear(struct mlxsw_sp_prefix_usage
*prefix_usage
,
369 unsigned char prefix_len
)
371 clear_bit(prefix_len
, prefix_usage
->b
);
374 struct mlxsw_sp_fib_key
{
375 unsigned char addr
[sizeof(struct in6_addr
)];
376 unsigned char prefix_len
;
379 enum mlxsw_sp_fib_entry_type
{
380 MLXSW_SP_FIB_ENTRY_TYPE_REMOTE
,
381 MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
,
382 MLXSW_SP_FIB_ENTRY_TYPE_TRAP
,
385 struct mlxsw_sp_nexthop_group
;
388 struct mlxsw_sp_fib_node
{
389 struct list_head entry_list
;
390 struct list_head list
;
391 struct rhash_head ht_node
;
392 struct mlxsw_sp_fib
*fib
;
393 struct mlxsw_sp_fib_key key
;
396 struct mlxsw_sp_fib_entry
{
397 struct list_head list
;
398 struct mlxsw_sp_fib_node
*fib_node
;
399 enum mlxsw_sp_fib_entry_type type
;
400 struct list_head nexthop_group_node
;
401 struct mlxsw_sp_nexthop_group
*nh_group
;
404 struct mlxsw_sp_fib4_entry
{
405 struct mlxsw_sp_fib_entry common
;
412 struct mlxsw_sp_fib6_entry
{
413 struct mlxsw_sp_fib_entry common
;
414 struct list_head rt6_list
;
418 struct mlxsw_sp_rt6
{
419 struct list_head list
;
423 struct mlxsw_sp_lpm_tree
{
425 unsigned int ref_count
;
426 enum mlxsw_sp_l3proto proto
;
427 struct mlxsw_sp_prefix_usage prefix_usage
;
430 struct mlxsw_sp_fib
{
431 struct rhashtable ht
;
432 struct list_head node_list
;
433 struct mlxsw_sp_vr
*vr
;
434 struct mlxsw_sp_lpm_tree
*lpm_tree
;
435 unsigned long prefix_ref_count
[MLXSW_SP_PREFIX_COUNT
];
436 struct mlxsw_sp_prefix_usage prefix_usage
;
437 enum mlxsw_sp_l3proto proto
;
441 u16 id
; /* virtual router ID */
442 u32 tb_id
; /* kernel fib table id */
443 unsigned int rif_count
;
444 struct mlxsw_sp_fib
*fib4
;
445 struct mlxsw_sp_fib
*fib6
;
448 static const struct rhashtable_params mlxsw_sp_fib_ht_params
;
450 static struct mlxsw_sp_fib
*mlxsw_sp_fib_create(struct mlxsw_sp_vr
*vr
,
451 enum mlxsw_sp_l3proto proto
)
453 struct mlxsw_sp_fib
*fib
;
456 fib
= kzalloc(sizeof(*fib
), GFP_KERNEL
);
458 return ERR_PTR(-ENOMEM
);
459 err
= rhashtable_init(&fib
->ht
, &mlxsw_sp_fib_ht_params
);
461 goto err_rhashtable_init
;
462 INIT_LIST_HEAD(&fib
->node_list
);
472 static void mlxsw_sp_fib_destroy(struct mlxsw_sp_fib
*fib
)
474 WARN_ON(!list_empty(&fib
->node_list
));
475 WARN_ON(fib
->lpm_tree
);
476 rhashtable_destroy(&fib
->ht
);
480 static struct mlxsw_sp_lpm_tree
*
481 mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp
*mlxsw_sp
)
483 static struct mlxsw_sp_lpm_tree
*lpm_tree
;
486 for (i
= 0; i
< mlxsw_sp
->router
->lpm
.tree_count
; i
++) {
487 lpm_tree
= &mlxsw_sp
->router
->lpm
.trees
[i
];
488 if (lpm_tree
->ref_count
== 0)
494 static int mlxsw_sp_lpm_tree_alloc(struct mlxsw_sp
*mlxsw_sp
,
495 struct mlxsw_sp_lpm_tree
*lpm_tree
)
497 char ralta_pl
[MLXSW_REG_RALTA_LEN
];
499 mlxsw_reg_ralta_pack(ralta_pl
, true,
500 (enum mlxsw_reg_ralxx_protocol
) lpm_tree
->proto
,
502 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralta
), ralta_pl
);
505 static void mlxsw_sp_lpm_tree_free(struct mlxsw_sp
*mlxsw_sp
,
506 struct mlxsw_sp_lpm_tree
*lpm_tree
)
508 char ralta_pl
[MLXSW_REG_RALTA_LEN
];
510 mlxsw_reg_ralta_pack(ralta_pl
, false,
511 (enum mlxsw_reg_ralxx_protocol
) lpm_tree
->proto
,
513 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralta
), ralta_pl
);
517 mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp
*mlxsw_sp
,
518 struct mlxsw_sp_prefix_usage
*prefix_usage
,
519 struct mlxsw_sp_lpm_tree
*lpm_tree
)
521 char ralst_pl
[MLXSW_REG_RALST_LEN
];
524 u8 last_prefix
= MLXSW_REG_RALST_BIN_NO_CHILD
;
526 mlxsw_sp_prefix_usage_for_each(prefix
, prefix_usage
)
529 mlxsw_reg_ralst_pack(ralst_pl
, root_bin
, lpm_tree
->id
);
530 mlxsw_sp_prefix_usage_for_each(prefix
, prefix_usage
) {
533 mlxsw_reg_ralst_bin_pack(ralst_pl
, prefix
, last_prefix
,
534 MLXSW_REG_RALST_BIN_NO_CHILD
);
535 last_prefix
= prefix
;
537 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralst
), ralst_pl
);
540 static struct mlxsw_sp_lpm_tree
*
541 mlxsw_sp_lpm_tree_create(struct mlxsw_sp
*mlxsw_sp
,
542 struct mlxsw_sp_prefix_usage
*prefix_usage
,
543 enum mlxsw_sp_l3proto proto
)
545 struct mlxsw_sp_lpm_tree
*lpm_tree
;
548 lpm_tree
= mlxsw_sp_lpm_tree_find_unused(mlxsw_sp
);
550 return ERR_PTR(-EBUSY
);
551 lpm_tree
->proto
= proto
;
552 err
= mlxsw_sp_lpm_tree_alloc(mlxsw_sp
, lpm_tree
);
556 err
= mlxsw_sp_lpm_tree_left_struct_set(mlxsw_sp
, prefix_usage
,
559 goto err_left_struct_set
;
560 memcpy(&lpm_tree
->prefix_usage
, prefix_usage
,
561 sizeof(lpm_tree
->prefix_usage
));
565 mlxsw_sp_lpm_tree_free(mlxsw_sp
, lpm_tree
);
569 static void mlxsw_sp_lpm_tree_destroy(struct mlxsw_sp
*mlxsw_sp
,
570 struct mlxsw_sp_lpm_tree
*lpm_tree
)
572 mlxsw_sp_lpm_tree_free(mlxsw_sp
, lpm_tree
);
575 static struct mlxsw_sp_lpm_tree
*
576 mlxsw_sp_lpm_tree_get(struct mlxsw_sp
*mlxsw_sp
,
577 struct mlxsw_sp_prefix_usage
*prefix_usage
,
578 enum mlxsw_sp_l3proto proto
)
580 struct mlxsw_sp_lpm_tree
*lpm_tree
;
583 for (i
= 0; i
< mlxsw_sp
->router
->lpm
.tree_count
; i
++) {
584 lpm_tree
= &mlxsw_sp
->router
->lpm
.trees
[i
];
585 if (lpm_tree
->ref_count
!= 0 &&
586 lpm_tree
->proto
== proto
&&
587 mlxsw_sp_prefix_usage_eq(&lpm_tree
->prefix_usage
,
591 return mlxsw_sp_lpm_tree_create(mlxsw_sp
, prefix_usage
, proto
);
594 static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree
*lpm_tree
)
596 lpm_tree
->ref_count
++;
599 static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp
*mlxsw_sp
,
600 struct mlxsw_sp_lpm_tree
*lpm_tree
)
602 if (--lpm_tree
->ref_count
== 0)
603 mlxsw_sp_lpm_tree_destroy(mlxsw_sp
, lpm_tree
);
606 #define MLXSW_SP_LPM_TREE_MIN 1 /* tree 0 is reserved */
608 static int mlxsw_sp_lpm_init(struct mlxsw_sp
*mlxsw_sp
)
610 struct mlxsw_sp_lpm_tree
*lpm_tree
;
614 if (!MLXSW_CORE_RES_VALID(mlxsw_sp
->core
, MAX_LPM_TREES
))
617 max_trees
= MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_LPM_TREES
);
618 mlxsw_sp
->router
->lpm
.tree_count
= max_trees
- MLXSW_SP_LPM_TREE_MIN
;
619 mlxsw_sp
->router
->lpm
.trees
= kcalloc(mlxsw_sp
->router
->lpm
.tree_count
,
620 sizeof(struct mlxsw_sp_lpm_tree
),
622 if (!mlxsw_sp
->router
->lpm
.trees
)
625 for (i
= 0; i
< mlxsw_sp
->router
->lpm
.tree_count
; i
++) {
626 lpm_tree
= &mlxsw_sp
->router
->lpm
.trees
[i
];
627 lpm_tree
->id
= i
+ MLXSW_SP_LPM_TREE_MIN
;
633 static void mlxsw_sp_lpm_fini(struct mlxsw_sp
*mlxsw_sp
)
635 kfree(mlxsw_sp
->router
->lpm
.trees
);
638 static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr
*vr
)
640 return !!vr
->fib4
|| !!vr
->fib6
;
643 static struct mlxsw_sp_vr
*mlxsw_sp_vr_find_unused(struct mlxsw_sp
*mlxsw_sp
)
645 struct mlxsw_sp_vr
*vr
;
648 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
649 vr
= &mlxsw_sp
->router
->vrs
[i
];
650 if (!mlxsw_sp_vr_is_used(vr
))
656 static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp
*mlxsw_sp
,
657 const struct mlxsw_sp_fib
*fib
, u8 tree_id
)
659 char raltb_pl
[MLXSW_REG_RALTB_LEN
];
661 mlxsw_reg_raltb_pack(raltb_pl
, fib
->vr
->id
,
662 (enum mlxsw_reg_ralxx_protocol
) fib
->proto
,
664 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(raltb
), raltb_pl
);
667 static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp
*mlxsw_sp
,
668 const struct mlxsw_sp_fib
*fib
)
670 char raltb_pl
[MLXSW_REG_RALTB_LEN
];
672 /* Bind to tree 0 which is default */
673 mlxsw_reg_raltb_pack(raltb_pl
, fib
->vr
->id
,
674 (enum mlxsw_reg_ralxx_protocol
) fib
->proto
, 0);
675 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(raltb
), raltb_pl
);
678 static u32
mlxsw_sp_fix_tb_id(u32 tb_id
)
680 /* For our purpose, squash main and local table into one */
681 if (tb_id
== RT_TABLE_LOCAL
)
682 tb_id
= RT_TABLE_MAIN
;
686 static struct mlxsw_sp_vr
*mlxsw_sp_vr_find(struct mlxsw_sp
*mlxsw_sp
,
689 struct mlxsw_sp_vr
*vr
;
692 tb_id
= mlxsw_sp_fix_tb_id(tb_id
);
694 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
695 vr
= &mlxsw_sp
->router
->vrs
[i
];
696 if (mlxsw_sp_vr_is_used(vr
) && vr
->tb_id
== tb_id
)
702 static struct mlxsw_sp_fib
*mlxsw_sp_vr_fib(const struct mlxsw_sp_vr
*vr
,
703 enum mlxsw_sp_l3proto proto
)
706 case MLXSW_SP_L3_PROTO_IPV4
:
708 case MLXSW_SP_L3_PROTO_IPV6
:
714 static struct mlxsw_sp_vr
*mlxsw_sp_vr_create(struct mlxsw_sp
*mlxsw_sp
,
717 struct mlxsw_sp_vr
*vr
;
720 vr
= mlxsw_sp_vr_find_unused(mlxsw_sp
);
722 return ERR_PTR(-EBUSY
);
723 vr
->fib4
= mlxsw_sp_fib_create(vr
, MLXSW_SP_L3_PROTO_IPV4
);
724 if (IS_ERR(vr
->fib4
))
725 return ERR_CAST(vr
->fib4
);
726 vr
->fib6
= mlxsw_sp_fib_create(vr
, MLXSW_SP_L3_PROTO_IPV6
);
727 if (IS_ERR(vr
->fib6
)) {
728 err
= PTR_ERR(vr
->fib6
);
729 goto err_fib6_create
;
735 mlxsw_sp_fib_destroy(vr
->fib4
);
740 static void mlxsw_sp_vr_destroy(struct mlxsw_sp_vr
*vr
)
742 mlxsw_sp_fib_destroy(vr
->fib6
);
744 mlxsw_sp_fib_destroy(vr
->fib4
);
748 static struct mlxsw_sp_vr
*mlxsw_sp_vr_get(struct mlxsw_sp
*mlxsw_sp
, u32 tb_id
)
750 struct mlxsw_sp_vr
*vr
;
752 tb_id
= mlxsw_sp_fix_tb_id(tb_id
);
753 vr
= mlxsw_sp_vr_find(mlxsw_sp
, tb_id
);
755 vr
= mlxsw_sp_vr_create(mlxsw_sp
, tb_id
);
759 static void mlxsw_sp_vr_put(struct mlxsw_sp_vr
*vr
)
761 if (!vr
->rif_count
&& list_empty(&vr
->fib4
->node_list
) &&
762 list_empty(&vr
->fib6
->node_list
))
763 mlxsw_sp_vr_destroy(vr
);
767 mlxsw_sp_vr_lpm_tree_should_replace(struct mlxsw_sp_vr
*vr
,
768 enum mlxsw_sp_l3proto proto
, u8 tree_id
)
770 struct mlxsw_sp_fib
*fib
= mlxsw_sp_vr_fib(vr
, proto
);
772 if (!mlxsw_sp_vr_is_used(vr
))
774 if (fib
->lpm_tree
&& fib
->lpm_tree
->id
== tree_id
)
779 static int mlxsw_sp_vr_lpm_tree_replace(struct mlxsw_sp
*mlxsw_sp
,
780 struct mlxsw_sp_fib
*fib
,
781 struct mlxsw_sp_lpm_tree
*new_tree
)
783 struct mlxsw_sp_lpm_tree
*old_tree
= fib
->lpm_tree
;
786 err
= mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp
, fib
, new_tree
->id
);
789 fib
->lpm_tree
= new_tree
;
790 mlxsw_sp_lpm_tree_hold(new_tree
);
791 mlxsw_sp_lpm_tree_put(mlxsw_sp
, old_tree
);
795 static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp
*mlxsw_sp
,
796 struct mlxsw_sp_fib
*fib
,
797 struct mlxsw_sp_lpm_tree
*new_tree
)
799 struct mlxsw_sp_lpm_tree
*old_tree
= fib
->lpm_tree
;
800 enum mlxsw_sp_l3proto proto
= fib
->proto
;
801 u8 old_id
, new_id
= new_tree
->id
;
802 struct mlxsw_sp_vr
*vr
;
807 old_id
= old_tree
->id
;
809 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
810 vr
= &mlxsw_sp
->router
->vrs
[i
];
811 if (!mlxsw_sp_vr_lpm_tree_should_replace(vr
, proto
, old_id
))
813 err
= mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp
,
814 mlxsw_sp_vr_fib(vr
, proto
),
817 goto err_tree_replace
;
823 for (i
--; i
>= 0; i
--) {
824 if (!mlxsw_sp_vr_lpm_tree_should_replace(vr
, proto
, new_id
))
826 mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp
,
827 mlxsw_sp_vr_fib(vr
, proto
),
833 err
= mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp
, fib
, new_tree
->id
);
836 fib
->lpm_tree
= new_tree
;
837 mlxsw_sp_lpm_tree_hold(new_tree
);
842 mlxsw_sp_vrs_prefixes(struct mlxsw_sp
*mlxsw_sp
,
843 enum mlxsw_sp_l3proto proto
,
844 struct mlxsw_sp_prefix_usage
*req_prefix_usage
)
848 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
849 struct mlxsw_sp_vr
*vr
= &mlxsw_sp
->router
->vrs
[i
];
850 struct mlxsw_sp_fib
*fib
= mlxsw_sp_vr_fib(vr
, proto
);
851 unsigned char prefix
;
853 if (!mlxsw_sp_vr_is_used(vr
))
855 mlxsw_sp_prefix_usage_for_each(prefix
, &fib
->prefix_usage
)
856 mlxsw_sp_prefix_usage_set(req_prefix_usage
, prefix
);
860 static int mlxsw_sp_vrs_init(struct mlxsw_sp
*mlxsw_sp
)
862 struct mlxsw_sp_vr
*vr
;
866 if (!MLXSW_CORE_RES_VALID(mlxsw_sp
->core
, MAX_VRS
))
869 max_vrs
= MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
);
870 mlxsw_sp
->router
->vrs
= kcalloc(max_vrs
, sizeof(struct mlxsw_sp_vr
),
872 if (!mlxsw_sp
->router
->vrs
)
875 for (i
= 0; i
< max_vrs
; i
++) {
876 vr
= &mlxsw_sp
->router
->vrs
[i
];
883 static void mlxsw_sp_router_fib_flush(struct mlxsw_sp
*mlxsw_sp
);
885 static void mlxsw_sp_vrs_fini(struct mlxsw_sp
*mlxsw_sp
)
887 /* At this stage we're guaranteed not to have new incoming
888 * FIB notifications and the work queue is free from FIBs
889 * sitting on top of mlxsw netdevs. However, we can still
890 * have other FIBs queued. Flush the queue before flushing
891 * the device's tables. No need for locks, as we're the only
894 mlxsw_core_flush_owq();
895 mlxsw_sp_router_fib_flush(mlxsw_sp
);
896 kfree(mlxsw_sp
->router
->vrs
);
899 static struct net_device
*
900 __mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device
*ol_dev
)
902 struct ip_tunnel
*tun
= netdev_priv(ol_dev
);
903 struct net
*net
= dev_net(ol_dev
);
905 return __dev_get_by_index(net
, tun
->parms
.link
);
908 static u32
mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device
*ol_dev
)
910 struct net_device
*d
= __mlxsw_sp_ipip_netdev_ul_dev_get(ol_dev
);
913 return l3mdev_fib_table(d
) ? : RT_TABLE_MAIN
;
915 return l3mdev_fib_table(ol_dev
) ? : RT_TABLE_MAIN
;
918 struct mlxsw_sp_neigh_key
{
922 struct mlxsw_sp_neigh_entry
{
923 struct list_head rif_list_node
;
924 struct rhash_head ht_node
;
925 struct mlxsw_sp_neigh_key key
;
928 unsigned char ha
[ETH_ALEN
];
929 struct list_head nexthop_list
; /* list of nexthops using
932 struct list_head nexthop_neighs_list_node
;
933 unsigned int counter_index
;
937 static const struct rhashtable_params mlxsw_sp_neigh_ht_params
= {
938 .key_offset
= offsetof(struct mlxsw_sp_neigh_entry
, key
),
939 .head_offset
= offsetof(struct mlxsw_sp_neigh_entry
, ht_node
),
940 .key_len
= sizeof(struct mlxsw_sp_neigh_key
),
943 struct mlxsw_sp_neigh_entry
*
944 mlxsw_sp_rif_neigh_next(struct mlxsw_sp_rif
*rif
,
945 struct mlxsw_sp_neigh_entry
*neigh_entry
)
948 if (list_empty(&rif
->neigh_list
))
951 return list_first_entry(&rif
->neigh_list
,
952 typeof(*neigh_entry
),
955 if (neigh_entry
->rif_list_node
.next
== &rif
->neigh_list
)
957 return list_next_entry(neigh_entry
, rif_list_node
);
960 int mlxsw_sp_neigh_entry_type(struct mlxsw_sp_neigh_entry
*neigh_entry
)
962 return neigh_entry
->key
.n
->tbl
->family
;
966 mlxsw_sp_neigh_entry_ha(struct mlxsw_sp_neigh_entry
*neigh_entry
)
968 return neigh_entry
->ha
;
971 u32
mlxsw_sp_neigh4_entry_dip(struct mlxsw_sp_neigh_entry
*neigh_entry
)
975 n
= neigh_entry
->key
.n
;
976 return ntohl(*((__be32
*) n
->primary_key
));
980 mlxsw_sp_neigh6_entry_dip(struct mlxsw_sp_neigh_entry
*neigh_entry
)
984 n
= neigh_entry
->key
.n
;
985 return (struct in6_addr
*) &n
->primary_key
;
988 int mlxsw_sp_neigh_counter_get(struct mlxsw_sp
*mlxsw_sp
,
989 struct mlxsw_sp_neigh_entry
*neigh_entry
,
992 if (!neigh_entry
->counter_valid
)
995 return mlxsw_sp_flow_counter_get(mlxsw_sp
, neigh_entry
->counter_index
,
999 static struct mlxsw_sp_neigh_entry
*
1000 mlxsw_sp_neigh_entry_alloc(struct mlxsw_sp
*mlxsw_sp
, struct neighbour
*n
,
1003 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1005 neigh_entry
= kzalloc(sizeof(*neigh_entry
), GFP_KERNEL
);
1009 neigh_entry
->key
.n
= n
;
1010 neigh_entry
->rif
= rif
;
1011 INIT_LIST_HEAD(&neigh_entry
->nexthop_list
);
1016 static void mlxsw_sp_neigh_entry_free(struct mlxsw_sp_neigh_entry
*neigh_entry
)
1022 mlxsw_sp_neigh_entry_insert(struct mlxsw_sp
*mlxsw_sp
,
1023 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1025 return rhashtable_insert_fast(&mlxsw_sp
->router
->neigh_ht
,
1026 &neigh_entry
->ht_node
,
1027 mlxsw_sp_neigh_ht_params
);
1031 mlxsw_sp_neigh_entry_remove(struct mlxsw_sp
*mlxsw_sp
,
1032 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1034 rhashtable_remove_fast(&mlxsw_sp
->router
->neigh_ht
,
1035 &neigh_entry
->ht_node
,
1036 mlxsw_sp_neigh_ht_params
);
1040 mlxsw_sp_neigh_counter_should_alloc(struct mlxsw_sp
*mlxsw_sp
,
1041 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1043 struct devlink
*devlink
;
1044 const char *table_name
;
1046 switch (mlxsw_sp_neigh_entry_type(neigh_entry
)) {
1048 table_name
= MLXSW_SP_DPIPE_TABLE_NAME_HOST4
;
1051 table_name
= MLXSW_SP_DPIPE_TABLE_NAME_HOST6
;
1058 devlink
= priv_to_devlink(mlxsw_sp
->core
);
1059 return devlink_dpipe_table_counter_enabled(devlink
, table_name
);
1063 mlxsw_sp_neigh_counter_alloc(struct mlxsw_sp
*mlxsw_sp
,
1064 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1066 if (!mlxsw_sp_neigh_counter_should_alloc(mlxsw_sp
, neigh_entry
))
1069 if (mlxsw_sp_flow_counter_alloc(mlxsw_sp
, &neigh_entry
->counter_index
))
1072 neigh_entry
->counter_valid
= true;
1076 mlxsw_sp_neigh_counter_free(struct mlxsw_sp
*mlxsw_sp
,
1077 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1079 if (!neigh_entry
->counter_valid
)
1081 mlxsw_sp_flow_counter_free(mlxsw_sp
,
1082 neigh_entry
->counter_index
);
1083 neigh_entry
->counter_valid
= false;
1086 static struct mlxsw_sp_neigh_entry
*
1087 mlxsw_sp_neigh_entry_create(struct mlxsw_sp
*mlxsw_sp
, struct neighbour
*n
)
1089 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1090 struct mlxsw_sp_rif
*rif
;
1093 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, n
->dev
);
1095 return ERR_PTR(-EINVAL
);
1097 neigh_entry
= mlxsw_sp_neigh_entry_alloc(mlxsw_sp
, n
, rif
->rif_index
);
1099 return ERR_PTR(-ENOMEM
);
1101 err
= mlxsw_sp_neigh_entry_insert(mlxsw_sp
, neigh_entry
);
1103 goto err_neigh_entry_insert
;
1105 mlxsw_sp_neigh_counter_alloc(mlxsw_sp
, neigh_entry
);
1106 list_add(&neigh_entry
->rif_list_node
, &rif
->neigh_list
);
1110 err_neigh_entry_insert
:
1111 mlxsw_sp_neigh_entry_free(neigh_entry
);
1112 return ERR_PTR(err
);
1116 mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp
*mlxsw_sp
,
1117 struct mlxsw_sp_neigh_entry
*neigh_entry
)
1119 list_del(&neigh_entry
->rif_list_node
);
1120 mlxsw_sp_neigh_counter_free(mlxsw_sp
, neigh_entry
);
1121 mlxsw_sp_neigh_entry_remove(mlxsw_sp
, neigh_entry
);
1122 mlxsw_sp_neigh_entry_free(neigh_entry
);
1125 static struct mlxsw_sp_neigh_entry
*
1126 mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp
*mlxsw_sp
, struct neighbour
*n
)
1128 struct mlxsw_sp_neigh_key key
;
1131 return rhashtable_lookup_fast(&mlxsw_sp
->router
->neigh_ht
,
1132 &key
, mlxsw_sp_neigh_ht_params
);
1136 mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp
*mlxsw_sp
)
1138 unsigned long interval
;
1140 #if IS_ENABLED(CONFIG_IPV6)
1141 interval
= min_t(unsigned long,
1142 NEIGH_VAR(&arp_tbl
.parms
, DELAY_PROBE_TIME
),
1143 NEIGH_VAR(&nd_tbl
.parms
, DELAY_PROBE_TIME
));
1145 interval
= NEIGH_VAR(&arp_tbl
.parms
, DELAY_PROBE_TIME
);
1147 mlxsw_sp
->router
->neighs_update
.interval
= jiffies_to_msecs(interval
);
1150 static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp
*mlxsw_sp
,
1154 struct net_device
*dev
;
1155 struct neighbour
*n
;
1160 mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl
, ent_index
, &rif
, &dip
);
1162 if (!mlxsw_sp
->router
->rifs
[rif
]) {
1163 dev_err_ratelimited(mlxsw_sp
->bus_info
->dev
, "Incorrect RIF in neighbour entry\n");
1168 dev
= mlxsw_sp
->router
->rifs
[rif
]->dev
;
1169 n
= neigh_lookup(&arp_tbl
, &dipn
, dev
);
1171 netdev_err(dev
, "Failed to find matching neighbour for IP=%pI4h\n",
1176 netdev_dbg(dev
, "Updating neighbour with IP=%pI4h\n", &dip
);
1177 neigh_event_send(n
, NULL
);
1181 #if IS_ENABLED(CONFIG_IPV6)
1182 static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp
*mlxsw_sp
,
1186 struct net_device
*dev
;
1187 struct neighbour
*n
;
1188 struct in6_addr dip
;
1191 mlxsw_reg_rauhtd_ent_ipv6_unpack(rauhtd_pl
, rec_index
, &rif
,
1194 if (!mlxsw_sp
->router
->rifs
[rif
]) {
1195 dev_err_ratelimited(mlxsw_sp
->bus_info
->dev
, "Incorrect RIF in neighbour entry\n");
1199 dev
= mlxsw_sp
->router
->rifs
[rif
]->dev
;
1200 n
= neigh_lookup(&nd_tbl
, &dip
, dev
);
1202 netdev_err(dev
, "Failed to find matching neighbour for IP=%pI6c\n",
1207 netdev_dbg(dev
, "Updating neighbour with IP=%pI6c\n", &dip
);
1208 neigh_event_send(n
, NULL
);
1212 static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp
*mlxsw_sp
,
1219 static void mlxsw_sp_router_neigh_rec_ipv4_process(struct mlxsw_sp
*mlxsw_sp
,
1226 num_entries
= mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl
,
1228 /* Hardware starts counting at 0, so add 1. */
1231 /* Each record consists of several neighbour entries. */
1232 for (i
= 0; i
< num_entries
; i
++) {
1235 ent_index
= rec_index
* MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC
+ i
;
1236 mlxsw_sp_router_neigh_ent_ipv4_process(mlxsw_sp
, rauhtd_pl
,
1242 static void mlxsw_sp_router_neigh_rec_ipv6_process(struct mlxsw_sp
*mlxsw_sp
,
1246 /* One record contains one entry. */
1247 mlxsw_sp_router_neigh_ent_ipv6_process(mlxsw_sp
, rauhtd_pl
,
1251 static void mlxsw_sp_router_neigh_rec_process(struct mlxsw_sp
*mlxsw_sp
,
1252 char *rauhtd_pl
, int rec_index
)
1254 switch (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl
, rec_index
)) {
1255 case MLXSW_REG_RAUHTD_TYPE_IPV4
:
1256 mlxsw_sp_router_neigh_rec_ipv4_process(mlxsw_sp
, rauhtd_pl
,
1259 case MLXSW_REG_RAUHTD_TYPE_IPV6
:
1260 mlxsw_sp_router_neigh_rec_ipv6_process(mlxsw_sp
, rauhtd_pl
,
1266 static bool mlxsw_sp_router_rauhtd_is_full(char *rauhtd_pl
)
1268 u8 num_rec
, last_rec_index
, num_entries
;
1270 num_rec
= mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl
);
1271 last_rec_index
= num_rec
- 1;
1273 if (num_rec
< MLXSW_REG_RAUHTD_REC_MAX_NUM
)
1275 if (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl
, last_rec_index
) ==
1276 MLXSW_REG_RAUHTD_TYPE_IPV6
)
1279 num_entries
= mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl
,
1281 if (++num_entries
== MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC
)
1287 __mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp
*mlxsw_sp
,
1289 enum mlxsw_reg_rauhtd_type type
)
1294 /* Make sure the neighbour's netdev isn't removed in the
1299 mlxsw_reg_rauhtd_pack(rauhtd_pl
, type
);
1300 err
= mlxsw_reg_query(mlxsw_sp
->core
, MLXSW_REG(rauhtd
),
1303 dev_err_ratelimited(mlxsw_sp
->bus_info
->dev
, "Failed to dump neighbour talbe\n");
1306 num_rec
= mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl
);
1307 for (i
= 0; i
< num_rec
; i
++)
1308 mlxsw_sp_router_neigh_rec_process(mlxsw_sp
, rauhtd_pl
,
1310 } while (mlxsw_sp_router_rauhtd_is_full(rauhtd_pl
));
1316 static int mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp
*mlxsw_sp
)
1318 enum mlxsw_reg_rauhtd_type type
;
1322 rauhtd_pl
= kmalloc(MLXSW_REG_RAUHTD_LEN
, GFP_KERNEL
);
1326 type
= MLXSW_REG_RAUHTD_TYPE_IPV4
;
1327 err
= __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp
, rauhtd_pl
, type
);
1331 type
= MLXSW_REG_RAUHTD_TYPE_IPV6
;
1332 err
= __mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp
, rauhtd_pl
, type
);
1338 static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp
*mlxsw_sp
)
1340 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1342 /* Take RTNL mutex here to prevent lists from changes */
1344 list_for_each_entry(neigh_entry
, &mlxsw_sp
->router
->nexthop_neighs_list
,
1345 nexthop_neighs_list_node
)
1346 /* If this neigh have nexthops, make the kernel think this neigh
1347 * is active regardless of the traffic.
1349 neigh_event_send(neigh_entry
->key
.n
, NULL
);
1354 mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp
*mlxsw_sp
)
1356 unsigned long interval
= mlxsw_sp
->router
->neighs_update
.interval
;
1358 mlxsw_core_schedule_dw(&mlxsw_sp
->router
->neighs_update
.dw
,
1359 msecs_to_jiffies(interval
));
1362 static void mlxsw_sp_router_neighs_update_work(struct work_struct
*work
)
1364 struct mlxsw_sp_router
*router
;
1367 router
= container_of(work
, struct mlxsw_sp_router
,
1368 neighs_update
.dw
.work
);
1369 err
= mlxsw_sp_router_neighs_update_rauhtd(router
->mlxsw_sp
);
1371 dev_err(router
->mlxsw_sp
->bus_info
->dev
, "Could not update kernel for neigh activity");
1373 mlxsw_sp_router_neighs_update_nh(router
->mlxsw_sp
);
1375 mlxsw_sp_router_neighs_update_work_schedule(router
->mlxsw_sp
);
1378 static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct
*work
)
1380 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1381 struct mlxsw_sp_router
*router
;
1383 router
= container_of(work
, struct mlxsw_sp_router
,
1384 nexthop_probe_dw
.work
);
1385 /* Iterate over nexthop neighbours, find those who are unresolved and
1386 * send arp on them. This solves the chicken-egg problem when
1387 * the nexthop wouldn't get offloaded until the neighbor is resolved
1388 * but it wouldn't get resolved ever in case traffic is flowing in HW
1389 * using different nexthop.
1391 * Take RTNL mutex here to prevent lists from changes.
1394 list_for_each_entry(neigh_entry
, &router
->nexthop_neighs_list
,
1395 nexthop_neighs_list_node
)
1396 if (!neigh_entry
->connected
)
1397 neigh_event_send(neigh_entry
->key
.n
, NULL
);
1400 mlxsw_core_schedule_dw(&router
->nexthop_probe_dw
,
1401 MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL
);
1405 mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp
*mlxsw_sp
,
1406 struct mlxsw_sp_neigh_entry
*neigh_entry
,
1409 static enum mlxsw_reg_rauht_op
mlxsw_sp_rauht_op(bool adding
)
1411 return adding
? MLXSW_REG_RAUHT_OP_WRITE_ADD
:
1412 MLXSW_REG_RAUHT_OP_WRITE_DELETE
;
1416 mlxsw_sp_router_neigh_entry_op4(struct mlxsw_sp
*mlxsw_sp
,
1417 struct mlxsw_sp_neigh_entry
*neigh_entry
,
1418 enum mlxsw_reg_rauht_op op
)
1420 struct neighbour
*n
= neigh_entry
->key
.n
;
1421 u32 dip
= ntohl(*((__be32
*) n
->primary_key
));
1422 char rauht_pl
[MLXSW_REG_RAUHT_LEN
];
1424 mlxsw_reg_rauht_pack4(rauht_pl
, op
, neigh_entry
->rif
, neigh_entry
->ha
,
1426 if (neigh_entry
->counter_valid
)
1427 mlxsw_reg_rauht_pack_counter(rauht_pl
,
1428 neigh_entry
->counter_index
);
1429 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(rauht
), rauht_pl
);
1433 mlxsw_sp_router_neigh_entry_op6(struct mlxsw_sp
*mlxsw_sp
,
1434 struct mlxsw_sp_neigh_entry
*neigh_entry
,
1435 enum mlxsw_reg_rauht_op op
)
1437 struct neighbour
*n
= neigh_entry
->key
.n
;
1438 char rauht_pl
[MLXSW_REG_RAUHT_LEN
];
1439 const char *dip
= n
->primary_key
;
1441 mlxsw_reg_rauht_pack6(rauht_pl
, op
, neigh_entry
->rif
, neigh_entry
->ha
,
1443 if (neigh_entry
->counter_valid
)
1444 mlxsw_reg_rauht_pack_counter(rauht_pl
,
1445 neigh_entry
->counter_index
);
1446 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(rauht
), rauht_pl
);
1449 bool mlxsw_sp_neigh_ipv6_ignore(struct mlxsw_sp_neigh_entry
*neigh_entry
)
1451 struct neighbour
*n
= neigh_entry
->key
.n
;
1453 /* Packets with a link-local destination address are trapped
1454 * after LPM lookup and never reach the neighbour table, so
1455 * there is no need to program such neighbours to the device.
1457 if (ipv6_addr_type((struct in6_addr
*) &n
->primary_key
) &
1458 IPV6_ADDR_LINKLOCAL
)
1464 mlxsw_sp_neigh_entry_update(struct mlxsw_sp
*mlxsw_sp
,
1465 struct mlxsw_sp_neigh_entry
*neigh_entry
,
1468 if (!adding
&& !neigh_entry
->connected
)
1470 neigh_entry
->connected
= adding
;
1471 if (neigh_entry
->key
.n
->tbl
->family
== AF_INET
) {
1472 mlxsw_sp_router_neigh_entry_op4(mlxsw_sp
, neigh_entry
,
1473 mlxsw_sp_rauht_op(adding
));
1474 } else if (neigh_entry
->key
.n
->tbl
->family
== AF_INET6
) {
1475 if (mlxsw_sp_neigh_ipv6_ignore(neigh_entry
))
1477 mlxsw_sp_router_neigh_entry_op6(mlxsw_sp
, neigh_entry
,
1478 mlxsw_sp_rauht_op(adding
));
1485 mlxsw_sp_neigh_entry_counter_update(struct mlxsw_sp
*mlxsw_sp
,
1486 struct mlxsw_sp_neigh_entry
*neigh_entry
,
1490 mlxsw_sp_neigh_counter_alloc(mlxsw_sp
, neigh_entry
);
1492 mlxsw_sp_neigh_counter_free(mlxsw_sp
, neigh_entry
);
1493 mlxsw_sp_neigh_entry_update(mlxsw_sp
, neigh_entry
, true);
1496 struct mlxsw_sp_neigh_event_work
{
1497 struct work_struct work
;
1498 struct mlxsw_sp
*mlxsw_sp
;
1499 struct neighbour
*n
;
1502 static void mlxsw_sp_router_neigh_event_work(struct work_struct
*work
)
1504 struct mlxsw_sp_neigh_event_work
*neigh_work
=
1505 container_of(work
, struct mlxsw_sp_neigh_event_work
, work
);
1506 struct mlxsw_sp
*mlxsw_sp
= neigh_work
->mlxsw_sp
;
1507 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1508 struct neighbour
*n
= neigh_work
->n
;
1509 unsigned char ha
[ETH_ALEN
];
1510 bool entry_connected
;
1513 /* If these parameters are changed after we release the lock,
1514 * then we are guaranteed to receive another event letting us
1517 read_lock_bh(&n
->lock
);
1518 memcpy(ha
, n
->ha
, ETH_ALEN
);
1519 nud_state
= n
->nud_state
;
1521 read_unlock_bh(&n
->lock
);
1524 entry_connected
= nud_state
& NUD_VALID
&& !dead
;
1525 neigh_entry
= mlxsw_sp_neigh_entry_lookup(mlxsw_sp
, n
);
1526 if (!entry_connected
&& !neigh_entry
)
1529 neigh_entry
= mlxsw_sp_neigh_entry_create(mlxsw_sp
, n
);
1530 if (IS_ERR(neigh_entry
))
1534 memcpy(neigh_entry
->ha
, ha
, ETH_ALEN
);
1535 mlxsw_sp_neigh_entry_update(mlxsw_sp
, neigh_entry
, entry_connected
);
1536 mlxsw_sp_nexthop_neigh_update(mlxsw_sp
, neigh_entry
, !entry_connected
);
1538 if (!neigh_entry
->connected
&& list_empty(&neigh_entry
->nexthop_list
))
1539 mlxsw_sp_neigh_entry_destroy(mlxsw_sp
, neigh_entry
);
1547 int mlxsw_sp_router_netevent_event(struct notifier_block
*unused
,
1548 unsigned long event
, void *ptr
)
1550 struct mlxsw_sp_neigh_event_work
*neigh_work
;
1551 struct mlxsw_sp_port
*mlxsw_sp_port
;
1552 struct mlxsw_sp
*mlxsw_sp
;
1553 unsigned long interval
;
1554 struct neigh_parms
*p
;
1555 struct neighbour
*n
;
1558 case NETEVENT_DELAY_PROBE_TIME_UPDATE
:
1561 /* We don't care about changes in the default table. */
1562 if (!p
->dev
|| (p
->tbl
->family
!= AF_INET
&&
1563 p
->tbl
->family
!= AF_INET6
))
1566 /* We are in atomic context and can't take RTNL mutex,
1567 * so use RCU variant to walk the device chain.
1569 mlxsw_sp_port
= mlxsw_sp_port_lower_dev_hold(p
->dev
);
1573 mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
1574 interval
= jiffies_to_msecs(NEIGH_VAR(p
, DELAY_PROBE_TIME
));
1575 mlxsw_sp
->router
->neighs_update
.interval
= interval
;
1577 mlxsw_sp_port_dev_put(mlxsw_sp_port
);
1579 case NETEVENT_NEIGH_UPDATE
:
1582 if (n
->tbl
->family
!= AF_INET
&& n
->tbl
->family
!= AF_INET6
)
1585 mlxsw_sp_port
= mlxsw_sp_port_lower_dev_hold(n
->dev
);
1589 neigh_work
= kzalloc(sizeof(*neigh_work
), GFP_ATOMIC
);
1591 mlxsw_sp_port_dev_put(mlxsw_sp_port
);
1595 INIT_WORK(&neigh_work
->work
, mlxsw_sp_router_neigh_event_work
);
1596 neigh_work
->mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
1599 /* Take a reference to ensure the neighbour won't be
1600 * destructed until we drop the reference in delayed
1604 mlxsw_core_schedule_work(&neigh_work
->work
);
1605 mlxsw_sp_port_dev_put(mlxsw_sp_port
);
1612 static int mlxsw_sp_neigh_init(struct mlxsw_sp
*mlxsw_sp
)
1616 err
= rhashtable_init(&mlxsw_sp
->router
->neigh_ht
,
1617 &mlxsw_sp_neigh_ht_params
);
1621 /* Initialize the polling interval according to the default
1624 mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp
);
1626 /* Create the delayed works for the activity_update */
1627 INIT_DELAYED_WORK(&mlxsw_sp
->router
->neighs_update
.dw
,
1628 mlxsw_sp_router_neighs_update_work
);
1629 INIT_DELAYED_WORK(&mlxsw_sp
->router
->nexthop_probe_dw
,
1630 mlxsw_sp_router_probe_unresolved_nexthops
);
1631 mlxsw_core_schedule_dw(&mlxsw_sp
->router
->neighs_update
.dw
, 0);
1632 mlxsw_core_schedule_dw(&mlxsw_sp
->router
->nexthop_probe_dw
, 0);
1636 static void mlxsw_sp_neigh_fini(struct mlxsw_sp
*mlxsw_sp
)
1638 cancel_delayed_work_sync(&mlxsw_sp
->router
->neighs_update
.dw
);
1639 cancel_delayed_work_sync(&mlxsw_sp
->router
->nexthop_probe_dw
);
1640 rhashtable_destroy(&mlxsw_sp
->router
->neigh_ht
);
1643 static void mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp
*mlxsw_sp
,
1644 struct mlxsw_sp_rif
*rif
)
1646 struct mlxsw_sp_neigh_entry
*neigh_entry
, *tmp
;
1648 list_for_each_entry_safe(neigh_entry
, tmp
, &rif
->neigh_list
,
1650 mlxsw_sp_neigh_entry_update(mlxsw_sp
, neigh_entry
, false);
1651 mlxsw_sp_neigh_entry_destroy(mlxsw_sp
, neigh_entry
);
1655 struct mlxsw_sp_nexthop_key
{
1656 struct fib_nh
*fib_nh
;
1659 struct mlxsw_sp_nexthop
{
1660 struct list_head neigh_list_node
; /* member of neigh entry list */
1661 struct list_head rif_list_node
;
1662 struct mlxsw_sp_nexthop_group
*nh_grp
; /* pointer back to the group
1665 struct rhash_head ht_node
;
1666 struct mlxsw_sp_nexthop_key key
;
1667 unsigned char gw_addr
[sizeof(struct in6_addr
)];
1669 struct mlxsw_sp_rif
*rif
;
1670 u8 should_offload
:1, /* set indicates this neigh is connected and
1671 * should be put to KVD linear area of this group.
1673 offloaded
:1, /* set in case the neigh is actually put into
1674 * KVD linear area of this group.
1676 update
:1; /* set indicates that MAC of this neigh should be
1679 struct mlxsw_sp_neigh_entry
*neigh_entry
;
1682 struct mlxsw_sp_nexthop_group
{
1684 struct rhash_head ht_node
;
1685 struct list_head fib_list
; /* list of fib entries that use this group */
1686 struct neigh_table
*neigh_tbl
;
1687 u8 adj_index_valid
:1,
1688 gateway
:1; /* routes using the group use a gateway */
1692 struct mlxsw_sp_nexthop nexthops
[0];
1693 #define nh_rif nexthops[0].rif
1696 static struct fib_info
*
1697 mlxsw_sp_nexthop4_group_fi(const struct mlxsw_sp_nexthop_group
*nh_grp
)
1699 return nh_grp
->priv
;
1702 struct mlxsw_sp_nexthop_group_cmp_arg
{
1703 enum mlxsw_sp_l3proto proto
;
1705 struct fib_info
*fi
;
1706 struct mlxsw_sp_fib6_entry
*fib6_entry
;
1711 mlxsw_sp_nexthop6_group_has_nexthop(const struct mlxsw_sp_nexthop_group
*nh_grp
,
1712 const struct in6_addr
*gw
, int ifindex
)
1716 for (i
= 0; i
< nh_grp
->count
; i
++) {
1717 const struct mlxsw_sp_nexthop
*nh
;
1719 nh
= &nh_grp
->nexthops
[i
];
1720 if (nh
->ifindex
== ifindex
&&
1721 ipv6_addr_equal(gw
, (struct in6_addr
*) nh
->gw_addr
))
1729 mlxsw_sp_nexthop6_group_cmp(const struct mlxsw_sp_nexthop_group
*nh_grp
,
1730 const struct mlxsw_sp_fib6_entry
*fib6_entry
)
1732 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
1734 if (nh_grp
->count
!= fib6_entry
->nrt6
)
1737 list_for_each_entry(mlxsw_sp_rt6
, &fib6_entry
->rt6_list
, list
) {
1738 struct in6_addr
*gw
;
1741 ifindex
= mlxsw_sp_rt6
->rt
->dst
.dev
->ifindex
;
1742 gw
= &mlxsw_sp_rt6
->rt
->rt6i_gateway
;
1743 if (!mlxsw_sp_nexthop6_group_has_nexthop(nh_grp
, gw
, ifindex
))
1751 mlxsw_sp_nexthop_group_cmp(struct rhashtable_compare_arg
*arg
, const void *ptr
)
1753 const struct mlxsw_sp_nexthop_group_cmp_arg
*cmp_arg
= arg
->key
;
1754 const struct mlxsw_sp_nexthop_group
*nh_grp
= ptr
;
1756 switch (cmp_arg
->proto
) {
1757 case MLXSW_SP_L3_PROTO_IPV4
:
1758 return cmp_arg
->fi
!= mlxsw_sp_nexthop4_group_fi(nh_grp
);
1759 case MLXSW_SP_L3_PROTO_IPV6
:
1760 return !mlxsw_sp_nexthop6_group_cmp(nh_grp
,
1761 cmp_arg
->fib6_entry
);
1769 mlxsw_sp_nexthop_group_type(const struct mlxsw_sp_nexthop_group
*nh_grp
)
1771 return nh_grp
->neigh_tbl
->family
;
1774 static u32
mlxsw_sp_nexthop_group_hash_obj(const void *data
, u32 len
, u32 seed
)
1776 const struct mlxsw_sp_nexthop_group
*nh_grp
= data
;
1777 const struct mlxsw_sp_nexthop
*nh
;
1778 struct fib_info
*fi
;
1782 switch (mlxsw_sp_nexthop_group_type(nh_grp
)) {
1784 fi
= mlxsw_sp_nexthop4_group_fi(nh_grp
);
1785 return jhash(&fi
, sizeof(fi
), seed
);
1787 val
= nh_grp
->count
;
1788 for (i
= 0; i
< nh_grp
->count
; i
++) {
1789 nh
= &nh_grp
->nexthops
[i
];
1792 return jhash(&val
, sizeof(val
), seed
);
1800 mlxsw_sp_nexthop6_group_hash(struct mlxsw_sp_fib6_entry
*fib6_entry
, u32 seed
)
1802 unsigned int val
= fib6_entry
->nrt6
;
1803 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
1804 struct net_device
*dev
;
1806 list_for_each_entry(mlxsw_sp_rt6
, &fib6_entry
->rt6_list
, list
) {
1807 dev
= mlxsw_sp_rt6
->rt
->dst
.dev
;
1808 val
^= dev
->ifindex
;
1811 return jhash(&val
, sizeof(val
), seed
);
1815 mlxsw_sp_nexthop_group_hash(const void *data
, u32 len
, u32 seed
)
1817 const struct mlxsw_sp_nexthop_group_cmp_arg
*cmp_arg
= data
;
1819 switch (cmp_arg
->proto
) {
1820 case MLXSW_SP_L3_PROTO_IPV4
:
1821 return jhash(&cmp_arg
->fi
, sizeof(cmp_arg
->fi
), seed
);
1822 case MLXSW_SP_L3_PROTO_IPV6
:
1823 return mlxsw_sp_nexthop6_group_hash(cmp_arg
->fib6_entry
, seed
);
1830 static const struct rhashtable_params mlxsw_sp_nexthop_group_ht_params
= {
1831 .head_offset
= offsetof(struct mlxsw_sp_nexthop_group
, ht_node
),
1832 .hashfn
= mlxsw_sp_nexthop_group_hash
,
1833 .obj_hashfn
= mlxsw_sp_nexthop_group_hash_obj
,
1834 .obj_cmpfn
= mlxsw_sp_nexthop_group_cmp
,
1837 static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp
*mlxsw_sp
,
1838 struct mlxsw_sp_nexthop_group
*nh_grp
)
1840 if (mlxsw_sp_nexthop_group_type(nh_grp
) == AF_INET6
&&
1844 return rhashtable_insert_fast(&mlxsw_sp
->router
->nexthop_group_ht
,
1846 mlxsw_sp_nexthop_group_ht_params
);
1849 static void mlxsw_sp_nexthop_group_remove(struct mlxsw_sp
*mlxsw_sp
,
1850 struct mlxsw_sp_nexthop_group
*nh_grp
)
1852 if (mlxsw_sp_nexthop_group_type(nh_grp
) == AF_INET6
&&
1856 rhashtable_remove_fast(&mlxsw_sp
->router
->nexthop_group_ht
,
1858 mlxsw_sp_nexthop_group_ht_params
);
1861 static struct mlxsw_sp_nexthop_group
*
1862 mlxsw_sp_nexthop4_group_lookup(struct mlxsw_sp
*mlxsw_sp
,
1863 struct fib_info
*fi
)
1865 struct mlxsw_sp_nexthop_group_cmp_arg cmp_arg
;
1867 cmp_arg
.proto
= MLXSW_SP_L3_PROTO_IPV4
;
1869 return rhashtable_lookup_fast(&mlxsw_sp
->router
->nexthop_group_ht
,
1871 mlxsw_sp_nexthop_group_ht_params
);
1874 static struct mlxsw_sp_nexthop_group
*
1875 mlxsw_sp_nexthop6_group_lookup(struct mlxsw_sp
*mlxsw_sp
,
1876 struct mlxsw_sp_fib6_entry
*fib6_entry
)
1878 struct mlxsw_sp_nexthop_group_cmp_arg cmp_arg
;
1880 cmp_arg
.proto
= MLXSW_SP_L3_PROTO_IPV6
;
1881 cmp_arg
.fib6_entry
= fib6_entry
;
1882 return rhashtable_lookup_fast(&mlxsw_sp
->router
->nexthop_group_ht
,
1884 mlxsw_sp_nexthop_group_ht_params
);
1887 static const struct rhashtable_params mlxsw_sp_nexthop_ht_params
= {
1888 .key_offset
= offsetof(struct mlxsw_sp_nexthop
, key
),
1889 .head_offset
= offsetof(struct mlxsw_sp_nexthop
, ht_node
),
1890 .key_len
= sizeof(struct mlxsw_sp_nexthop_key
),
1893 static int mlxsw_sp_nexthop_insert(struct mlxsw_sp
*mlxsw_sp
,
1894 struct mlxsw_sp_nexthop
*nh
)
1896 return rhashtable_insert_fast(&mlxsw_sp
->router
->nexthop_ht
,
1897 &nh
->ht_node
, mlxsw_sp_nexthop_ht_params
);
1900 static void mlxsw_sp_nexthop_remove(struct mlxsw_sp
*mlxsw_sp
,
1901 struct mlxsw_sp_nexthop
*nh
)
1903 rhashtable_remove_fast(&mlxsw_sp
->router
->nexthop_ht
, &nh
->ht_node
,
1904 mlxsw_sp_nexthop_ht_params
);
1907 static struct mlxsw_sp_nexthop
*
1908 mlxsw_sp_nexthop_lookup(struct mlxsw_sp
*mlxsw_sp
,
1909 struct mlxsw_sp_nexthop_key key
)
1911 return rhashtable_lookup_fast(&mlxsw_sp
->router
->nexthop_ht
, &key
,
1912 mlxsw_sp_nexthop_ht_params
);
1915 static int mlxsw_sp_adj_index_mass_update_vr(struct mlxsw_sp
*mlxsw_sp
,
1916 const struct mlxsw_sp_fib
*fib
,
1917 u32 adj_index
, u16 ecmp_size
,
1921 char raleu_pl
[MLXSW_REG_RALEU_LEN
];
1923 mlxsw_reg_raleu_pack(raleu_pl
,
1924 (enum mlxsw_reg_ralxx_protocol
) fib
->proto
,
1925 fib
->vr
->id
, adj_index
, ecmp_size
, new_adj_index
,
1927 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(raleu
), raleu_pl
);
1930 static int mlxsw_sp_adj_index_mass_update(struct mlxsw_sp
*mlxsw_sp
,
1931 struct mlxsw_sp_nexthop_group
*nh_grp
,
1932 u32 old_adj_index
, u16 old_ecmp_size
)
1934 struct mlxsw_sp_fib_entry
*fib_entry
;
1935 struct mlxsw_sp_fib
*fib
= NULL
;
1938 list_for_each_entry(fib_entry
, &nh_grp
->fib_list
, nexthop_group_node
) {
1939 if (fib
== fib_entry
->fib_node
->fib
)
1941 fib
= fib_entry
->fib_node
->fib
;
1942 err
= mlxsw_sp_adj_index_mass_update_vr(mlxsw_sp
, fib
,
1953 static int mlxsw_sp_nexthop_mac_update(struct mlxsw_sp
*mlxsw_sp
, u32 adj_index
,
1954 struct mlxsw_sp_nexthop
*nh
)
1956 struct mlxsw_sp_neigh_entry
*neigh_entry
= nh
->neigh_entry
;
1957 char ratr_pl
[MLXSW_REG_RATR_LEN
];
1959 mlxsw_reg_ratr_pack(ratr_pl
, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY
,
1960 true, MLXSW_REG_RATR_TYPE_ETHERNET
,
1961 adj_index
, neigh_entry
->rif
);
1962 mlxsw_reg_ratr_eth_entry_pack(ratr_pl
, neigh_entry
->ha
);
1963 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ratr
), ratr_pl
);
1967 mlxsw_sp_nexthop_group_mac_update(struct mlxsw_sp
*mlxsw_sp
,
1968 struct mlxsw_sp_nexthop_group
*nh_grp
,
1971 u32 adj_index
= nh_grp
->adj_index
; /* base */
1972 struct mlxsw_sp_nexthop
*nh
;
1976 for (i
= 0; i
< nh_grp
->count
; i
++) {
1977 nh
= &nh_grp
->nexthops
[i
];
1979 if (!nh
->should_offload
) {
1984 if (nh
->update
|| reallocate
) {
1985 err
= mlxsw_sp_nexthop_mac_update(mlxsw_sp
,
1997 static int mlxsw_sp_fib_entry_update(struct mlxsw_sp
*mlxsw_sp
,
1998 struct mlxsw_sp_fib_entry
*fib_entry
);
2001 mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node
*fib_node
,
2002 const struct mlxsw_sp_fib_entry
*fib_entry
);
2005 mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp
*mlxsw_sp
,
2006 struct mlxsw_sp_nexthop_group
*nh_grp
)
2008 struct mlxsw_sp_fib_entry
*fib_entry
;
2011 list_for_each_entry(fib_entry
, &nh_grp
->fib_list
, nexthop_group_node
) {
2012 if (!mlxsw_sp_fib_node_entry_is_first(fib_entry
->fib_node
,
2015 err
= mlxsw_sp_fib_entry_update(mlxsw_sp
, fib_entry
);
2023 mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry
*fib_entry
,
2024 enum mlxsw_reg_ralue_op op
, int err
);
2027 mlxsw_sp_nexthop_fib_entries_refresh(struct mlxsw_sp_nexthop_group
*nh_grp
)
2029 enum mlxsw_reg_ralue_op op
= MLXSW_REG_RALUE_OP_WRITE_WRITE
;
2030 struct mlxsw_sp_fib_entry
*fib_entry
;
2032 list_for_each_entry(fib_entry
, &nh_grp
->fib_list
, nexthop_group_node
) {
2033 if (!mlxsw_sp_fib_node_entry_is_first(fib_entry
->fib_node
,
2036 mlxsw_sp_fib_entry_offload_refresh(fib_entry
, op
, 0);
2041 mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp
*mlxsw_sp
,
2042 struct mlxsw_sp_nexthop_group
*nh_grp
)
2044 struct mlxsw_sp_nexthop
*nh
;
2045 bool offload_change
= false;
2048 bool old_adj_index_valid
;
2054 if (!nh_grp
->gateway
) {
2055 mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp
, nh_grp
);
2059 for (i
= 0; i
< nh_grp
->count
; i
++) {
2060 nh
= &nh_grp
->nexthops
[i
];
2062 if (nh
->should_offload
!= nh
->offloaded
) {
2063 offload_change
= true;
2064 if (nh
->should_offload
)
2067 if (nh
->should_offload
)
2070 if (!offload_change
) {
2071 /* Nothing was added or removed, so no need to reallocate. Just
2072 * update MAC on existing adjacency indexes.
2074 err
= mlxsw_sp_nexthop_group_mac_update(mlxsw_sp
, nh_grp
,
2077 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to update neigh MAC in adjacency table.\n");
2083 /* No neigh of this group is connected so we just set
2084 * the trap and let everthing flow through kernel.
2088 err
= mlxsw_sp_kvdl_alloc(mlxsw_sp
, ecmp_size
, &adj_index
);
2090 /* We ran out of KVD linear space, just set the
2091 * trap and let everything flow through kernel.
2093 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to allocate KVD linear area for nexthop group.\n");
2096 old_adj_index_valid
= nh_grp
->adj_index_valid
;
2097 old_adj_index
= nh_grp
->adj_index
;
2098 old_ecmp_size
= nh_grp
->ecmp_size
;
2099 nh_grp
->adj_index_valid
= 1;
2100 nh_grp
->adj_index
= adj_index
;
2101 nh_grp
->ecmp_size
= ecmp_size
;
2102 err
= mlxsw_sp_nexthop_group_mac_update(mlxsw_sp
, nh_grp
, true);
2104 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to update neigh MAC in adjacency table.\n");
2108 if (!old_adj_index_valid
) {
2109 /* The trap was set for fib entries, so we have to call
2110 * fib entry update to unset it and use adjacency index.
2112 err
= mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp
, nh_grp
);
2114 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to add adjacency index to fib entries.\n");
2120 err
= mlxsw_sp_adj_index_mass_update(mlxsw_sp
, nh_grp
,
2121 old_adj_index
, old_ecmp_size
);
2122 mlxsw_sp_kvdl_free(mlxsw_sp
, old_adj_index
);
2124 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to mass-update adjacency index for nexthop group.\n");
2128 /* Offload state within the group changed, so update the flags. */
2129 mlxsw_sp_nexthop_fib_entries_refresh(nh_grp
);
2134 old_adj_index_valid
= nh_grp
->adj_index_valid
;
2135 nh_grp
->adj_index_valid
= 0;
2136 for (i
= 0; i
< nh_grp
->count
; i
++) {
2137 nh
= &nh_grp
->nexthops
[i
];
2140 err
= mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp
, nh_grp
);
2142 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to set traps for fib entries.\n");
2143 if (old_adj_index_valid
)
2144 mlxsw_sp_kvdl_free(mlxsw_sp
, nh_grp
->adj_index
);
2147 static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop
*nh
,
2151 nh
->should_offload
= 1;
2152 else if (nh
->offloaded
)
2153 nh
->should_offload
= 0;
2158 mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp
*mlxsw_sp
,
2159 struct mlxsw_sp_neigh_entry
*neigh_entry
,
2162 struct mlxsw_sp_nexthop
*nh
;
2164 list_for_each_entry(nh
, &neigh_entry
->nexthop_list
,
2166 __mlxsw_sp_nexthop_neigh_update(nh
, removing
);
2167 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh
->nh_grp
);
2171 static void mlxsw_sp_nexthop_rif_init(struct mlxsw_sp_nexthop
*nh
,
2172 struct mlxsw_sp_rif
*rif
)
2178 list_add(&nh
->rif_list_node
, &rif
->nexthop_list
);
2181 static void mlxsw_sp_nexthop_rif_fini(struct mlxsw_sp_nexthop
*nh
)
2186 list_del(&nh
->rif_list_node
);
2190 static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp
*mlxsw_sp
,
2191 struct mlxsw_sp_nexthop
*nh
)
2193 struct mlxsw_sp_neigh_entry
*neigh_entry
;
2194 struct neighbour
*n
;
2198 if (!nh
->nh_grp
->gateway
|| nh
->neigh_entry
)
2201 /* Take a reference of neigh here ensuring that neigh would
2202 * not be destructed before the nexthop entry is finished.
2203 * The reference is taken either in neigh_lookup() or
2204 * in neigh_create() in case n is not found.
2206 n
= neigh_lookup(nh
->nh_grp
->neigh_tbl
, &nh
->gw_addr
, nh
->rif
->dev
);
2208 n
= neigh_create(nh
->nh_grp
->neigh_tbl
, &nh
->gw_addr
,
2212 neigh_event_send(n
, NULL
);
2214 neigh_entry
= mlxsw_sp_neigh_entry_lookup(mlxsw_sp
, n
);
2216 neigh_entry
= mlxsw_sp_neigh_entry_create(mlxsw_sp
, n
);
2217 if (IS_ERR(neigh_entry
)) {
2219 goto err_neigh_entry_create
;
2223 /* If that is the first nexthop connected to that neigh, add to
2224 * nexthop_neighs_list
2226 if (list_empty(&neigh_entry
->nexthop_list
))
2227 list_add_tail(&neigh_entry
->nexthop_neighs_list_node
,
2228 &mlxsw_sp
->router
->nexthop_neighs_list
);
2230 nh
->neigh_entry
= neigh_entry
;
2231 list_add_tail(&nh
->neigh_list_node
, &neigh_entry
->nexthop_list
);
2232 read_lock_bh(&n
->lock
);
2233 nud_state
= n
->nud_state
;
2235 read_unlock_bh(&n
->lock
);
2236 __mlxsw_sp_nexthop_neigh_update(nh
, !(nud_state
& NUD_VALID
&& !dead
));
2240 err_neigh_entry_create
:
2245 static void mlxsw_sp_nexthop_neigh_fini(struct mlxsw_sp
*mlxsw_sp
,
2246 struct mlxsw_sp_nexthop
*nh
)
2248 struct mlxsw_sp_neigh_entry
*neigh_entry
= nh
->neigh_entry
;
2249 struct neighbour
*n
;
2253 n
= neigh_entry
->key
.n
;
2255 __mlxsw_sp_nexthop_neigh_update(nh
, true);
2256 list_del(&nh
->neigh_list_node
);
2257 nh
->neigh_entry
= NULL
;
2259 /* If that is the last nexthop connected to that neigh, remove from
2260 * nexthop_neighs_list
2262 if (list_empty(&neigh_entry
->nexthop_list
))
2263 list_del(&neigh_entry
->nexthop_neighs_list_node
);
2265 if (!neigh_entry
->connected
&& list_empty(&neigh_entry
->nexthop_list
))
2266 mlxsw_sp_neigh_entry_destroy(mlxsw_sp
, neigh_entry
);
2271 static bool mlxsw_sp_netdev_ipip_type(const struct mlxsw_sp
*mlxsw_sp
,
2272 const struct net_device
*dev
,
2273 enum mlxsw_sp_ipip_type
*p_type
)
2275 struct mlxsw_sp_router
*router
= mlxsw_sp
->router
;
2276 const struct mlxsw_sp_ipip_ops
*ipip_ops
;
2277 enum mlxsw_sp_ipip_type ipipt
;
2279 for (ipipt
= 0; ipipt
< MLXSW_SP_IPIP_TYPE_MAX
; ++ipipt
) {
2280 ipip_ops
= router
->ipip_ops_arr
[ipipt
];
2281 if (dev
->type
== ipip_ops
->dev_type
) {
2290 static int mlxsw_sp_nexthop4_init(struct mlxsw_sp
*mlxsw_sp
,
2291 struct mlxsw_sp_nexthop_group
*nh_grp
,
2292 struct mlxsw_sp_nexthop
*nh
,
2293 struct fib_nh
*fib_nh
)
2295 struct net_device
*dev
= fib_nh
->nh_dev
;
2296 struct in_device
*in_dev
;
2297 struct mlxsw_sp_rif
*rif
;
2300 nh
->nh_grp
= nh_grp
;
2301 nh
->key
.fib_nh
= fib_nh
;
2302 memcpy(&nh
->gw_addr
, &fib_nh
->nh_gw
, sizeof(fib_nh
->nh_gw
));
2303 err
= mlxsw_sp_nexthop_insert(mlxsw_sp
, nh
);
2310 in_dev
= __in_dev_get_rtnl(dev
);
2311 if (in_dev
&& IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev
) &&
2312 fib_nh
->nh_flags
& RTNH_F_LINKDOWN
)
2315 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, dev
);
2318 mlxsw_sp_nexthop_rif_init(nh
, rif
);
2320 err
= mlxsw_sp_nexthop_neigh_init(mlxsw_sp
, nh
);
2322 goto err_nexthop_neigh_init
;
2326 err_nexthop_neigh_init
:
2327 mlxsw_sp_nexthop_rif_fini(nh
);
2328 mlxsw_sp_nexthop_remove(mlxsw_sp
, nh
);
2332 static void mlxsw_sp_nexthop4_fini(struct mlxsw_sp
*mlxsw_sp
,
2333 struct mlxsw_sp_nexthop
*nh
)
2335 mlxsw_sp_nexthop_neigh_fini(mlxsw_sp
, nh
);
2336 mlxsw_sp_nexthop_rif_fini(nh
);
2337 mlxsw_sp_nexthop_remove(mlxsw_sp
, nh
);
2340 static void mlxsw_sp_nexthop4_event(struct mlxsw_sp
*mlxsw_sp
,
2341 unsigned long event
, struct fib_nh
*fib_nh
)
2343 struct mlxsw_sp_nexthop_key key
;
2344 struct mlxsw_sp_nexthop
*nh
;
2345 struct mlxsw_sp_rif
*rif
;
2347 if (mlxsw_sp
->router
->aborted
)
2350 key
.fib_nh
= fib_nh
;
2351 nh
= mlxsw_sp_nexthop_lookup(mlxsw_sp
, key
);
2352 if (WARN_ON_ONCE(!nh
))
2355 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, fib_nh
->nh_dev
);
2360 case FIB_EVENT_NH_ADD
:
2361 mlxsw_sp_nexthop_rif_init(nh
, rif
);
2362 mlxsw_sp_nexthop_neigh_init(mlxsw_sp
, nh
);
2364 case FIB_EVENT_NH_DEL
:
2365 mlxsw_sp_nexthop_neigh_fini(mlxsw_sp
, nh
);
2366 mlxsw_sp_nexthop_rif_fini(nh
);
2370 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh
->nh_grp
);
2373 static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp
*mlxsw_sp
,
2374 struct mlxsw_sp_rif
*rif
)
2376 struct mlxsw_sp_nexthop
*nh
, *tmp
;
2378 list_for_each_entry_safe(nh
, tmp
, &rif
->nexthop_list
, rif_list_node
) {
2379 mlxsw_sp_nexthop_neigh_fini(mlxsw_sp
, nh
);
2380 mlxsw_sp_nexthop_rif_fini(nh
);
2381 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh
->nh_grp
);
2385 static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp
*mlxsw_sp
,
2386 const struct fib_info
*fi
)
2388 return fi
->fib_nh
->nh_scope
== RT_SCOPE_LINK
;
2391 static struct mlxsw_sp_nexthop_group
*
2392 mlxsw_sp_nexthop4_group_create(struct mlxsw_sp
*mlxsw_sp
, struct fib_info
*fi
)
2394 struct mlxsw_sp_nexthop_group
*nh_grp
;
2395 struct mlxsw_sp_nexthop
*nh
;
2396 struct fib_nh
*fib_nh
;
2401 alloc_size
= sizeof(*nh_grp
) +
2402 fi
->fib_nhs
* sizeof(struct mlxsw_sp_nexthop
);
2403 nh_grp
= kzalloc(alloc_size
, GFP_KERNEL
);
2405 return ERR_PTR(-ENOMEM
);
2407 INIT_LIST_HEAD(&nh_grp
->fib_list
);
2408 nh_grp
->neigh_tbl
= &arp_tbl
;
2410 nh_grp
->gateway
= mlxsw_sp_fi_is_gateway(mlxsw_sp
, fi
);
2411 nh_grp
->count
= fi
->fib_nhs
;
2413 for (i
= 0; i
< nh_grp
->count
; i
++) {
2414 nh
= &nh_grp
->nexthops
[i
];
2415 fib_nh
= &fi
->fib_nh
[i
];
2416 err
= mlxsw_sp_nexthop4_init(mlxsw_sp
, nh_grp
, nh
, fib_nh
);
2418 goto err_nexthop4_init
;
2420 err
= mlxsw_sp_nexthop_group_insert(mlxsw_sp
, nh_grp
);
2422 goto err_nexthop_group_insert
;
2423 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh_grp
);
2426 err_nexthop_group_insert
:
2428 for (i
--; i
>= 0; i
--) {
2429 nh
= &nh_grp
->nexthops
[i
];
2430 mlxsw_sp_nexthop4_fini(mlxsw_sp
, nh
);
2434 return ERR_PTR(err
);
2438 mlxsw_sp_nexthop4_group_destroy(struct mlxsw_sp
*mlxsw_sp
,
2439 struct mlxsw_sp_nexthop_group
*nh_grp
)
2441 struct mlxsw_sp_nexthop
*nh
;
2444 mlxsw_sp_nexthop_group_remove(mlxsw_sp
, nh_grp
);
2445 for (i
= 0; i
< nh_grp
->count
; i
++) {
2446 nh
= &nh_grp
->nexthops
[i
];
2447 mlxsw_sp_nexthop4_fini(mlxsw_sp
, nh
);
2449 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh_grp
);
2450 WARN_ON_ONCE(nh_grp
->adj_index_valid
);
2451 fib_info_put(mlxsw_sp_nexthop4_group_fi(nh_grp
));
2455 static int mlxsw_sp_nexthop4_group_get(struct mlxsw_sp
*mlxsw_sp
,
2456 struct mlxsw_sp_fib_entry
*fib_entry
,
2457 struct fib_info
*fi
)
2459 struct mlxsw_sp_nexthop_group
*nh_grp
;
2461 nh_grp
= mlxsw_sp_nexthop4_group_lookup(mlxsw_sp
, fi
);
2463 nh_grp
= mlxsw_sp_nexthop4_group_create(mlxsw_sp
, fi
);
2465 return PTR_ERR(nh_grp
);
2467 list_add_tail(&fib_entry
->nexthop_group_node
, &nh_grp
->fib_list
);
2468 fib_entry
->nh_group
= nh_grp
;
2472 static void mlxsw_sp_nexthop4_group_put(struct mlxsw_sp
*mlxsw_sp
,
2473 struct mlxsw_sp_fib_entry
*fib_entry
)
2475 struct mlxsw_sp_nexthop_group
*nh_grp
= fib_entry
->nh_group
;
2477 list_del(&fib_entry
->nexthop_group_node
);
2478 if (!list_empty(&nh_grp
->fib_list
))
2480 mlxsw_sp_nexthop4_group_destroy(mlxsw_sp
, nh_grp
);
2484 mlxsw_sp_fib4_entry_should_offload(const struct mlxsw_sp_fib_entry
*fib_entry
)
2486 struct mlxsw_sp_fib4_entry
*fib4_entry
;
2488 fib4_entry
= container_of(fib_entry
, struct mlxsw_sp_fib4_entry
,
2490 return !fib4_entry
->tos
;
2494 mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry
*fib_entry
)
2496 struct mlxsw_sp_nexthop_group
*nh_group
= fib_entry
->nh_group
;
2498 switch (fib_entry
->fib_node
->fib
->proto
) {
2499 case MLXSW_SP_L3_PROTO_IPV4
:
2500 if (!mlxsw_sp_fib4_entry_should_offload(fib_entry
))
2503 case MLXSW_SP_L3_PROTO_IPV6
:
2507 switch (fib_entry
->type
) {
2508 case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE
:
2509 return !!nh_group
->adj_index_valid
;
2510 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
:
2511 return !!nh_group
->nh_rif
;
2517 static struct mlxsw_sp_nexthop
*
2518 mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group
*nh_grp
,
2519 const struct mlxsw_sp_rt6
*mlxsw_sp_rt6
)
2523 for (i
= 0; i
< nh_grp
->count
; i
++) {
2524 struct mlxsw_sp_nexthop
*nh
= &nh_grp
->nexthops
[i
];
2525 struct rt6_info
*rt
= mlxsw_sp_rt6
->rt
;
2527 if (nh
->rif
&& nh
->rif
->dev
== rt
->dst
.dev
&&
2528 ipv6_addr_equal((const struct in6_addr
*) &nh
->gw_addr
,
2538 mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry
*fib_entry
)
2540 struct mlxsw_sp_nexthop_group
*nh_grp
= fib_entry
->nh_group
;
2543 if (fib_entry
->type
== MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
) {
2544 nh_grp
->nexthops
->key
.fib_nh
->nh_flags
|= RTNH_F_OFFLOAD
;
2548 for (i
= 0; i
< nh_grp
->count
; i
++) {
2549 struct mlxsw_sp_nexthop
*nh
= &nh_grp
->nexthops
[i
];
2552 nh
->key
.fib_nh
->nh_flags
|= RTNH_F_OFFLOAD
;
2554 nh
->key
.fib_nh
->nh_flags
&= ~RTNH_F_OFFLOAD
;
2559 mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry
*fib_entry
)
2561 struct mlxsw_sp_nexthop_group
*nh_grp
= fib_entry
->nh_group
;
2564 for (i
= 0; i
< nh_grp
->count
; i
++) {
2565 struct mlxsw_sp_nexthop
*nh
= &nh_grp
->nexthops
[i
];
2567 nh
->key
.fib_nh
->nh_flags
&= ~RTNH_F_OFFLOAD
;
2572 mlxsw_sp_fib6_entry_offload_set(struct mlxsw_sp_fib_entry
*fib_entry
)
2574 struct mlxsw_sp_fib6_entry
*fib6_entry
;
2575 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
2577 fib6_entry
= container_of(fib_entry
, struct mlxsw_sp_fib6_entry
,
2580 if (fib_entry
->type
== MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
) {
2581 list_first_entry(&fib6_entry
->rt6_list
, struct mlxsw_sp_rt6
,
2582 list
)->rt
->rt6i_nh_flags
|= RTNH_F_OFFLOAD
;
2586 list_for_each_entry(mlxsw_sp_rt6
, &fib6_entry
->rt6_list
, list
) {
2587 struct mlxsw_sp_nexthop_group
*nh_grp
= fib_entry
->nh_group
;
2588 struct mlxsw_sp_nexthop
*nh
;
2590 nh
= mlxsw_sp_rt6_nexthop(nh_grp
, mlxsw_sp_rt6
);
2591 if (nh
&& nh
->offloaded
)
2592 mlxsw_sp_rt6
->rt
->rt6i_nh_flags
|= RTNH_F_OFFLOAD
;
2594 mlxsw_sp_rt6
->rt
->rt6i_nh_flags
&= ~RTNH_F_OFFLOAD
;
2599 mlxsw_sp_fib6_entry_offload_unset(struct mlxsw_sp_fib_entry
*fib_entry
)
2601 struct mlxsw_sp_fib6_entry
*fib6_entry
;
2602 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
2604 fib6_entry
= container_of(fib_entry
, struct mlxsw_sp_fib6_entry
,
2606 list_for_each_entry(mlxsw_sp_rt6
, &fib6_entry
->rt6_list
, list
) {
2607 struct rt6_info
*rt
= mlxsw_sp_rt6
->rt
;
2609 rt
->rt6i_nh_flags
&= ~RTNH_F_OFFLOAD
;
2613 static void mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry
*fib_entry
)
2615 switch (fib_entry
->fib_node
->fib
->proto
) {
2616 case MLXSW_SP_L3_PROTO_IPV4
:
2617 mlxsw_sp_fib4_entry_offload_set(fib_entry
);
2619 case MLXSW_SP_L3_PROTO_IPV6
:
2620 mlxsw_sp_fib6_entry_offload_set(fib_entry
);
2626 mlxsw_sp_fib_entry_offload_unset(struct mlxsw_sp_fib_entry
*fib_entry
)
2628 switch (fib_entry
->fib_node
->fib
->proto
) {
2629 case MLXSW_SP_L3_PROTO_IPV4
:
2630 mlxsw_sp_fib4_entry_offload_unset(fib_entry
);
2632 case MLXSW_SP_L3_PROTO_IPV6
:
2633 mlxsw_sp_fib6_entry_offload_unset(fib_entry
);
2639 mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry
*fib_entry
,
2640 enum mlxsw_reg_ralue_op op
, int err
)
2643 case MLXSW_REG_RALUE_OP_WRITE_DELETE
:
2644 return mlxsw_sp_fib_entry_offload_unset(fib_entry
);
2645 case MLXSW_REG_RALUE_OP_WRITE_WRITE
:
2648 if (mlxsw_sp_fib_entry_should_offload(fib_entry
))
2649 mlxsw_sp_fib_entry_offload_set(fib_entry
);
2650 else if (!mlxsw_sp_fib_entry_should_offload(fib_entry
))
2651 mlxsw_sp_fib_entry_offload_unset(fib_entry
);
2659 mlxsw_sp_fib_entry_ralue_pack(char *ralue_pl
,
2660 const struct mlxsw_sp_fib_entry
*fib_entry
,
2661 enum mlxsw_reg_ralue_op op
)
2663 struct mlxsw_sp_fib
*fib
= fib_entry
->fib_node
->fib
;
2664 enum mlxsw_reg_ralxx_protocol proto
;
2667 proto
= (enum mlxsw_reg_ralxx_protocol
) fib
->proto
;
2669 switch (fib
->proto
) {
2670 case MLXSW_SP_L3_PROTO_IPV4
:
2671 p_dip
= (u32
*) fib_entry
->fib_node
->key
.addr
;
2672 mlxsw_reg_ralue_pack4(ralue_pl
, proto
, op
, fib
->vr
->id
,
2673 fib_entry
->fib_node
->key
.prefix_len
,
2676 case MLXSW_SP_L3_PROTO_IPV6
:
2677 mlxsw_reg_ralue_pack6(ralue_pl
, proto
, op
, fib
->vr
->id
,
2678 fib_entry
->fib_node
->key
.prefix_len
,
2679 fib_entry
->fib_node
->key
.addr
);
2684 static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp
*mlxsw_sp
,
2685 struct mlxsw_sp_fib_entry
*fib_entry
,
2686 enum mlxsw_reg_ralue_op op
)
2688 char ralue_pl
[MLXSW_REG_RALUE_LEN
];
2689 enum mlxsw_reg_ralue_trap_action trap_action
;
2691 u32 adjacency_index
= 0;
2694 /* In case the nexthop group adjacency index is valid, use it
2695 * with provided ECMP size. Otherwise, setup trap and pass
2696 * traffic to kernel.
2698 if (mlxsw_sp_fib_entry_should_offload(fib_entry
)) {
2699 trap_action
= MLXSW_REG_RALUE_TRAP_ACTION_NOP
;
2700 adjacency_index
= fib_entry
->nh_group
->adj_index
;
2701 ecmp_size
= fib_entry
->nh_group
->ecmp_size
;
2703 trap_action
= MLXSW_REG_RALUE_TRAP_ACTION_TRAP
;
2704 trap_id
= MLXSW_TRAP_ID_RTR_INGRESS0
;
2707 mlxsw_sp_fib_entry_ralue_pack(ralue_pl
, fib_entry
, op
);
2708 mlxsw_reg_ralue_act_remote_pack(ralue_pl
, trap_action
, trap_id
,
2709 adjacency_index
, ecmp_size
);
2710 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralue
), ralue_pl
);
2713 static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp
*mlxsw_sp
,
2714 struct mlxsw_sp_fib_entry
*fib_entry
,
2715 enum mlxsw_reg_ralue_op op
)
2717 struct mlxsw_sp_rif
*rif
= fib_entry
->nh_group
->nh_rif
;
2718 enum mlxsw_reg_ralue_trap_action trap_action
;
2719 char ralue_pl
[MLXSW_REG_RALUE_LEN
];
2723 if (mlxsw_sp_fib_entry_should_offload(fib_entry
)) {
2724 trap_action
= MLXSW_REG_RALUE_TRAP_ACTION_NOP
;
2725 rif_index
= rif
->rif_index
;
2727 trap_action
= MLXSW_REG_RALUE_TRAP_ACTION_TRAP
;
2728 trap_id
= MLXSW_TRAP_ID_RTR_INGRESS0
;
2731 mlxsw_sp_fib_entry_ralue_pack(ralue_pl
, fib_entry
, op
);
2732 mlxsw_reg_ralue_act_local_pack(ralue_pl
, trap_action
, trap_id
,
2734 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralue
), ralue_pl
);
2737 static int mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp
*mlxsw_sp
,
2738 struct mlxsw_sp_fib_entry
*fib_entry
,
2739 enum mlxsw_reg_ralue_op op
)
2741 char ralue_pl
[MLXSW_REG_RALUE_LEN
];
2743 mlxsw_sp_fib_entry_ralue_pack(ralue_pl
, fib_entry
, op
);
2744 mlxsw_reg_ralue_act_ip2me_pack(ralue_pl
);
2745 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralue
), ralue_pl
);
2748 static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp
*mlxsw_sp
,
2749 struct mlxsw_sp_fib_entry
*fib_entry
,
2750 enum mlxsw_reg_ralue_op op
)
2752 switch (fib_entry
->type
) {
2753 case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE
:
2754 return mlxsw_sp_fib_entry_op_remote(mlxsw_sp
, fib_entry
, op
);
2755 case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
:
2756 return mlxsw_sp_fib_entry_op_local(mlxsw_sp
, fib_entry
, op
);
2757 case MLXSW_SP_FIB_ENTRY_TYPE_TRAP
:
2758 return mlxsw_sp_fib_entry_op_trap(mlxsw_sp
, fib_entry
, op
);
2763 static int mlxsw_sp_fib_entry_op(struct mlxsw_sp
*mlxsw_sp
,
2764 struct mlxsw_sp_fib_entry
*fib_entry
,
2765 enum mlxsw_reg_ralue_op op
)
2767 int err
= __mlxsw_sp_fib_entry_op(mlxsw_sp
, fib_entry
, op
);
2769 mlxsw_sp_fib_entry_offload_refresh(fib_entry
, op
, err
);
2774 static int mlxsw_sp_fib_entry_update(struct mlxsw_sp
*mlxsw_sp
,
2775 struct mlxsw_sp_fib_entry
*fib_entry
)
2777 return mlxsw_sp_fib_entry_op(mlxsw_sp
, fib_entry
,
2778 MLXSW_REG_RALUE_OP_WRITE_WRITE
);
2781 static int mlxsw_sp_fib_entry_del(struct mlxsw_sp
*mlxsw_sp
,
2782 struct mlxsw_sp_fib_entry
*fib_entry
)
2784 return mlxsw_sp_fib_entry_op(mlxsw_sp
, fib_entry
,
2785 MLXSW_REG_RALUE_OP_WRITE_DELETE
);
2789 mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp
*mlxsw_sp
,
2790 const struct fib_entry_notifier_info
*fen_info
,
2791 struct mlxsw_sp_fib_entry
*fib_entry
)
2793 struct fib_info
*fi
= fen_info
->fi
;
2795 switch (fen_info
->type
) {
2796 case RTN_BROADCAST
: /* fall through */
2798 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_TRAP
;
2800 case RTN_UNREACHABLE
: /* fall through */
2801 case RTN_BLACKHOLE
: /* fall through */
2803 /* Packets hitting these routes need to be trapped, but
2804 * can do so with a lower priority than packets directed
2805 * at the host, so use action type local instead of trap.
2807 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
;
2810 if (mlxsw_sp_fi_is_gateway(mlxsw_sp
, fi
))
2811 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_REMOTE
;
2813 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
;
2820 static struct mlxsw_sp_fib4_entry
*
2821 mlxsw_sp_fib4_entry_create(struct mlxsw_sp
*mlxsw_sp
,
2822 struct mlxsw_sp_fib_node
*fib_node
,
2823 const struct fib_entry_notifier_info
*fen_info
)
2825 struct mlxsw_sp_fib4_entry
*fib4_entry
;
2826 struct mlxsw_sp_fib_entry
*fib_entry
;
2829 fib4_entry
= kzalloc(sizeof(*fib4_entry
), GFP_KERNEL
);
2831 return ERR_PTR(-ENOMEM
);
2832 fib_entry
= &fib4_entry
->common
;
2834 err
= mlxsw_sp_fib4_entry_type_set(mlxsw_sp
, fen_info
, fib_entry
);
2836 goto err_fib4_entry_type_set
;
2838 err
= mlxsw_sp_nexthop4_group_get(mlxsw_sp
, fib_entry
, fen_info
->fi
);
2840 goto err_nexthop4_group_get
;
2842 fib4_entry
->prio
= fen_info
->fi
->fib_priority
;
2843 fib4_entry
->tb_id
= fen_info
->tb_id
;
2844 fib4_entry
->type
= fen_info
->type
;
2845 fib4_entry
->tos
= fen_info
->tos
;
2847 fib_entry
->fib_node
= fib_node
;
2851 err_nexthop4_group_get
:
2852 err_fib4_entry_type_set
:
2854 return ERR_PTR(err
);
2857 static void mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp
*mlxsw_sp
,
2858 struct mlxsw_sp_fib4_entry
*fib4_entry
)
2860 mlxsw_sp_nexthop4_group_put(mlxsw_sp
, &fib4_entry
->common
);
2864 static struct mlxsw_sp_fib_node
*
2865 mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib
*fib
, const void *addr
,
2866 size_t addr_len
, unsigned char prefix_len
);
2868 static struct mlxsw_sp_fib4_entry
*
2869 mlxsw_sp_fib4_entry_lookup(struct mlxsw_sp
*mlxsw_sp
,
2870 const struct fib_entry_notifier_info
*fen_info
)
2872 struct mlxsw_sp_fib4_entry
*fib4_entry
;
2873 struct mlxsw_sp_fib_node
*fib_node
;
2874 struct mlxsw_sp_fib
*fib
;
2875 struct mlxsw_sp_vr
*vr
;
2877 vr
= mlxsw_sp_vr_find(mlxsw_sp
, fen_info
->tb_id
);
2880 fib
= mlxsw_sp_vr_fib(vr
, MLXSW_SP_L3_PROTO_IPV4
);
2882 fib_node
= mlxsw_sp_fib_node_lookup(fib
, &fen_info
->dst
,
2883 sizeof(fen_info
->dst
),
2888 list_for_each_entry(fib4_entry
, &fib_node
->entry_list
, common
.list
) {
2889 if (fib4_entry
->tb_id
== fen_info
->tb_id
&&
2890 fib4_entry
->tos
== fen_info
->tos
&&
2891 fib4_entry
->type
== fen_info
->type
&&
2892 mlxsw_sp_nexthop4_group_fi(fib4_entry
->common
.nh_group
) ==
2901 static const struct rhashtable_params mlxsw_sp_fib_ht_params
= {
2902 .key_offset
= offsetof(struct mlxsw_sp_fib_node
, key
),
2903 .head_offset
= offsetof(struct mlxsw_sp_fib_node
, ht_node
),
2904 .key_len
= sizeof(struct mlxsw_sp_fib_key
),
2905 .automatic_shrinking
= true,
2908 static int mlxsw_sp_fib_node_insert(struct mlxsw_sp_fib
*fib
,
2909 struct mlxsw_sp_fib_node
*fib_node
)
2911 return rhashtable_insert_fast(&fib
->ht
, &fib_node
->ht_node
,
2912 mlxsw_sp_fib_ht_params
);
2915 static void mlxsw_sp_fib_node_remove(struct mlxsw_sp_fib
*fib
,
2916 struct mlxsw_sp_fib_node
*fib_node
)
2918 rhashtable_remove_fast(&fib
->ht
, &fib_node
->ht_node
,
2919 mlxsw_sp_fib_ht_params
);
2922 static struct mlxsw_sp_fib_node
*
2923 mlxsw_sp_fib_node_lookup(struct mlxsw_sp_fib
*fib
, const void *addr
,
2924 size_t addr_len
, unsigned char prefix_len
)
2926 struct mlxsw_sp_fib_key key
;
2928 memset(&key
, 0, sizeof(key
));
2929 memcpy(key
.addr
, addr
, addr_len
);
2930 key
.prefix_len
= prefix_len
;
2931 return rhashtable_lookup_fast(&fib
->ht
, &key
, mlxsw_sp_fib_ht_params
);
2934 static struct mlxsw_sp_fib_node
*
2935 mlxsw_sp_fib_node_create(struct mlxsw_sp_fib
*fib
, const void *addr
,
2936 size_t addr_len
, unsigned char prefix_len
)
2938 struct mlxsw_sp_fib_node
*fib_node
;
2940 fib_node
= kzalloc(sizeof(*fib_node
), GFP_KERNEL
);
2944 INIT_LIST_HEAD(&fib_node
->entry_list
);
2945 list_add(&fib_node
->list
, &fib
->node_list
);
2946 memcpy(fib_node
->key
.addr
, addr
, addr_len
);
2947 fib_node
->key
.prefix_len
= prefix_len
;
2952 static void mlxsw_sp_fib_node_destroy(struct mlxsw_sp_fib_node
*fib_node
)
2954 list_del(&fib_node
->list
);
2955 WARN_ON(!list_empty(&fib_node
->entry_list
));
2960 mlxsw_sp_fib_node_entry_is_first(const struct mlxsw_sp_fib_node
*fib_node
,
2961 const struct mlxsw_sp_fib_entry
*fib_entry
)
2963 return list_first_entry(&fib_node
->entry_list
,
2964 struct mlxsw_sp_fib_entry
, list
) == fib_entry
;
2967 static int mlxsw_sp_fib_lpm_tree_link(struct mlxsw_sp
*mlxsw_sp
,
2968 struct mlxsw_sp_fib
*fib
,
2969 struct mlxsw_sp_fib_node
*fib_node
)
2971 struct mlxsw_sp_prefix_usage req_prefix_usage
= {{ 0 } };
2972 struct mlxsw_sp_lpm_tree
*lpm_tree
;
2975 /* Since the tree is shared between all virtual routers we must
2976 * make sure it contains all the required prefix lengths. This
2977 * can be computed by either adding the new prefix length to the
2978 * existing prefix usage of a bound tree, or by aggregating the
2979 * prefix lengths across all virtual routers and adding the new
2983 mlxsw_sp_prefix_usage_cpy(&req_prefix_usage
,
2984 &fib
->lpm_tree
->prefix_usage
);
2986 mlxsw_sp_vrs_prefixes(mlxsw_sp
, fib
->proto
, &req_prefix_usage
);
2987 mlxsw_sp_prefix_usage_set(&req_prefix_usage
, fib_node
->key
.prefix_len
);
2989 lpm_tree
= mlxsw_sp_lpm_tree_get(mlxsw_sp
, &req_prefix_usage
,
2991 if (IS_ERR(lpm_tree
))
2992 return PTR_ERR(lpm_tree
);
2994 if (fib
->lpm_tree
&& fib
->lpm_tree
->id
== lpm_tree
->id
)
2997 err
= mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp
, fib
, lpm_tree
);
3004 static void mlxsw_sp_fib_lpm_tree_unlink(struct mlxsw_sp
*mlxsw_sp
,
3005 struct mlxsw_sp_fib
*fib
)
3007 struct mlxsw_sp_prefix_usage req_prefix_usage
= {{ 0 } };
3008 struct mlxsw_sp_lpm_tree
*lpm_tree
;
3010 /* Aggregate prefix lengths across all virtual routers to make
3011 * sure we only have used prefix lengths in the LPM tree.
3013 mlxsw_sp_vrs_prefixes(mlxsw_sp
, fib
->proto
, &req_prefix_usage
);
3014 lpm_tree
= mlxsw_sp_lpm_tree_get(mlxsw_sp
, &req_prefix_usage
,
3016 if (IS_ERR(lpm_tree
))
3018 mlxsw_sp_vrs_lpm_tree_replace(mlxsw_sp
, fib
, lpm_tree
);
3021 if (!mlxsw_sp_prefix_usage_none(&fib
->prefix_usage
))
3023 mlxsw_sp_vr_lpm_tree_unbind(mlxsw_sp
, fib
);
3024 mlxsw_sp_lpm_tree_put(mlxsw_sp
, fib
->lpm_tree
);
3025 fib
->lpm_tree
= NULL
;
3028 static void mlxsw_sp_fib_node_prefix_inc(struct mlxsw_sp_fib_node
*fib_node
)
3030 unsigned char prefix_len
= fib_node
->key
.prefix_len
;
3031 struct mlxsw_sp_fib
*fib
= fib_node
->fib
;
3033 if (fib
->prefix_ref_count
[prefix_len
]++ == 0)
3034 mlxsw_sp_prefix_usage_set(&fib
->prefix_usage
, prefix_len
);
3037 static void mlxsw_sp_fib_node_prefix_dec(struct mlxsw_sp_fib_node
*fib_node
)
3039 unsigned char prefix_len
= fib_node
->key
.prefix_len
;
3040 struct mlxsw_sp_fib
*fib
= fib_node
->fib
;
3042 if (--fib
->prefix_ref_count
[prefix_len
] == 0)
3043 mlxsw_sp_prefix_usage_clear(&fib
->prefix_usage
, prefix_len
);
3046 static int mlxsw_sp_fib_node_init(struct mlxsw_sp
*mlxsw_sp
,
3047 struct mlxsw_sp_fib_node
*fib_node
,
3048 struct mlxsw_sp_fib
*fib
)
3052 err
= mlxsw_sp_fib_node_insert(fib
, fib_node
);
3055 fib_node
->fib
= fib
;
3057 err
= mlxsw_sp_fib_lpm_tree_link(mlxsw_sp
, fib
, fib_node
);
3059 goto err_fib_lpm_tree_link
;
3061 mlxsw_sp_fib_node_prefix_inc(fib_node
);
3065 err_fib_lpm_tree_link
:
3066 fib_node
->fib
= NULL
;
3067 mlxsw_sp_fib_node_remove(fib
, fib_node
);
3071 static void mlxsw_sp_fib_node_fini(struct mlxsw_sp
*mlxsw_sp
,
3072 struct mlxsw_sp_fib_node
*fib_node
)
3074 struct mlxsw_sp_fib
*fib
= fib_node
->fib
;
3076 mlxsw_sp_fib_node_prefix_dec(fib_node
);
3077 mlxsw_sp_fib_lpm_tree_unlink(mlxsw_sp
, fib
);
3078 fib_node
->fib
= NULL
;
3079 mlxsw_sp_fib_node_remove(fib
, fib_node
);
3082 static struct mlxsw_sp_fib_node
*
3083 mlxsw_sp_fib_node_get(struct mlxsw_sp
*mlxsw_sp
, u32 tb_id
, const void *addr
,
3084 size_t addr_len
, unsigned char prefix_len
,
3085 enum mlxsw_sp_l3proto proto
)
3087 struct mlxsw_sp_fib_node
*fib_node
;
3088 struct mlxsw_sp_fib
*fib
;
3089 struct mlxsw_sp_vr
*vr
;
3092 vr
= mlxsw_sp_vr_get(mlxsw_sp
, tb_id
);
3094 return ERR_CAST(vr
);
3095 fib
= mlxsw_sp_vr_fib(vr
, proto
);
3097 fib_node
= mlxsw_sp_fib_node_lookup(fib
, addr
, addr_len
, prefix_len
);
3101 fib_node
= mlxsw_sp_fib_node_create(fib
, addr
, addr_len
, prefix_len
);
3104 goto err_fib_node_create
;
3107 err
= mlxsw_sp_fib_node_init(mlxsw_sp
, fib_node
, fib
);
3109 goto err_fib_node_init
;
3114 mlxsw_sp_fib_node_destroy(fib_node
);
3115 err_fib_node_create
:
3116 mlxsw_sp_vr_put(vr
);
3117 return ERR_PTR(err
);
3120 static void mlxsw_sp_fib_node_put(struct mlxsw_sp
*mlxsw_sp
,
3121 struct mlxsw_sp_fib_node
*fib_node
)
3123 struct mlxsw_sp_vr
*vr
= fib_node
->fib
->vr
;
3125 if (!list_empty(&fib_node
->entry_list
))
3127 mlxsw_sp_fib_node_fini(mlxsw_sp
, fib_node
);
3128 mlxsw_sp_fib_node_destroy(fib_node
);
3129 mlxsw_sp_vr_put(vr
);
3132 static struct mlxsw_sp_fib4_entry
*
3133 mlxsw_sp_fib4_node_entry_find(const struct mlxsw_sp_fib_node
*fib_node
,
3134 const struct mlxsw_sp_fib4_entry
*new4_entry
)
3136 struct mlxsw_sp_fib4_entry
*fib4_entry
;
3138 list_for_each_entry(fib4_entry
, &fib_node
->entry_list
, common
.list
) {
3139 if (fib4_entry
->tb_id
> new4_entry
->tb_id
)
3141 if (fib4_entry
->tb_id
!= new4_entry
->tb_id
)
3143 if (fib4_entry
->tos
> new4_entry
->tos
)
3145 if (fib4_entry
->prio
>= new4_entry
->prio
||
3146 fib4_entry
->tos
< new4_entry
->tos
)
3154 mlxsw_sp_fib4_node_list_append(struct mlxsw_sp_fib4_entry
*fib4_entry
,
3155 struct mlxsw_sp_fib4_entry
*new4_entry
)
3157 struct mlxsw_sp_fib_node
*fib_node
;
3159 if (WARN_ON(!fib4_entry
))
3162 fib_node
= fib4_entry
->common
.fib_node
;
3163 list_for_each_entry_from(fib4_entry
, &fib_node
->entry_list
,
3165 if (fib4_entry
->tb_id
!= new4_entry
->tb_id
||
3166 fib4_entry
->tos
!= new4_entry
->tos
||
3167 fib4_entry
->prio
!= new4_entry
->prio
)
3171 list_add_tail(&new4_entry
->common
.list
, &fib4_entry
->common
.list
);
3176 mlxsw_sp_fib4_node_list_insert(struct mlxsw_sp_fib4_entry
*new4_entry
,
3177 bool replace
, bool append
)
3179 struct mlxsw_sp_fib_node
*fib_node
= new4_entry
->common
.fib_node
;
3180 struct mlxsw_sp_fib4_entry
*fib4_entry
;
3182 fib4_entry
= mlxsw_sp_fib4_node_entry_find(fib_node
, new4_entry
);
3185 return mlxsw_sp_fib4_node_list_append(fib4_entry
, new4_entry
);
3186 if (replace
&& WARN_ON(!fib4_entry
))
3189 /* Insert new entry before replaced one, so that we can later
3190 * remove the second.
3193 list_add_tail(&new4_entry
->common
.list
,
3194 &fib4_entry
->common
.list
);
3196 struct mlxsw_sp_fib4_entry
*last
;
3198 list_for_each_entry(last
, &fib_node
->entry_list
, common
.list
) {
3199 if (new4_entry
->tb_id
> last
->tb_id
)
3205 list_add(&new4_entry
->common
.list
,
3206 &fib4_entry
->common
.list
);
3208 list_add(&new4_entry
->common
.list
,
3209 &fib_node
->entry_list
);
3216 mlxsw_sp_fib4_node_list_remove(struct mlxsw_sp_fib4_entry
*fib4_entry
)
3218 list_del(&fib4_entry
->common
.list
);
3221 static int mlxsw_sp_fib_node_entry_add(struct mlxsw_sp
*mlxsw_sp
,
3222 struct mlxsw_sp_fib_entry
*fib_entry
)
3224 struct mlxsw_sp_fib_node
*fib_node
= fib_entry
->fib_node
;
3226 if (!mlxsw_sp_fib_node_entry_is_first(fib_node
, fib_entry
))
3229 /* To prevent packet loss, overwrite the previously offloaded
3232 if (!list_is_singular(&fib_node
->entry_list
)) {
3233 enum mlxsw_reg_ralue_op op
= MLXSW_REG_RALUE_OP_WRITE_DELETE
;
3234 struct mlxsw_sp_fib_entry
*n
= list_next_entry(fib_entry
, list
);
3236 mlxsw_sp_fib_entry_offload_refresh(n
, op
, 0);
3239 return mlxsw_sp_fib_entry_update(mlxsw_sp
, fib_entry
);
3242 static void mlxsw_sp_fib_node_entry_del(struct mlxsw_sp
*mlxsw_sp
,
3243 struct mlxsw_sp_fib_entry
*fib_entry
)
3245 struct mlxsw_sp_fib_node
*fib_node
= fib_entry
->fib_node
;
3247 if (!mlxsw_sp_fib_node_entry_is_first(fib_node
, fib_entry
))
3250 /* Promote the next entry by overwriting the deleted entry */
3251 if (!list_is_singular(&fib_node
->entry_list
)) {
3252 struct mlxsw_sp_fib_entry
*n
= list_next_entry(fib_entry
, list
);
3253 enum mlxsw_reg_ralue_op op
= MLXSW_REG_RALUE_OP_WRITE_DELETE
;
3255 mlxsw_sp_fib_entry_update(mlxsw_sp
, n
);
3256 mlxsw_sp_fib_entry_offload_refresh(fib_entry
, op
, 0);
3260 mlxsw_sp_fib_entry_del(mlxsw_sp
, fib_entry
);
3263 static int mlxsw_sp_fib4_node_entry_link(struct mlxsw_sp
*mlxsw_sp
,
3264 struct mlxsw_sp_fib4_entry
*fib4_entry
,
3265 bool replace
, bool append
)
3269 err
= mlxsw_sp_fib4_node_list_insert(fib4_entry
, replace
, append
);
3273 err
= mlxsw_sp_fib_node_entry_add(mlxsw_sp
, &fib4_entry
->common
);
3275 goto err_fib_node_entry_add
;
3279 err_fib_node_entry_add
:
3280 mlxsw_sp_fib4_node_list_remove(fib4_entry
);
3285 mlxsw_sp_fib4_node_entry_unlink(struct mlxsw_sp
*mlxsw_sp
,
3286 struct mlxsw_sp_fib4_entry
*fib4_entry
)
3288 mlxsw_sp_fib_node_entry_del(mlxsw_sp
, &fib4_entry
->common
);
3289 mlxsw_sp_fib4_node_list_remove(fib4_entry
);
3292 static void mlxsw_sp_fib4_entry_replace(struct mlxsw_sp
*mlxsw_sp
,
3293 struct mlxsw_sp_fib4_entry
*fib4_entry
,
3296 struct mlxsw_sp_fib_node
*fib_node
= fib4_entry
->common
.fib_node
;
3297 struct mlxsw_sp_fib4_entry
*replaced
;
3302 /* We inserted the new entry before replaced one */
3303 replaced
= list_next_entry(fib4_entry
, common
.list
);
3305 mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp
, replaced
);
3306 mlxsw_sp_fib4_entry_destroy(mlxsw_sp
, replaced
);
3307 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
3311 mlxsw_sp_router_fib4_add(struct mlxsw_sp
*mlxsw_sp
,
3312 const struct fib_entry_notifier_info
*fen_info
,
3313 bool replace
, bool append
)
3315 struct mlxsw_sp_fib4_entry
*fib4_entry
;
3316 struct mlxsw_sp_fib_node
*fib_node
;
3319 if (mlxsw_sp
->router
->aborted
)
3322 fib_node
= mlxsw_sp_fib_node_get(mlxsw_sp
, fen_info
->tb_id
,
3323 &fen_info
->dst
, sizeof(fen_info
->dst
),
3325 MLXSW_SP_L3_PROTO_IPV4
);
3326 if (IS_ERR(fib_node
)) {
3327 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to get FIB node\n");
3328 return PTR_ERR(fib_node
);
3331 fib4_entry
= mlxsw_sp_fib4_entry_create(mlxsw_sp
, fib_node
, fen_info
);
3332 if (IS_ERR(fib4_entry
)) {
3333 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to create FIB entry\n");
3334 err
= PTR_ERR(fib4_entry
);
3335 goto err_fib4_entry_create
;
3338 err
= mlxsw_sp_fib4_node_entry_link(mlxsw_sp
, fib4_entry
, replace
,
3341 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to link FIB entry to node\n");
3342 goto err_fib4_node_entry_link
;
3345 mlxsw_sp_fib4_entry_replace(mlxsw_sp
, fib4_entry
, replace
);
3349 err_fib4_node_entry_link
:
3350 mlxsw_sp_fib4_entry_destroy(mlxsw_sp
, fib4_entry
);
3351 err_fib4_entry_create
:
3352 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
3356 static void mlxsw_sp_router_fib4_del(struct mlxsw_sp
*mlxsw_sp
,
3357 struct fib_entry_notifier_info
*fen_info
)
3359 struct mlxsw_sp_fib4_entry
*fib4_entry
;
3360 struct mlxsw_sp_fib_node
*fib_node
;
3362 if (mlxsw_sp
->router
->aborted
)
3365 fib4_entry
= mlxsw_sp_fib4_entry_lookup(mlxsw_sp
, fen_info
);
3366 if (WARN_ON(!fib4_entry
))
3368 fib_node
= fib4_entry
->common
.fib_node
;
3370 mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp
, fib4_entry
);
3371 mlxsw_sp_fib4_entry_destroy(mlxsw_sp
, fib4_entry
);
3372 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
3375 static bool mlxsw_sp_fib6_rt_should_ignore(const struct rt6_info
*rt
)
3377 /* Packets with link-local destination IP arriving to the router
3378 * are trapped to the CPU, so no need to program specific routes
3381 if (ipv6_addr_type(&rt
->rt6i_dst
.addr
) & IPV6_ADDR_LINKLOCAL
)
3384 /* Multicast routes aren't supported, so ignore them. Neighbour
3385 * Discovery packets are specifically trapped.
3387 if (ipv6_addr_type(&rt
->rt6i_dst
.addr
) & IPV6_ADDR_MULTICAST
)
3390 /* Cloned routes are irrelevant in the forwarding path. */
3391 if (rt
->rt6i_flags
& RTF_CACHE
)
3397 static struct mlxsw_sp_rt6
*mlxsw_sp_rt6_create(struct rt6_info
*rt
)
3399 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
3401 mlxsw_sp_rt6
= kzalloc(sizeof(*mlxsw_sp_rt6
), GFP_KERNEL
);
3403 return ERR_PTR(-ENOMEM
);
3405 /* In case of route replace, replaced route is deleted with
3406 * no notification. Take reference to prevent accessing freed
3409 mlxsw_sp_rt6
->rt
= rt
;
3412 return mlxsw_sp_rt6
;
3415 #if IS_ENABLED(CONFIG_IPV6)
3416 static void mlxsw_sp_rt6_release(struct rt6_info
*rt
)
3421 static void mlxsw_sp_rt6_release(struct rt6_info
*rt
)
3426 static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6
*mlxsw_sp_rt6
)
3428 mlxsw_sp_rt6_release(mlxsw_sp_rt6
->rt
);
3429 kfree(mlxsw_sp_rt6
);
3432 static bool mlxsw_sp_fib6_rt_can_mp(const struct rt6_info
*rt
)
3434 /* RTF_CACHE routes are ignored */
3435 return (rt
->rt6i_flags
& (RTF_GATEWAY
| RTF_ADDRCONF
)) == RTF_GATEWAY
;
3438 static struct rt6_info
*
3439 mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry
*fib6_entry
)
3441 return list_first_entry(&fib6_entry
->rt6_list
, struct mlxsw_sp_rt6
,
3445 static struct mlxsw_sp_fib6_entry
*
3446 mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node
*fib_node
,
3447 const struct rt6_info
*nrt
, bool replace
)
3449 struct mlxsw_sp_fib6_entry
*fib6_entry
;
3451 if (!mlxsw_sp_fib6_rt_can_mp(nrt
) || replace
)
3454 list_for_each_entry(fib6_entry
, &fib_node
->entry_list
, common
.list
) {
3455 struct rt6_info
*rt
= mlxsw_sp_fib6_entry_rt(fib6_entry
);
3457 /* RT6_TABLE_LOCAL and RT6_TABLE_MAIN share the same
3460 if (rt
->rt6i_table
->tb6_id
> nrt
->rt6i_table
->tb6_id
)
3462 if (rt
->rt6i_table
->tb6_id
!= nrt
->rt6i_table
->tb6_id
)
3464 if (rt
->rt6i_metric
< nrt
->rt6i_metric
)
3466 if (rt
->rt6i_metric
== nrt
->rt6i_metric
&&
3467 mlxsw_sp_fib6_rt_can_mp(rt
))
3469 if (rt
->rt6i_metric
> nrt
->rt6i_metric
)
3476 static struct mlxsw_sp_rt6
*
3477 mlxsw_sp_fib6_entry_rt_find(const struct mlxsw_sp_fib6_entry
*fib6_entry
,
3478 const struct rt6_info
*rt
)
3480 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
3482 list_for_each_entry(mlxsw_sp_rt6
, &fib6_entry
->rt6_list
, list
) {
3483 if (mlxsw_sp_rt6
->rt
== rt
)
3484 return mlxsw_sp_rt6
;
3490 static int mlxsw_sp_nexthop6_init(struct mlxsw_sp
*mlxsw_sp
,
3491 struct mlxsw_sp_nexthop_group
*nh_grp
,
3492 struct mlxsw_sp_nexthop
*nh
,
3493 const struct rt6_info
*rt
)
3495 struct net_device
*dev
= rt
->dst
.dev
;
3496 struct mlxsw_sp_rif
*rif
;
3499 nh
->nh_grp
= nh_grp
;
3500 memcpy(&nh
->gw_addr
, &rt
->rt6i_gateway
, sizeof(nh
->gw_addr
));
3504 nh
->ifindex
= dev
->ifindex
;
3506 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, dev
);
3509 mlxsw_sp_nexthop_rif_init(nh
, rif
);
3511 err
= mlxsw_sp_nexthop_neigh_init(mlxsw_sp
, nh
);
3513 goto err_nexthop_neigh_init
;
3517 err_nexthop_neigh_init
:
3518 mlxsw_sp_nexthop_rif_fini(nh
);
3522 static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp
*mlxsw_sp
,
3523 struct mlxsw_sp_nexthop
*nh
)
3525 mlxsw_sp_nexthop_neigh_fini(mlxsw_sp
, nh
);
3526 mlxsw_sp_nexthop_rif_fini(nh
);
3529 static struct mlxsw_sp_nexthop_group
*
3530 mlxsw_sp_nexthop6_group_create(struct mlxsw_sp
*mlxsw_sp
,
3531 struct mlxsw_sp_fib6_entry
*fib6_entry
)
3533 struct mlxsw_sp_nexthop_group
*nh_grp
;
3534 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
3535 struct mlxsw_sp_nexthop
*nh
;
3540 alloc_size
= sizeof(*nh_grp
) +
3541 fib6_entry
->nrt6
* sizeof(struct mlxsw_sp_nexthop
);
3542 nh_grp
= kzalloc(alloc_size
, GFP_KERNEL
);
3544 return ERR_PTR(-ENOMEM
);
3545 INIT_LIST_HEAD(&nh_grp
->fib_list
);
3546 #if IS_ENABLED(CONFIG_IPV6)
3547 nh_grp
->neigh_tbl
= &nd_tbl
;
3549 mlxsw_sp_rt6
= list_first_entry(&fib6_entry
->rt6_list
,
3550 struct mlxsw_sp_rt6
, list
);
3551 nh_grp
->gateway
= !!(mlxsw_sp_rt6
->rt
->rt6i_flags
& RTF_GATEWAY
);
3552 nh_grp
->count
= fib6_entry
->nrt6
;
3553 for (i
= 0; i
< nh_grp
->count
; i
++) {
3554 struct rt6_info
*rt
= mlxsw_sp_rt6
->rt
;
3556 nh
= &nh_grp
->nexthops
[i
];
3557 err
= mlxsw_sp_nexthop6_init(mlxsw_sp
, nh_grp
, nh
, rt
);
3559 goto err_nexthop6_init
;
3560 mlxsw_sp_rt6
= list_next_entry(mlxsw_sp_rt6
, list
);
3563 err
= mlxsw_sp_nexthop_group_insert(mlxsw_sp
, nh_grp
);
3565 goto err_nexthop_group_insert
;
3567 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh_grp
);
3570 err_nexthop_group_insert
:
3572 for (i
--; i
>= 0; i
--) {
3573 nh
= &nh_grp
->nexthops
[i
];
3574 mlxsw_sp_nexthop6_fini(mlxsw_sp
, nh
);
3577 return ERR_PTR(err
);
3581 mlxsw_sp_nexthop6_group_destroy(struct mlxsw_sp
*mlxsw_sp
,
3582 struct mlxsw_sp_nexthop_group
*nh_grp
)
3584 struct mlxsw_sp_nexthop
*nh
;
3585 int i
= nh_grp
->count
;
3587 mlxsw_sp_nexthop_group_remove(mlxsw_sp
, nh_grp
);
3588 for (i
--; i
>= 0; i
--) {
3589 nh
= &nh_grp
->nexthops
[i
];
3590 mlxsw_sp_nexthop6_fini(mlxsw_sp
, nh
);
3592 mlxsw_sp_nexthop_group_refresh(mlxsw_sp
, nh_grp
);
3593 WARN_ON(nh_grp
->adj_index_valid
);
3597 static int mlxsw_sp_nexthop6_group_get(struct mlxsw_sp
*mlxsw_sp
,
3598 struct mlxsw_sp_fib6_entry
*fib6_entry
)
3600 struct mlxsw_sp_nexthop_group
*nh_grp
;
3602 nh_grp
= mlxsw_sp_nexthop6_group_lookup(mlxsw_sp
, fib6_entry
);
3604 nh_grp
= mlxsw_sp_nexthop6_group_create(mlxsw_sp
, fib6_entry
);
3606 return PTR_ERR(nh_grp
);
3609 list_add_tail(&fib6_entry
->common
.nexthop_group_node
,
3611 fib6_entry
->common
.nh_group
= nh_grp
;
3616 static void mlxsw_sp_nexthop6_group_put(struct mlxsw_sp
*mlxsw_sp
,
3617 struct mlxsw_sp_fib_entry
*fib_entry
)
3619 struct mlxsw_sp_nexthop_group
*nh_grp
= fib_entry
->nh_group
;
3621 list_del(&fib_entry
->nexthop_group_node
);
3622 if (!list_empty(&nh_grp
->fib_list
))
3624 mlxsw_sp_nexthop6_group_destroy(mlxsw_sp
, nh_grp
);
3628 mlxsw_sp_nexthop6_group_update(struct mlxsw_sp
*mlxsw_sp
,
3629 struct mlxsw_sp_fib6_entry
*fib6_entry
)
3631 struct mlxsw_sp_nexthop_group
*old_nh_grp
= fib6_entry
->common
.nh_group
;
3634 fib6_entry
->common
.nh_group
= NULL
;
3635 list_del(&fib6_entry
->common
.nexthop_group_node
);
3637 err
= mlxsw_sp_nexthop6_group_get(mlxsw_sp
, fib6_entry
);
3639 goto err_nexthop6_group_get
;
3641 /* In case this entry is offloaded, then the adjacency index
3642 * currently associated with it in the device's table is that
3643 * of the old group. Start using the new one instead.
3645 err
= mlxsw_sp_fib_node_entry_add(mlxsw_sp
, &fib6_entry
->common
);
3647 goto err_fib_node_entry_add
;
3649 if (list_empty(&old_nh_grp
->fib_list
))
3650 mlxsw_sp_nexthop6_group_destroy(mlxsw_sp
, old_nh_grp
);
3654 err_fib_node_entry_add
:
3655 mlxsw_sp_nexthop6_group_put(mlxsw_sp
, &fib6_entry
->common
);
3656 err_nexthop6_group_get
:
3657 list_add_tail(&fib6_entry
->common
.nexthop_group_node
,
3658 &old_nh_grp
->fib_list
);
3659 fib6_entry
->common
.nh_group
= old_nh_grp
;
3664 mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp
*mlxsw_sp
,
3665 struct mlxsw_sp_fib6_entry
*fib6_entry
,
3666 struct rt6_info
*rt
)
3668 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
3671 mlxsw_sp_rt6
= mlxsw_sp_rt6_create(rt
);
3672 if (IS_ERR(mlxsw_sp_rt6
))
3673 return PTR_ERR(mlxsw_sp_rt6
);
3675 list_add_tail(&mlxsw_sp_rt6
->list
, &fib6_entry
->rt6_list
);
3678 err
= mlxsw_sp_nexthop6_group_update(mlxsw_sp
, fib6_entry
);
3680 goto err_nexthop6_group_update
;
3684 err_nexthop6_group_update
:
3686 list_del(&mlxsw_sp_rt6
->list
);
3687 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6
);
3692 mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp
*mlxsw_sp
,
3693 struct mlxsw_sp_fib6_entry
*fib6_entry
,
3694 struct rt6_info
*rt
)
3696 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
3698 mlxsw_sp_rt6
= mlxsw_sp_fib6_entry_rt_find(fib6_entry
, rt
);
3699 if (WARN_ON(!mlxsw_sp_rt6
))
3703 list_del(&mlxsw_sp_rt6
->list
);
3704 mlxsw_sp_nexthop6_group_update(mlxsw_sp
, fib6_entry
);
3705 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6
);
3708 static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp_fib_entry
*fib_entry
,
3709 const struct rt6_info
*rt
)
3711 /* Packets hitting RTF_REJECT routes need to be discarded by the
3712 * stack. We can rely on their destination device not having a
3713 * RIF (it's the loopback device) and can thus use action type
3714 * local, which will cause them to be trapped with a lower
3715 * priority than packets that need to be locally received.
3717 if (rt
->rt6i_flags
& (RTF_LOCAL
| RTF_ANYCAST
))
3718 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_TRAP
;
3719 else if (rt
->rt6i_flags
& RTF_REJECT
)
3720 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
;
3721 else if (rt
->rt6i_flags
& RTF_GATEWAY
)
3722 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_REMOTE
;
3724 fib_entry
->type
= MLXSW_SP_FIB_ENTRY_TYPE_LOCAL
;
3728 mlxsw_sp_fib6_entry_rt_destroy_all(struct mlxsw_sp_fib6_entry
*fib6_entry
)
3730 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
, *tmp
;
3732 list_for_each_entry_safe(mlxsw_sp_rt6
, tmp
, &fib6_entry
->rt6_list
,
3735 list_del(&mlxsw_sp_rt6
->list
);
3736 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6
);
3740 static struct mlxsw_sp_fib6_entry
*
3741 mlxsw_sp_fib6_entry_create(struct mlxsw_sp
*mlxsw_sp
,
3742 struct mlxsw_sp_fib_node
*fib_node
,
3743 struct rt6_info
*rt
)
3745 struct mlxsw_sp_fib6_entry
*fib6_entry
;
3746 struct mlxsw_sp_fib_entry
*fib_entry
;
3747 struct mlxsw_sp_rt6
*mlxsw_sp_rt6
;
3750 fib6_entry
= kzalloc(sizeof(*fib6_entry
), GFP_KERNEL
);
3752 return ERR_PTR(-ENOMEM
);
3753 fib_entry
= &fib6_entry
->common
;
3755 mlxsw_sp_rt6
= mlxsw_sp_rt6_create(rt
);
3756 if (IS_ERR(mlxsw_sp_rt6
)) {
3757 err
= PTR_ERR(mlxsw_sp_rt6
);
3758 goto err_rt6_create
;
3761 mlxsw_sp_fib6_entry_type_set(fib_entry
, mlxsw_sp_rt6
->rt
);
3763 INIT_LIST_HEAD(&fib6_entry
->rt6_list
);
3764 list_add_tail(&mlxsw_sp_rt6
->list
, &fib6_entry
->rt6_list
);
3765 fib6_entry
->nrt6
= 1;
3766 err
= mlxsw_sp_nexthop6_group_get(mlxsw_sp
, fib6_entry
);
3768 goto err_nexthop6_group_get
;
3770 fib_entry
->fib_node
= fib_node
;
3774 err_nexthop6_group_get
:
3775 list_del(&mlxsw_sp_rt6
->list
);
3776 mlxsw_sp_rt6_destroy(mlxsw_sp_rt6
);
3779 return ERR_PTR(err
);
3782 static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp
*mlxsw_sp
,
3783 struct mlxsw_sp_fib6_entry
*fib6_entry
)
3785 mlxsw_sp_nexthop6_group_put(mlxsw_sp
, &fib6_entry
->common
);
3786 mlxsw_sp_fib6_entry_rt_destroy_all(fib6_entry
);
3787 WARN_ON(fib6_entry
->nrt6
);
3791 static struct mlxsw_sp_fib6_entry
*
3792 mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node
*fib_node
,
3793 const struct rt6_info
*nrt
, bool replace
)
3795 struct mlxsw_sp_fib6_entry
*fib6_entry
, *fallback
= NULL
;
3797 list_for_each_entry(fib6_entry
, &fib_node
->entry_list
, common
.list
) {
3798 struct rt6_info
*rt
= mlxsw_sp_fib6_entry_rt(fib6_entry
);
3800 if (rt
->rt6i_table
->tb6_id
> nrt
->rt6i_table
->tb6_id
)
3802 if (rt
->rt6i_table
->tb6_id
!= nrt
->rt6i_table
->tb6_id
)
3804 if (replace
&& rt
->rt6i_metric
== nrt
->rt6i_metric
) {
3805 if (mlxsw_sp_fib6_rt_can_mp(rt
) ==
3806 mlxsw_sp_fib6_rt_can_mp(nrt
))
3808 if (mlxsw_sp_fib6_rt_can_mp(nrt
))
3809 fallback
= fallback
?: fib6_entry
;
3811 if (rt
->rt6i_metric
> nrt
->rt6i_metric
)
3812 return fallback
?: fib6_entry
;
3819 mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry
*new6_entry
,
3822 struct mlxsw_sp_fib_node
*fib_node
= new6_entry
->common
.fib_node
;
3823 struct rt6_info
*nrt
= mlxsw_sp_fib6_entry_rt(new6_entry
);
3824 struct mlxsw_sp_fib6_entry
*fib6_entry
;
3826 fib6_entry
= mlxsw_sp_fib6_node_entry_find(fib_node
, nrt
, replace
);
3828 if (replace
&& WARN_ON(!fib6_entry
))
3832 list_add_tail(&new6_entry
->common
.list
,
3833 &fib6_entry
->common
.list
);
3835 struct mlxsw_sp_fib6_entry
*last
;
3837 list_for_each_entry(last
, &fib_node
->entry_list
, common
.list
) {
3838 struct rt6_info
*rt
= mlxsw_sp_fib6_entry_rt(last
);
3840 if (nrt
->rt6i_table
->tb6_id
> rt
->rt6i_table
->tb6_id
)
3846 list_add(&new6_entry
->common
.list
,
3847 &fib6_entry
->common
.list
);
3849 list_add(&new6_entry
->common
.list
,
3850 &fib_node
->entry_list
);
3857 mlxsw_sp_fib6_node_list_remove(struct mlxsw_sp_fib6_entry
*fib6_entry
)
3859 list_del(&fib6_entry
->common
.list
);
3862 static int mlxsw_sp_fib6_node_entry_link(struct mlxsw_sp
*mlxsw_sp
,
3863 struct mlxsw_sp_fib6_entry
*fib6_entry
,
3868 err
= mlxsw_sp_fib6_node_list_insert(fib6_entry
, replace
);
3872 err
= mlxsw_sp_fib_node_entry_add(mlxsw_sp
, &fib6_entry
->common
);
3874 goto err_fib_node_entry_add
;
3878 err_fib_node_entry_add
:
3879 mlxsw_sp_fib6_node_list_remove(fib6_entry
);
3884 mlxsw_sp_fib6_node_entry_unlink(struct mlxsw_sp
*mlxsw_sp
,
3885 struct mlxsw_sp_fib6_entry
*fib6_entry
)
3887 mlxsw_sp_fib_node_entry_del(mlxsw_sp
, &fib6_entry
->common
);
3888 mlxsw_sp_fib6_node_list_remove(fib6_entry
);
3891 static struct mlxsw_sp_fib6_entry
*
3892 mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp
*mlxsw_sp
,
3893 const struct rt6_info
*rt
)
3895 struct mlxsw_sp_fib6_entry
*fib6_entry
;
3896 struct mlxsw_sp_fib_node
*fib_node
;
3897 struct mlxsw_sp_fib
*fib
;
3898 struct mlxsw_sp_vr
*vr
;
3900 vr
= mlxsw_sp_vr_find(mlxsw_sp
, rt
->rt6i_table
->tb6_id
);
3903 fib
= mlxsw_sp_vr_fib(vr
, MLXSW_SP_L3_PROTO_IPV6
);
3905 fib_node
= mlxsw_sp_fib_node_lookup(fib
, &rt
->rt6i_dst
.addr
,
3906 sizeof(rt
->rt6i_dst
.addr
),
3911 list_for_each_entry(fib6_entry
, &fib_node
->entry_list
, common
.list
) {
3912 struct rt6_info
*iter_rt
= mlxsw_sp_fib6_entry_rt(fib6_entry
);
3914 if (rt
->rt6i_table
->tb6_id
== iter_rt
->rt6i_table
->tb6_id
&&
3915 rt
->rt6i_metric
== iter_rt
->rt6i_metric
&&
3916 mlxsw_sp_fib6_entry_rt_find(fib6_entry
, rt
))
3923 static void mlxsw_sp_fib6_entry_replace(struct mlxsw_sp
*mlxsw_sp
,
3924 struct mlxsw_sp_fib6_entry
*fib6_entry
,
3927 struct mlxsw_sp_fib_node
*fib_node
= fib6_entry
->common
.fib_node
;
3928 struct mlxsw_sp_fib6_entry
*replaced
;
3933 replaced
= list_next_entry(fib6_entry
, common
.list
);
3935 mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp
, replaced
);
3936 mlxsw_sp_fib6_entry_destroy(mlxsw_sp
, replaced
);
3937 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
3940 static int mlxsw_sp_router_fib6_add(struct mlxsw_sp
*mlxsw_sp
,
3941 struct rt6_info
*rt
, bool replace
)
3943 struct mlxsw_sp_fib6_entry
*fib6_entry
;
3944 struct mlxsw_sp_fib_node
*fib_node
;
3947 if (mlxsw_sp
->router
->aborted
)
3950 if (rt
->rt6i_src
.plen
)
3953 if (mlxsw_sp_fib6_rt_should_ignore(rt
))
3956 fib_node
= mlxsw_sp_fib_node_get(mlxsw_sp
, rt
->rt6i_table
->tb6_id
,
3958 sizeof(rt
->rt6i_dst
.addr
),
3960 MLXSW_SP_L3_PROTO_IPV6
);
3961 if (IS_ERR(fib_node
))
3962 return PTR_ERR(fib_node
);
3964 /* Before creating a new entry, try to append route to an existing
3967 fib6_entry
= mlxsw_sp_fib6_node_mp_entry_find(fib_node
, rt
, replace
);
3969 err
= mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp
, fib6_entry
, rt
);
3971 goto err_fib6_entry_nexthop_add
;
3975 fib6_entry
= mlxsw_sp_fib6_entry_create(mlxsw_sp
, fib_node
, rt
);
3976 if (IS_ERR(fib6_entry
)) {
3977 err
= PTR_ERR(fib6_entry
);
3978 goto err_fib6_entry_create
;
3981 err
= mlxsw_sp_fib6_node_entry_link(mlxsw_sp
, fib6_entry
, replace
);
3983 goto err_fib6_node_entry_link
;
3985 mlxsw_sp_fib6_entry_replace(mlxsw_sp
, fib6_entry
, replace
);
3989 err_fib6_node_entry_link
:
3990 mlxsw_sp_fib6_entry_destroy(mlxsw_sp
, fib6_entry
);
3991 err_fib6_entry_create
:
3992 err_fib6_entry_nexthop_add
:
3993 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
3997 static void mlxsw_sp_router_fib6_del(struct mlxsw_sp
*mlxsw_sp
,
3998 struct rt6_info
*rt
)
4000 struct mlxsw_sp_fib6_entry
*fib6_entry
;
4001 struct mlxsw_sp_fib_node
*fib_node
;
4003 if (mlxsw_sp
->router
->aborted
)
4006 if (mlxsw_sp_fib6_rt_should_ignore(rt
))
4009 fib6_entry
= mlxsw_sp_fib6_entry_lookup(mlxsw_sp
, rt
);
4010 if (WARN_ON(!fib6_entry
))
4013 /* If route is part of a multipath entry, but not the last one
4014 * removed, then only reduce its nexthop group.
4016 if (!list_is_singular(&fib6_entry
->rt6_list
)) {
4017 mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp
, fib6_entry
, rt
);
4021 fib_node
= fib6_entry
->common
.fib_node
;
4023 mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp
, fib6_entry
);
4024 mlxsw_sp_fib6_entry_destroy(mlxsw_sp
, fib6_entry
);
4025 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
4028 static int __mlxsw_sp_router_set_abort_trap(struct mlxsw_sp
*mlxsw_sp
,
4029 enum mlxsw_reg_ralxx_protocol proto
,
4032 char ralta_pl
[MLXSW_REG_RALTA_LEN
];
4033 char ralst_pl
[MLXSW_REG_RALST_LEN
];
4036 mlxsw_reg_ralta_pack(ralta_pl
, true, proto
, tree_id
);
4037 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralta
), ralta_pl
);
4041 mlxsw_reg_ralst_pack(ralst_pl
, 0xff, tree_id
);
4042 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralst
), ralst_pl
);
4046 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
4047 struct mlxsw_sp_vr
*vr
= &mlxsw_sp
->router
->vrs
[i
];
4048 char raltb_pl
[MLXSW_REG_RALTB_LEN
];
4049 char ralue_pl
[MLXSW_REG_RALUE_LEN
];
4051 mlxsw_reg_raltb_pack(raltb_pl
, vr
->id
, proto
, tree_id
);
4052 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(raltb
),
4057 mlxsw_reg_ralue_pack(ralue_pl
, proto
,
4058 MLXSW_REG_RALUE_OP_WRITE_WRITE
, vr
->id
, 0);
4059 mlxsw_reg_ralue_act_ip2me_pack(ralue_pl
);
4060 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ralue
),
4069 static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp
*mlxsw_sp
)
4071 enum mlxsw_reg_ralxx_protocol proto
= MLXSW_REG_RALXX_PROTOCOL_IPV4
;
4074 err
= __mlxsw_sp_router_set_abort_trap(mlxsw_sp
, proto
,
4075 MLXSW_SP_LPM_TREE_MIN
);
4079 proto
= MLXSW_REG_RALXX_PROTOCOL_IPV6
;
4080 return __mlxsw_sp_router_set_abort_trap(mlxsw_sp
, proto
,
4081 MLXSW_SP_LPM_TREE_MIN
+ 1);
4084 static void mlxsw_sp_fib4_node_flush(struct mlxsw_sp
*mlxsw_sp
,
4085 struct mlxsw_sp_fib_node
*fib_node
)
4087 struct mlxsw_sp_fib4_entry
*fib4_entry
, *tmp
;
4089 list_for_each_entry_safe(fib4_entry
, tmp
, &fib_node
->entry_list
,
4091 bool do_break
= &tmp
->common
.list
== &fib_node
->entry_list
;
4093 mlxsw_sp_fib4_node_entry_unlink(mlxsw_sp
, fib4_entry
);
4094 mlxsw_sp_fib4_entry_destroy(mlxsw_sp
, fib4_entry
);
4095 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
4096 /* Break when entry list is empty and node was freed.
4097 * Otherwise, we'll access freed memory in the next
4105 static void mlxsw_sp_fib6_node_flush(struct mlxsw_sp
*mlxsw_sp
,
4106 struct mlxsw_sp_fib_node
*fib_node
)
4108 struct mlxsw_sp_fib6_entry
*fib6_entry
, *tmp
;
4110 list_for_each_entry_safe(fib6_entry
, tmp
, &fib_node
->entry_list
,
4112 bool do_break
= &tmp
->common
.list
== &fib_node
->entry_list
;
4114 mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp
, fib6_entry
);
4115 mlxsw_sp_fib6_entry_destroy(mlxsw_sp
, fib6_entry
);
4116 mlxsw_sp_fib_node_put(mlxsw_sp
, fib_node
);
4122 static void mlxsw_sp_fib_node_flush(struct mlxsw_sp
*mlxsw_sp
,
4123 struct mlxsw_sp_fib_node
*fib_node
)
4125 switch (fib_node
->fib
->proto
) {
4126 case MLXSW_SP_L3_PROTO_IPV4
:
4127 mlxsw_sp_fib4_node_flush(mlxsw_sp
, fib_node
);
4129 case MLXSW_SP_L3_PROTO_IPV6
:
4130 mlxsw_sp_fib6_node_flush(mlxsw_sp
, fib_node
);
4135 static void mlxsw_sp_vr_fib_flush(struct mlxsw_sp
*mlxsw_sp
,
4136 struct mlxsw_sp_vr
*vr
,
4137 enum mlxsw_sp_l3proto proto
)
4139 struct mlxsw_sp_fib
*fib
= mlxsw_sp_vr_fib(vr
, proto
);
4140 struct mlxsw_sp_fib_node
*fib_node
, *tmp
;
4142 list_for_each_entry_safe(fib_node
, tmp
, &fib
->node_list
, list
) {
4143 bool do_break
= &tmp
->list
== &fib
->node_list
;
4145 mlxsw_sp_fib_node_flush(mlxsw_sp
, fib_node
);
4151 static void mlxsw_sp_router_fib_flush(struct mlxsw_sp
*mlxsw_sp
)
4155 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_VRS
); i
++) {
4156 struct mlxsw_sp_vr
*vr
= &mlxsw_sp
->router
->vrs
[i
];
4158 if (!mlxsw_sp_vr_is_used(vr
))
4160 mlxsw_sp_vr_fib_flush(mlxsw_sp
, vr
, MLXSW_SP_L3_PROTO_IPV4
);
4162 /* If virtual router was only used for IPv4, then it's no
4165 if (!mlxsw_sp_vr_is_used(vr
))
4167 mlxsw_sp_vr_fib_flush(mlxsw_sp
, vr
, MLXSW_SP_L3_PROTO_IPV6
);
4171 static void mlxsw_sp_router_fib_abort(struct mlxsw_sp
*mlxsw_sp
)
4175 if (mlxsw_sp
->router
->aborted
)
4177 dev_warn(mlxsw_sp
->bus_info
->dev
, "FIB abort triggered. Note that FIB entries are no longer being offloaded to this device.\n");
4178 mlxsw_sp_router_fib_flush(mlxsw_sp
);
4179 mlxsw_sp
->router
->aborted
= true;
4180 err
= mlxsw_sp_router_set_abort_trap(mlxsw_sp
);
4182 dev_warn(mlxsw_sp
->bus_info
->dev
, "Failed to set abort trap.\n");
4185 struct mlxsw_sp_fib_event_work
{
4186 struct work_struct work
;
4188 struct fib6_entry_notifier_info fen6_info
;
4189 struct fib_entry_notifier_info fen_info
;
4190 struct fib_rule_notifier_info fr_info
;
4191 struct fib_nh_notifier_info fnh_info
;
4193 struct mlxsw_sp
*mlxsw_sp
;
4194 unsigned long event
;
4197 static void mlxsw_sp_router_fib4_event_work(struct work_struct
*work
)
4199 struct mlxsw_sp_fib_event_work
*fib_work
=
4200 container_of(work
, struct mlxsw_sp_fib_event_work
, work
);
4201 struct mlxsw_sp
*mlxsw_sp
= fib_work
->mlxsw_sp
;
4202 struct fib_rule
*rule
;
4203 bool replace
, append
;
4206 /* Protect internal structures from changes */
4208 switch (fib_work
->event
) {
4209 case FIB_EVENT_ENTRY_REPLACE
: /* fall through */
4210 case FIB_EVENT_ENTRY_APPEND
: /* fall through */
4211 case FIB_EVENT_ENTRY_ADD
:
4212 replace
= fib_work
->event
== FIB_EVENT_ENTRY_REPLACE
;
4213 append
= fib_work
->event
== FIB_EVENT_ENTRY_APPEND
;
4214 err
= mlxsw_sp_router_fib4_add(mlxsw_sp
, &fib_work
->fen_info
,
4217 mlxsw_sp_router_fib_abort(mlxsw_sp
);
4218 fib_info_put(fib_work
->fen_info
.fi
);
4220 case FIB_EVENT_ENTRY_DEL
:
4221 mlxsw_sp_router_fib4_del(mlxsw_sp
, &fib_work
->fen_info
);
4222 fib_info_put(fib_work
->fen_info
.fi
);
4224 case FIB_EVENT_RULE_ADD
: /* fall through */
4225 case FIB_EVENT_RULE_DEL
:
4226 rule
= fib_work
->fr_info
.rule
;
4227 if (!fib4_rule_default(rule
) && !rule
->l3mdev
)
4228 mlxsw_sp_router_fib_abort(mlxsw_sp
);
4231 case FIB_EVENT_NH_ADD
: /* fall through */
4232 case FIB_EVENT_NH_DEL
:
4233 mlxsw_sp_nexthop4_event(mlxsw_sp
, fib_work
->event
,
4234 fib_work
->fnh_info
.fib_nh
);
4235 fib_info_put(fib_work
->fnh_info
.fib_nh
->nh_parent
);
4242 static void mlxsw_sp_router_fib6_event_work(struct work_struct
*work
)
4244 struct mlxsw_sp_fib_event_work
*fib_work
=
4245 container_of(work
, struct mlxsw_sp_fib_event_work
, work
);
4246 struct mlxsw_sp
*mlxsw_sp
= fib_work
->mlxsw_sp
;
4247 struct fib_rule
*rule
;
4252 switch (fib_work
->event
) {
4253 case FIB_EVENT_ENTRY_REPLACE
: /* fall through */
4254 case FIB_EVENT_ENTRY_ADD
:
4255 replace
= fib_work
->event
== FIB_EVENT_ENTRY_REPLACE
;
4256 err
= mlxsw_sp_router_fib6_add(mlxsw_sp
,
4257 fib_work
->fen6_info
.rt
, replace
);
4259 mlxsw_sp_router_fib_abort(mlxsw_sp
);
4260 mlxsw_sp_rt6_release(fib_work
->fen6_info
.rt
);
4262 case FIB_EVENT_ENTRY_DEL
:
4263 mlxsw_sp_router_fib6_del(mlxsw_sp
, fib_work
->fen6_info
.rt
);
4264 mlxsw_sp_rt6_release(fib_work
->fen6_info
.rt
);
4266 case FIB_EVENT_RULE_ADD
: /* fall through */
4267 case FIB_EVENT_RULE_DEL
:
4268 rule
= fib_work
->fr_info
.rule
;
4269 if (!fib6_rule_default(rule
) && !rule
->l3mdev
)
4270 mlxsw_sp_router_fib_abort(mlxsw_sp
);
4278 static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work
*fib_work
,
4279 struct fib_notifier_info
*info
)
4281 switch (fib_work
->event
) {
4282 case FIB_EVENT_ENTRY_REPLACE
: /* fall through */
4283 case FIB_EVENT_ENTRY_APPEND
: /* fall through */
4284 case FIB_EVENT_ENTRY_ADD
: /* fall through */
4285 case FIB_EVENT_ENTRY_DEL
:
4286 memcpy(&fib_work
->fen_info
, info
, sizeof(fib_work
->fen_info
));
4287 /* Take referece on fib_info to prevent it from being
4288 * freed while work is queued. Release it afterwards.
4290 fib_info_hold(fib_work
->fen_info
.fi
);
4292 case FIB_EVENT_RULE_ADD
: /* fall through */
4293 case FIB_EVENT_RULE_DEL
:
4294 memcpy(&fib_work
->fr_info
, info
, sizeof(fib_work
->fr_info
));
4295 fib_rule_get(fib_work
->fr_info
.rule
);
4297 case FIB_EVENT_NH_ADD
: /* fall through */
4298 case FIB_EVENT_NH_DEL
:
4299 memcpy(&fib_work
->fnh_info
, info
, sizeof(fib_work
->fnh_info
));
4300 fib_info_hold(fib_work
->fnh_info
.fib_nh
->nh_parent
);
4305 static void mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work
*fib_work
,
4306 struct fib_notifier_info
*info
)
4308 switch (fib_work
->event
) {
4309 case FIB_EVENT_ENTRY_REPLACE
: /* fall through */
4310 case FIB_EVENT_ENTRY_ADD
: /* fall through */
4311 case FIB_EVENT_ENTRY_DEL
:
4312 memcpy(&fib_work
->fen6_info
, info
, sizeof(fib_work
->fen6_info
));
4313 rt6_hold(fib_work
->fen6_info
.rt
);
4315 case FIB_EVENT_RULE_ADD
: /* fall through */
4316 case FIB_EVENT_RULE_DEL
:
4317 memcpy(&fib_work
->fr_info
, info
, sizeof(fib_work
->fr_info
));
4318 fib_rule_get(fib_work
->fr_info
.rule
);
4323 /* Called with rcu_read_lock() */
4324 static int mlxsw_sp_router_fib_event(struct notifier_block
*nb
,
4325 unsigned long event
, void *ptr
)
4327 struct mlxsw_sp_fib_event_work
*fib_work
;
4328 struct fib_notifier_info
*info
= ptr
;
4329 struct mlxsw_sp_router
*router
;
4331 if (!net_eq(info
->net
, &init_net
))
4334 fib_work
= kzalloc(sizeof(*fib_work
), GFP_ATOMIC
);
4335 if (WARN_ON(!fib_work
))
4338 router
= container_of(nb
, struct mlxsw_sp_router
, fib_nb
);
4339 fib_work
->mlxsw_sp
= router
->mlxsw_sp
;
4340 fib_work
->event
= event
;
4342 switch (info
->family
) {
4344 INIT_WORK(&fib_work
->work
, mlxsw_sp_router_fib4_event_work
);
4345 mlxsw_sp_router_fib4_event(fib_work
, info
);
4348 INIT_WORK(&fib_work
->work
, mlxsw_sp_router_fib6_event_work
);
4349 mlxsw_sp_router_fib6_event(fib_work
, info
);
4353 mlxsw_core_schedule_work(&fib_work
->work
);
4358 static struct mlxsw_sp_rif
*
4359 mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp
*mlxsw_sp
,
4360 const struct net_device
*dev
)
4364 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
); i
++)
4365 if (mlxsw_sp
->router
->rifs
[i
] &&
4366 mlxsw_sp
->router
->rifs
[i
]->dev
== dev
)
4367 return mlxsw_sp
->router
->rifs
[i
];
4372 static int mlxsw_sp_router_rif_disable(struct mlxsw_sp
*mlxsw_sp
, u16 rif
)
4374 char ritr_pl
[MLXSW_REG_RITR_LEN
];
4377 mlxsw_reg_ritr_rif_pack(ritr_pl
, rif
);
4378 err
= mlxsw_reg_query(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
4379 if (WARN_ON_ONCE(err
))
4382 mlxsw_reg_ritr_enable_set(ritr_pl
, false);
4383 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
4386 static void mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp
*mlxsw_sp
,
4387 struct mlxsw_sp_rif
*rif
)
4389 mlxsw_sp_router_rif_disable(mlxsw_sp
, rif
->rif_index
);
4390 mlxsw_sp_nexthop_rif_gone_sync(mlxsw_sp
, rif
);
4391 mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp
, rif
);
4395 mlxsw_sp_rif_should_config(struct mlxsw_sp_rif
*rif
, struct net_device
*dev
,
4396 unsigned long event
)
4398 struct inet6_dev
*inet6_dev
;
4399 bool addr_list_empty
= true;
4400 struct in_device
*idev
;
4406 idev
= __in_dev_get_rtnl(dev
);
4407 if (idev
&& idev
->ifa_list
)
4408 addr_list_empty
= false;
4410 inet6_dev
= __in6_dev_get(dev
);
4411 if (addr_list_empty
&& inet6_dev
&&
4412 !list_empty(&inet6_dev
->addr_list
))
4413 addr_list_empty
= false;
4415 if (rif
&& addr_list_empty
&&
4416 !netif_is_l3_slave(rif
->dev
))
4418 /* It is possible we already removed the RIF ourselves
4419 * if it was assigned to a netdev that is now a bridge
4428 static enum mlxsw_sp_rif_type
4429 mlxsw_sp_dev_rif_type(const struct mlxsw_sp
*mlxsw_sp
,
4430 const struct net_device
*dev
)
4432 enum mlxsw_sp_fid_type type
;
4434 if (mlxsw_sp_netdev_ipip_type(mlxsw_sp
, dev
, NULL
))
4435 return MLXSW_SP_RIF_TYPE_IPIP_LB
;
4437 /* Otherwise RIF type is derived from the type of the underlying FID. */
4438 if (is_vlan_dev(dev
) && netif_is_bridge_master(vlan_dev_real_dev(dev
)))
4439 type
= MLXSW_SP_FID_TYPE_8021Q
;
4440 else if (netif_is_bridge_master(dev
) && br_vlan_enabled(dev
))
4441 type
= MLXSW_SP_FID_TYPE_8021Q
;
4442 else if (netif_is_bridge_master(dev
))
4443 type
= MLXSW_SP_FID_TYPE_8021D
;
4445 type
= MLXSW_SP_FID_TYPE_RFID
;
4447 return mlxsw_sp_fid_type_rif_type(mlxsw_sp
, type
);
4450 static int mlxsw_sp_rif_index_alloc(struct mlxsw_sp
*mlxsw_sp
, u16
*p_rif_index
)
4454 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
); i
++) {
4455 if (!mlxsw_sp
->router
->rifs
[i
]) {
4464 static struct mlxsw_sp_rif
*mlxsw_sp_rif_alloc(size_t rif_size
, u16 rif_index
,
4466 struct net_device
*l3_dev
)
4468 struct mlxsw_sp_rif
*rif
;
4470 rif
= kzalloc(rif_size
, GFP_KERNEL
);
4474 INIT_LIST_HEAD(&rif
->nexthop_list
);
4475 INIT_LIST_HEAD(&rif
->neigh_list
);
4476 ether_addr_copy(rif
->addr
, l3_dev
->dev_addr
);
4477 rif
->mtu
= l3_dev
->mtu
;
4480 rif
->rif_index
= rif_index
;
4485 struct mlxsw_sp_rif
*mlxsw_sp_rif_by_index(const struct mlxsw_sp
*mlxsw_sp
,
4488 return mlxsw_sp
->router
->rifs
[rif_index
];
4491 u16
mlxsw_sp_rif_index(const struct mlxsw_sp_rif
*rif
)
4493 return rif
->rif_index
;
4496 int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif
*rif
)
4498 return rif
->dev
->ifindex
;
4501 static struct mlxsw_sp_rif
*
4502 mlxsw_sp_rif_create(struct mlxsw_sp
*mlxsw_sp
,
4503 const struct mlxsw_sp_rif_params
*params
)
4505 u32 tb_id
= l3mdev_fib_table(params
->dev
);
4506 const struct mlxsw_sp_rif_ops
*ops
;
4507 struct mlxsw_sp_fid
*fid
= NULL
;
4508 enum mlxsw_sp_rif_type type
;
4509 struct mlxsw_sp_rif
*rif
;
4510 struct mlxsw_sp_vr
*vr
;
4514 type
= mlxsw_sp_dev_rif_type(mlxsw_sp
, params
->dev
);
4515 ops
= mlxsw_sp
->router
->rif_ops_arr
[type
];
4517 vr
= mlxsw_sp_vr_get(mlxsw_sp
, tb_id
? : RT_TABLE_MAIN
);
4519 return ERR_CAST(vr
);
4521 err
= mlxsw_sp_rif_index_alloc(mlxsw_sp
, &rif_index
);
4523 goto err_rif_index_alloc
;
4525 rif
= mlxsw_sp_rif_alloc(ops
->rif_size
, rif_index
, vr
->id
, params
->dev
);
4530 rif
->mlxsw_sp
= mlxsw_sp
;
4534 fid
= ops
->fid_get(rif
);
4543 ops
->setup(rif
, params
);
4545 err
= ops
->configure(rif
);
4549 mlxsw_sp_rif_counters_alloc(rif
);
4550 mlxsw_sp
->router
->rifs
[rif_index
] = rif
;
4557 mlxsw_sp_fid_put(fid
);
4561 err_rif_index_alloc
:
4562 mlxsw_sp_vr_put(vr
);
4563 return ERR_PTR(err
);
4566 void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif
*rif
)
4568 const struct mlxsw_sp_rif_ops
*ops
= rif
->ops
;
4569 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
4570 struct mlxsw_sp_fid
*fid
= rif
->fid
;
4571 struct mlxsw_sp_vr
*vr
;
4573 mlxsw_sp_router_rif_gone_sync(mlxsw_sp
, rif
);
4574 vr
= &mlxsw_sp
->router
->vrs
[rif
->vr_id
];
4577 mlxsw_sp
->router
->rifs
[rif
->rif_index
] = NULL
;
4578 mlxsw_sp_rif_counters_free(rif
);
4579 ops
->deconfigure(rif
);
4581 /* Loopback RIFs are not associated with a FID. */
4582 mlxsw_sp_fid_put(fid
);
4584 mlxsw_sp_vr_put(vr
);
4588 mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params
*params
,
4589 struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
)
4591 struct mlxsw_sp_port
*mlxsw_sp_port
= mlxsw_sp_port_vlan
->mlxsw_sp_port
;
4593 params
->vid
= mlxsw_sp_port_vlan
->vid
;
4594 params
->lag
= mlxsw_sp_port
->lagged
;
4596 params
->lag_id
= mlxsw_sp_port
->lag_id
;
4598 params
->system_port
= mlxsw_sp_port
->local_port
;
4602 mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
,
4603 struct net_device
*l3_dev
)
4605 struct mlxsw_sp_port
*mlxsw_sp_port
= mlxsw_sp_port_vlan
->mlxsw_sp_port
;
4606 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
4607 u16 vid
= mlxsw_sp_port_vlan
->vid
;
4608 struct mlxsw_sp_rif
*rif
;
4609 struct mlxsw_sp_fid
*fid
;
4612 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, l3_dev
);
4614 struct mlxsw_sp_rif_params params
= {
4618 mlxsw_sp_rif_subport_params_init(¶ms
, mlxsw_sp_port_vlan
);
4619 rif
= mlxsw_sp_rif_create(mlxsw_sp
, ¶ms
);
4621 return PTR_ERR(rif
);
4624 /* FID was already created, just take a reference */
4625 fid
= rif
->ops
->fid_get(rif
);
4626 err
= mlxsw_sp_fid_port_vid_map(fid
, mlxsw_sp_port
, vid
);
4628 goto err_fid_port_vid_map
;
4630 err
= mlxsw_sp_port_vid_learning_set(mlxsw_sp_port
, vid
, false);
4632 goto err_port_vid_learning_set
;
4634 err
= mlxsw_sp_port_vid_stp_set(mlxsw_sp_port
, vid
,
4635 BR_STATE_FORWARDING
);
4637 goto err_port_vid_stp_set
;
4639 mlxsw_sp_port_vlan
->fid
= fid
;
4643 err_port_vid_stp_set
:
4644 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port
, vid
, true);
4645 err_port_vid_learning_set
:
4646 mlxsw_sp_fid_port_vid_unmap(fid
, mlxsw_sp_port
, vid
);
4647 err_fid_port_vid_map
:
4648 mlxsw_sp_fid_put(fid
);
4653 mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
)
4655 struct mlxsw_sp_port
*mlxsw_sp_port
= mlxsw_sp_port_vlan
->mlxsw_sp_port
;
4656 struct mlxsw_sp_fid
*fid
= mlxsw_sp_port_vlan
->fid
;
4657 u16 vid
= mlxsw_sp_port_vlan
->vid
;
4659 if (WARN_ON(mlxsw_sp_fid_type(fid
) != MLXSW_SP_FID_TYPE_RFID
))
4662 mlxsw_sp_port_vlan
->fid
= NULL
;
4663 mlxsw_sp_port_vid_stp_set(mlxsw_sp_port
, vid
, BR_STATE_BLOCKING
);
4664 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port
, vid
, true);
4665 mlxsw_sp_fid_port_vid_unmap(fid
, mlxsw_sp_port
, vid
);
4666 /* If router port holds the last reference on the rFID, then the
4667 * associated Sub-port RIF will be destroyed.
4669 mlxsw_sp_fid_put(fid
);
4672 static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device
*l3_dev
,
4673 struct net_device
*port_dev
,
4674 unsigned long event
, u16 vid
)
4676 struct mlxsw_sp_port
*mlxsw_sp_port
= netdev_priv(port_dev
);
4677 struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
;
4679 mlxsw_sp_port_vlan
= mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port
, vid
);
4680 if (WARN_ON(!mlxsw_sp_port_vlan
))
4685 return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan
,
4688 mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan
);
4695 static int mlxsw_sp_inetaddr_port_event(struct net_device
*port_dev
,
4696 unsigned long event
)
4698 if (netif_is_bridge_port(port_dev
) ||
4699 netif_is_lag_port(port_dev
) ||
4700 netif_is_ovs_port(port_dev
))
4703 return mlxsw_sp_inetaddr_port_vlan_event(port_dev
, port_dev
, event
, 1);
4706 static int __mlxsw_sp_inetaddr_lag_event(struct net_device
*l3_dev
,
4707 struct net_device
*lag_dev
,
4708 unsigned long event
, u16 vid
)
4710 struct net_device
*port_dev
;
4711 struct list_head
*iter
;
4714 netdev_for_each_lower_dev(lag_dev
, port_dev
, iter
) {
4715 if (mlxsw_sp_port_dev_check(port_dev
)) {
4716 err
= mlxsw_sp_inetaddr_port_vlan_event(l3_dev
,
4727 static int mlxsw_sp_inetaddr_lag_event(struct net_device
*lag_dev
,
4728 unsigned long event
)
4730 if (netif_is_bridge_port(lag_dev
))
4733 return __mlxsw_sp_inetaddr_lag_event(lag_dev
, lag_dev
, event
, 1);
4736 static int mlxsw_sp_inetaddr_bridge_event(struct net_device
*l3_dev
,
4737 unsigned long event
)
4739 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_lower_get(l3_dev
);
4740 struct mlxsw_sp_rif_params params
= {
4743 struct mlxsw_sp_rif
*rif
;
4747 rif
= mlxsw_sp_rif_create(mlxsw_sp
, ¶ms
);
4749 return PTR_ERR(rif
);
4752 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, l3_dev
);
4753 mlxsw_sp_rif_destroy(rif
);
4760 static int mlxsw_sp_inetaddr_vlan_event(struct net_device
*vlan_dev
,
4761 unsigned long event
)
4763 struct net_device
*real_dev
= vlan_dev_real_dev(vlan_dev
);
4764 u16 vid
= vlan_dev_vlan_id(vlan_dev
);
4766 if (netif_is_bridge_port(vlan_dev
))
4769 if (mlxsw_sp_port_dev_check(real_dev
))
4770 return mlxsw_sp_inetaddr_port_vlan_event(vlan_dev
, real_dev
,
4772 else if (netif_is_lag_master(real_dev
))
4773 return __mlxsw_sp_inetaddr_lag_event(vlan_dev
, real_dev
, event
,
4775 else if (netif_is_bridge_master(real_dev
) && br_vlan_enabled(real_dev
))
4776 return mlxsw_sp_inetaddr_bridge_event(vlan_dev
, event
);
4781 static int __mlxsw_sp_inetaddr_event(struct net_device
*dev
,
4782 unsigned long event
)
4784 if (mlxsw_sp_port_dev_check(dev
))
4785 return mlxsw_sp_inetaddr_port_event(dev
, event
);
4786 else if (netif_is_lag_master(dev
))
4787 return mlxsw_sp_inetaddr_lag_event(dev
, event
);
4788 else if (netif_is_bridge_master(dev
))
4789 return mlxsw_sp_inetaddr_bridge_event(dev
, event
);
4790 else if (is_vlan_dev(dev
))
4791 return mlxsw_sp_inetaddr_vlan_event(dev
, event
);
4796 int mlxsw_sp_inetaddr_event(struct notifier_block
*unused
,
4797 unsigned long event
, void *ptr
)
4799 struct in_ifaddr
*ifa
= (struct in_ifaddr
*) ptr
;
4800 struct net_device
*dev
= ifa
->ifa_dev
->dev
;
4801 struct mlxsw_sp
*mlxsw_sp
;
4802 struct mlxsw_sp_rif
*rif
;
4805 mlxsw_sp
= mlxsw_sp_lower_get(dev
);
4809 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, dev
);
4810 if (!mlxsw_sp_rif_should_config(rif
, dev
, event
))
4813 err
= __mlxsw_sp_inetaddr_event(dev
, event
);
4815 return notifier_from_errno(err
);
4818 struct mlxsw_sp_inet6addr_event_work
{
4819 struct work_struct work
;
4820 struct net_device
*dev
;
4821 unsigned long event
;
4824 static void mlxsw_sp_inet6addr_event_work(struct work_struct
*work
)
4826 struct mlxsw_sp_inet6addr_event_work
*inet6addr_work
=
4827 container_of(work
, struct mlxsw_sp_inet6addr_event_work
, work
);
4828 struct net_device
*dev
= inet6addr_work
->dev
;
4829 unsigned long event
= inet6addr_work
->event
;
4830 struct mlxsw_sp
*mlxsw_sp
;
4831 struct mlxsw_sp_rif
*rif
;
4834 mlxsw_sp
= mlxsw_sp_lower_get(dev
);
4838 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, dev
);
4839 if (!mlxsw_sp_rif_should_config(rif
, dev
, event
))
4842 __mlxsw_sp_inetaddr_event(dev
, event
);
4846 kfree(inet6addr_work
);
4849 /* Called with rcu_read_lock() */
4850 int mlxsw_sp_inet6addr_event(struct notifier_block
*unused
,
4851 unsigned long event
, void *ptr
)
4853 struct inet6_ifaddr
*if6
= (struct inet6_ifaddr
*) ptr
;
4854 struct mlxsw_sp_inet6addr_event_work
*inet6addr_work
;
4855 struct net_device
*dev
= if6
->idev
->dev
;
4857 if (!mlxsw_sp_port_dev_lower_find_rcu(dev
))
4860 inet6addr_work
= kzalloc(sizeof(*inet6addr_work
), GFP_ATOMIC
);
4861 if (!inet6addr_work
)
4864 INIT_WORK(&inet6addr_work
->work
, mlxsw_sp_inet6addr_event_work
);
4865 inet6addr_work
->dev
= dev
;
4866 inet6addr_work
->event
= event
;
4868 mlxsw_core_schedule_work(&inet6addr_work
->work
);
4873 static int mlxsw_sp_rif_edit(struct mlxsw_sp
*mlxsw_sp
, u16 rif_index
,
4874 const char *mac
, int mtu
)
4876 char ritr_pl
[MLXSW_REG_RITR_LEN
];
4879 mlxsw_reg_ritr_rif_pack(ritr_pl
, rif_index
);
4880 err
= mlxsw_reg_query(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
4884 mlxsw_reg_ritr_mtu_set(ritr_pl
, mtu
);
4885 mlxsw_reg_ritr_if_mac_memcpy_to(ritr_pl
, mac
);
4886 mlxsw_reg_ritr_op_set(ritr_pl
, MLXSW_REG_RITR_RIF_CREATE
);
4887 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
4890 int mlxsw_sp_netdevice_router_port_event(struct net_device
*dev
)
4892 struct mlxsw_sp
*mlxsw_sp
;
4893 struct mlxsw_sp_rif
*rif
;
4897 mlxsw_sp
= mlxsw_sp_lower_get(dev
);
4901 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, dev
);
4904 fid_index
= mlxsw_sp_fid_index(rif
->fid
);
4906 err
= mlxsw_sp_rif_fdb_op(mlxsw_sp
, rif
->addr
, fid_index
, false);
4910 err
= mlxsw_sp_rif_edit(mlxsw_sp
, rif
->rif_index
, dev
->dev_addr
,
4915 err
= mlxsw_sp_rif_fdb_op(mlxsw_sp
, dev
->dev_addr
, fid_index
, true);
4917 goto err_rif_fdb_op
;
4919 ether_addr_copy(rif
->addr
, dev
->dev_addr
);
4920 rif
->mtu
= dev
->mtu
;
4922 netdev_dbg(dev
, "Updated RIF=%d\n", rif
->rif_index
);
4927 mlxsw_sp_rif_edit(mlxsw_sp
, rif
->rif_index
, rif
->addr
, rif
->mtu
);
4929 mlxsw_sp_rif_fdb_op(mlxsw_sp
, rif
->addr
, fid_index
, true);
4933 static int mlxsw_sp_port_vrf_join(struct mlxsw_sp
*mlxsw_sp
,
4934 struct net_device
*l3_dev
)
4936 struct mlxsw_sp_rif
*rif
;
4938 /* If netdev is already associated with a RIF, then we need to
4939 * destroy it and create a new one with the new virtual router ID.
4941 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, l3_dev
);
4943 __mlxsw_sp_inetaddr_event(l3_dev
, NETDEV_DOWN
);
4945 return __mlxsw_sp_inetaddr_event(l3_dev
, NETDEV_UP
);
4948 static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp
*mlxsw_sp
,
4949 struct net_device
*l3_dev
)
4951 struct mlxsw_sp_rif
*rif
;
4953 rif
= mlxsw_sp_rif_find_by_dev(mlxsw_sp
, l3_dev
);
4956 __mlxsw_sp_inetaddr_event(l3_dev
, NETDEV_DOWN
);
4959 int mlxsw_sp_netdevice_vrf_event(struct net_device
*l3_dev
, unsigned long event
,
4960 struct netdev_notifier_changeupper_info
*info
)
4962 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_lower_get(l3_dev
);
4969 case NETDEV_PRECHANGEUPPER
:
4971 case NETDEV_CHANGEUPPER
:
4973 err
= mlxsw_sp_port_vrf_join(mlxsw_sp
, l3_dev
);
4975 mlxsw_sp_port_vrf_leave(mlxsw_sp
, l3_dev
);
4982 static struct mlxsw_sp_rif_subport
*
4983 mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif
*rif
)
4985 return container_of(rif
, struct mlxsw_sp_rif_subport
, common
);
4988 static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif
*rif
,
4989 const struct mlxsw_sp_rif_params
*params
)
4991 struct mlxsw_sp_rif_subport
*rif_subport
;
4993 rif_subport
= mlxsw_sp_rif_subport_rif(rif
);
4994 rif_subport
->vid
= params
->vid
;
4995 rif_subport
->lag
= params
->lag
;
4997 rif_subport
->lag_id
= params
->lag_id
;
4999 rif_subport
->system_port
= params
->system_port
;
5002 static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif
*rif
, bool enable
)
5004 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5005 struct mlxsw_sp_rif_subport
*rif_subport
;
5006 char ritr_pl
[MLXSW_REG_RITR_LEN
];
5008 rif_subport
= mlxsw_sp_rif_subport_rif(rif
);
5009 mlxsw_reg_ritr_pack(ritr_pl
, enable
, MLXSW_REG_RITR_SP_IF
,
5010 rif
->rif_index
, rif
->vr_id
, rif
->dev
->mtu
);
5011 mlxsw_reg_ritr_mac_pack(ritr_pl
, rif
->dev
->dev_addr
);
5012 mlxsw_reg_ritr_sp_if_pack(ritr_pl
, rif_subport
->lag
,
5013 rif_subport
->lag
? rif_subport
->lag_id
:
5014 rif_subport
->system_port
,
5017 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
5020 static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif
*rif
)
5024 err
= mlxsw_sp_rif_subport_op(rif
, true);
5028 err
= mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5029 mlxsw_sp_fid_index(rif
->fid
), true);
5031 goto err_rif_fdb_op
;
5033 mlxsw_sp_fid_rif_set(rif
->fid
, rif
);
5037 mlxsw_sp_rif_subport_op(rif
, false);
5041 static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif
*rif
)
5043 struct mlxsw_sp_fid
*fid
= rif
->fid
;
5045 mlxsw_sp_fid_rif_set(fid
, NULL
);
5046 mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5047 mlxsw_sp_fid_index(fid
), false);
5048 mlxsw_sp_rif_subport_op(rif
, false);
5051 static struct mlxsw_sp_fid
*
5052 mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif
*rif
)
5054 return mlxsw_sp_fid_rfid_get(rif
->mlxsw_sp
, rif
->rif_index
);
5057 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_subport_ops
= {
5058 .type
= MLXSW_SP_RIF_TYPE_SUBPORT
,
5059 .rif_size
= sizeof(struct mlxsw_sp_rif_subport
),
5060 .setup
= mlxsw_sp_rif_subport_setup
,
5061 .configure
= mlxsw_sp_rif_subport_configure
,
5062 .deconfigure
= mlxsw_sp_rif_subport_deconfigure
,
5063 .fid_get
= mlxsw_sp_rif_subport_fid_get
,
5066 static int mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif
*rif
,
5067 enum mlxsw_reg_ritr_if_type type
,
5068 u16 vid_fid
, bool enable
)
5070 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5071 char ritr_pl
[MLXSW_REG_RITR_LEN
];
5073 mlxsw_reg_ritr_pack(ritr_pl
, enable
, type
, rif
->rif_index
, rif
->vr_id
,
5075 mlxsw_reg_ritr_mac_pack(ritr_pl
, rif
->dev
->dev_addr
);
5076 mlxsw_reg_ritr_fid_set(ritr_pl
, type
, vid_fid
);
5078 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
5081 static u8
mlxsw_sp_router_port(const struct mlxsw_sp
*mlxsw_sp
)
5083 return mlxsw_core_max_ports(mlxsw_sp
->core
) + 1;
5086 static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif
*rif
)
5088 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5089 u16 vid
= mlxsw_sp_fid_8021q_vid(rif
->fid
);
5092 err
= mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_VLAN_IF
, vid
, true);
5096 err
= mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5097 mlxsw_sp_router_port(mlxsw_sp
), true);
5099 goto err_fid_mc_flood_set
;
5101 err
= mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5102 mlxsw_sp_router_port(mlxsw_sp
), true);
5104 goto err_fid_bc_flood_set
;
5106 err
= mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5107 mlxsw_sp_fid_index(rif
->fid
), true);
5109 goto err_rif_fdb_op
;
5111 mlxsw_sp_fid_rif_set(rif
->fid
, rif
);
5115 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5116 mlxsw_sp_router_port(mlxsw_sp
), false);
5117 err_fid_bc_flood_set
:
5118 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5119 mlxsw_sp_router_port(mlxsw_sp
), false);
5120 err_fid_mc_flood_set
:
5121 mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_VLAN_IF
, vid
, false);
5125 static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif
*rif
)
5127 u16 vid
= mlxsw_sp_fid_8021q_vid(rif
->fid
);
5128 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5129 struct mlxsw_sp_fid
*fid
= rif
->fid
;
5131 mlxsw_sp_fid_rif_set(fid
, NULL
);
5132 mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5133 mlxsw_sp_fid_index(fid
), false);
5134 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5135 mlxsw_sp_router_port(mlxsw_sp
), false);
5136 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5137 mlxsw_sp_router_port(mlxsw_sp
), false);
5138 mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_VLAN_IF
, vid
, false);
5141 static struct mlxsw_sp_fid
*
5142 mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif
*rif
)
5144 u16 vid
= is_vlan_dev(rif
->dev
) ? vlan_dev_vlan_id(rif
->dev
) : 1;
5146 return mlxsw_sp_fid_8021q_get(rif
->mlxsw_sp
, vid
);
5149 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_ops
= {
5150 .type
= MLXSW_SP_RIF_TYPE_VLAN
,
5151 .rif_size
= sizeof(struct mlxsw_sp_rif
),
5152 .configure
= mlxsw_sp_rif_vlan_configure
,
5153 .deconfigure
= mlxsw_sp_rif_vlan_deconfigure
,
5154 .fid_get
= mlxsw_sp_rif_vlan_fid_get
,
5157 static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif
*rif
)
5159 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5160 u16 fid_index
= mlxsw_sp_fid_index(rif
->fid
);
5163 err
= mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_FID_IF
, fid_index
,
5168 err
= mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5169 mlxsw_sp_router_port(mlxsw_sp
), true);
5171 goto err_fid_mc_flood_set
;
5173 err
= mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5174 mlxsw_sp_router_port(mlxsw_sp
), true);
5176 goto err_fid_bc_flood_set
;
5178 err
= mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5179 mlxsw_sp_fid_index(rif
->fid
), true);
5181 goto err_rif_fdb_op
;
5183 mlxsw_sp_fid_rif_set(rif
->fid
, rif
);
5187 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5188 mlxsw_sp_router_port(mlxsw_sp
), false);
5189 err_fid_bc_flood_set
:
5190 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5191 mlxsw_sp_router_port(mlxsw_sp
), false);
5192 err_fid_mc_flood_set
:
5193 mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_FID_IF
, fid_index
, false);
5197 static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif
*rif
)
5199 u16 fid_index
= mlxsw_sp_fid_index(rif
->fid
);
5200 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5201 struct mlxsw_sp_fid
*fid
= rif
->fid
;
5203 mlxsw_sp_fid_rif_set(fid
, NULL
);
5204 mlxsw_sp_rif_fdb_op(rif
->mlxsw_sp
, rif
->dev
->dev_addr
,
5205 mlxsw_sp_fid_index(fid
), false);
5206 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_BC
,
5207 mlxsw_sp_router_port(mlxsw_sp
), false);
5208 mlxsw_sp_fid_flood_set(rif
->fid
, MLXSW_SP_FLOOD_TYPE_MC
,
5209 mlxsw_sp_router_port(mlxsw_sp
), false);
5210 mlxsw_sp_rif_vlan_fid_op(rif
, MLXSW_REG_RITR_FID_IF
, fid_index
, false);
5213 static struct mlxsw_sp_fid
*
5214 mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif
*rif
)
5216 return mlxsw_sp_fid_8021d_get(rif
->mlxsw_sp
, rif
->dev
->ifindex
);
5219 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops
= {
5220 .type
= MLXSW_SP_RIF_TYPE_FID
,
5221 .rif_size
= sizeof(struct mlxsw_sp_rif
),
5222 .configure
= mlxsw_sp_rif_fid_configure
,
5223 .deconfigure
= mlxsw_sp_rif_fid_deconfigure
,
5224 .fid_get
= mlxsw_sp_rif_fid_fid_get
,
5227 static struct mlxsw_sp_rif_ipip_lb
*
5228 mlxsw_sp_rif_ipip_lb_rif(struct mlxsw_sp_rif
*rif
)
5230 return container_of(rif
, struct mlxsw_sp_rif_ipip_lb
, common
);
5234 mlxsw_sp_rif_ipip_lb_setup(struct mlxsw_sp_rif
*rif
,
5235 const struct mlxsw_sp_rif_params
*params
)
5237 struct mlxsw_sp_rif_params_ipip_lb
*params_lb
;
5238 struct mlxsw_sp_rif_ipip_lb
*rif_lb
;
5240 params_lb
= container_of(params
, struct mlxsw_sp_rif_params_ipip_lb
,
5242 rif_lb
= mlxsw_sp_rif_ipip_lb_rif(rif
);
5243 rif_lb
->lb_config
= params_lb
->lb_config
;
5247 mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb
*lb_rif
,
5248 struct mlxsw_sp_vr
*ul_vr
, bool enable
)
5250 struct mlxsw_sp_rif_ipip_lb_config lb_cf
= lb_rif
->lb_config
;
5251 struct mlxsw_sp_rif
*rif
= &lb_rif
->common
;
5252 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5253 char ritr_pl
[MLXSW_REG_RITR_LEN
];
5256 switch (lb_cf
.ul_protocol
) {
5257 case MLXSW_SP_L3_PROTO_IPV4
:
5258 saddr4
= be32_to_cpu(lb_cf
.saddr
.addr4
);
5259 mlxsw_reg_ritr_pack(ritr_pl
, enable
, MLXSW_REG_RITR_LOOPBACK_IF
,
5260 rif
->rif_index
, rif
->vr_id
, rif
->dev
->mtu
);
5261 mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl
, lb_cf
.lb_ipipt
,
5262 MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET
,
5263 ul_vr
->id
, saddr4
, lb_cf
.okey
);
5266 case MLXSW_SP_L3_PROTO_IPV6
:
5267 return -EAFNOSUPPORT
;
5270 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ritr
), ritr_pl
);
5274 mlxsw_sp_rif_ipip_lb_configure(struct mlxsw_sp_rif
*rif
)
5276 struct mlxsw_sp_rif_ipip_lb
*lb_rif
= mlxsw_sp_rif_ipip_lb_rif(rif
);
5277 u32 ul_tb_id
= mlxsw_sp_ipip_dev_ul_tb_id(rif
->dev
);
5278 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5279 struct mlxsw_sp_vr
*ul_vr
;
5282 ul_vr
= mlxsw_sp_vr_get(mlxsw_sp
, ul_tb_id
);
5284 return PTR_ERR(ul_vr
);
5286 err
= mlxsw_sp_rif_ipip_lb_op(lb_rif
, ul_vr
, true);
5288 goto err_loopback_op
;
5290 lb_rif
->ul_vr_id
= ul_vr
->id
;
5295 mlxsw_sp_vr_put(ul_vr
);
5299 static void mlxsw_sp_rif_ipip_lb_deconfigure(struct mlxsw_sp_rif
*rif
)
5301 struct mlxsw_sp_rif_ipip_lb
*lb_rif
= mlxsw_sp_rif_ipip_lb_rif(rif
);
5302 struct mlxsw_sp
*mlxsw_sp
= rif
->mlxsw_sp
;
5303 struct mlxsw_sp_vr
*ul_vr
;
5305 ul_vr
= &mlxsw_sp
->router
->vrs
[lb_rif
->ul_vr_id
];
5306 mlxsw_sp_rif_ipip_lb_op(lb_rif
, ul_vr
, false);
5309 mlxsw_sp_vr_put(ul_vr
);
5312 static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_ipip_lb_ops
= {
5313 .type
= MLXSW_SP_RIF_TYPE_IPIP_LB
,
5314 .rif_size
= sizeof(struct mlxsw_sp_rif_ipip_lb
),
5315 .setup
= mlxsw_sp_rif_ipip_lb_setup
,
5316 .configure
= mlxsw_sp_rif_ipip_lb_configure
,
5317 .deconfigure
= mlxsw_sp_rif_ipip_lb_deconfigure
,
5320 static const struct mlxsw_sp_rif_ops
*mlxsw_sp_rif_ops_arr
[] = {
5321 [MLXSW_SP_RIF_TYPE_SUBPORT
] = &mlxsw_sp_rif_subport_ops
,
5322 [MLXSW_SP_RIF_TYPE_VLAN
] = &mlxsw_sp_rif_vlan_ops
,
5323 [MLXSW_SP_RIF_TYPE_FID
] = &mlxsw_sp_rif_fid_ops
,
5324 [MLXSW_SP_RIF_TYPE_IPIP_LB
] = &mlxsw_sp_rif_ipip_lb_ops
,
5327 static int mlxsw_sp_rifs_init(struct mlxsw_sp
*mlxsw_sp
)
5329 u64 max_rifs
= MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
);
5331 mlxsw_sp
->router
->rifs
= kcalloc(max_rifs
,
5332 sizeof(struct mlxsw_sp_rif
*),
5334 if (!mlxsw_sp
->router
->rifs
)
5337 mlxsw_sp
->router
->rif_ops_arr
= mlxsw_sp_rif_ops_arr
;
5342 static void mlxsw_sp_rifs_fini(struct mlxsw_sp
*mlxsw_sp
)
5346 for (i
= 0; i
< MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
); i
++)
5347 WARN_ON_ONCE(mlxsw_sp
->router
->rifs
[i
]);
5349 kfree(mlxsw_sp
->router
->rifs
);
5352 static int mlxsw_sp_ipips_init(struct mlxsw_sp
*mlxsw_sp
)
5354 mlxsw_sp
->router
->ipip_ops_arr
= mlxsw_sp_ipip_ops_arr
;
5358 static void mlxsw_sp_ipips_fini(struct mlxsw_sp
*mlxsw_sp
)
5362 static void mlxsw_sp_router_fib_dump_flush(struct notifier_block
*nb
)
5364 struct mlxsw_sp_router
*router
;
5366 /* Flush pending FIB notifications and then flush the device's
5367 * table before requesting another dump. The FIB notification
5368 * block is unregistered, so no need to take RTNL.
5370 mlxsw_core_flush_owq();
5371 router
= container_of(nb
, struct mlxsw_sp_router
, fib_nb
);
5372 mlxsw_sp_router_fib_flush(router
->mlxsw_sp
);
5375 static int __mlxsw_sp_router_init(struct mlxsw_sp
*mlxsw_sp
)
5377 char rgcr_pl
[MLXSW_REG_RGCR_LEN
];
5381 if (!MLXSW_CORE_RES_VALID(mlxsw_sp
->core
, MAX_RIFS
))
5383 max_rifs
= MLXSW_CORE_RES_GET(mlxsw_sp
->core
, MAX_RIFS
);
5385 mlxsw_reg_rgcr_pack(rgcr_pl
, true, true);
5386 mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl
, max_rifs
);
5387 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(rgcr
), rgcr_pl
);
5393 static void __mlxsw_sp_router_fini(struct mlxsw_sp
*mlxsw_sp
)
5395 char rgcr_pl
[MLXSW_REG_RGCR_LEN
];
5397 mlxsw_reg_rgcr_pack(rgcr_pl
, false, false);
5398 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(rgcr
), rgcr_pl
);
5401 int mlxsw_sp_router_init(struct mlxsw_sp
*mlxsw_sp
)
5403 struct mlxsw_sp_router
*router
;
5406 router
= kzalloc(sizeof(*mlxsw_sp
->router
), GFP_KERNEL
);
5409 mlxsw_sp
->router
= router
;
5410 router
->mlxsw_sp
= mlxsw_sp
;
5412 INIT_LIST_HEAD(&mlxsw_sp
->router
->nexthop_neighs_list
);
5413 err
= __mlxsw_sp_router_init(mlxsw_sp
);
5415 goto err_router_init
;
5417 err
= mlxsw_sp_rifs_init(mlxsw_sp
);
5421 err
= mlxsw_sp_ipips_init(mlxsw_sp
);
5423 goto err_ipips_init
;
5425 err
= rhashtable_init(&mlxsw_sp
->router
->nexthop_ht
,
5426 &mlxsw_sp_nexthop_ht_params
);
5428 goto err_nexthop_ht_init
;
5430 err
= rhashtable_init(&mlxsw_sp
->router
->nexthop_group_ht
,
5431 &mlxsw_sp_nexthop_group_ht_params
);
5433 goto err_nexthop_group_ht_init
;
5435 err
= mlxsw_sp_lpm_init(mlxsw_sp
);
5439 err
= mlxsw_sp_vrs_init(mlxsw_sp
);
5443 err
= mlxsw_sp_neigh_init(mlxsw_sp
);
5445 goto err_neigh_init
;
5447 mlxsw_sp
->router
->fib_nb
.notifier_call
= mlxsw_sp_router_fib_event
;
5448 err
= register_fib_notifier(&mlxsw_sp
->router
->fib_nb
,
5449 mlxsw_sp_router_fib_dump_flush
);
5451 goto err_register_fib_notifier
;
5455 err_register_fib_notifier
:
5456 mlxsw_sp_neigh_fini(mlxsw_sp
);
5458 mlxsw_sp_vrs_fini(mlxsw_sp
);
5460 mlxsw_sp_lpm_fini(mlxsw_sp
);
5462 rhashtable_destroy(&mlxsw_sp
->router
->nexthop_group_ht
);
5463 err_nexthop_group_ht_init
:
5464 rhashtable_destroy(&mlxsw_sp
->router
->nexthop_ht
);
5465 err_nexthop_ht_init
:
5466 mlxsw_sp_ipips_fini(mlxsw_sp
);
5468 mlxsw_sp_rifs_fini(mlxsw_sp
);
5470 __mlxsw_sp_router_fini(mlxsw_sp
);
5472 kfree(mlxsw_sp
->router
);
5476 void mlxsw_sp_router_fini(struct mlxsw_sp
*mlxsw_sp
)
5478 unregister_fib_notifier(&mlxsw_sp
->router
->fib_nb
);
5479 mlxsw_sp_neigh_fini(mlxsw_sp
);
5480 mlxsw_sp_vrs_fini(mlxsw_sp
);
5481 mlxsw_sp_lpm_fini(mlxsw_sp
);
5482 rhashtable_destroy(&mlxsw_sp
->router
->nexthop_group_ht
);
5483 rhashtable_destroy(&mlxsw_sp
->router
->nexthop_ht
);
5484 mlxsw_sp_ipips_fini(mlxsw_sp
);
5485 mlxsw_sp_rifs_fini(mlxsw_sp
);
5486 __mlxsw_sp_router_fini(mlxsw_sp
);
5487 kfree(mlxsw_sp
->router
);