Skip to content

Commit 0a7fd1a

Browse files
idoschdavem330
authored andcommitted
mlxsw: spectrum_router: Add support for route replace
In case we got a replace event, then the replaced route must exist. If the route isn't capable of multipath, then replace first matching non-multipath capable route. If the route is capable of multipath and matching multipath capable route is found, then replace it. Otherwise, replace first matching non-multipath capable route. The new route is inserted before the replaced one. In case the replaced route is currently offloaded, then it's overwritten in the device's table by the new route and later deleted, thus not impacting routed traffic. Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 428b851 commit 0a7fd1a

File tree

1 file changed

+49
-14
lines changed

1 file changed

+49
-14
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3035,11 +3035,11 @@ mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry)
30353035

30363036
static struct mlxsw_sp_fib6_entry *
30373037
mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node,
3038-
const struct rt6_info *nrt)
3038+
const struct rt6_info *nrt, bool replace)
30393039
{
30403040
struct mlxsw_sp_fib6_entry *fib6_entry;
30413041

3042-
if (!mlxsw_sp_fib6_rt_can_mp(nrt))
3042+
if (!mlxsw_sp_fib6_rt_can_mp(nrt) || replace)
30433043
return NULL;
30443044

30453045
list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) {
@@ -3371,9 +3371,9 @@ static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp *mlxsw_sp,
33713371

33723372
static struct mlxsw_sp_fib6_entry *
33733373
mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
3374-
const struct rt6_info *nrt)
3374+
const struct rt6_info *nrt, bool replace)
33753375
{
3376-
struct mlxsw_sp_fib6_entry *fib6_entry;
3376+
struct mlxsw_sp_fib6_entry *fib6_entry, *fallback = NULL;
33773377

33783378
list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) {
33793379
struct rt6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
@@ -3382,21 +3382,32 @@ mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
33823382
continue;
33833383
if (rt->rt6i_table->tb6_id != nrt->rt6i_table->tb6_id)
33843384
break;
3385+
if (replace && rt->rt6i_metric == nrt->rt6i_metric) {
3386+
if (mlxsw_sp_fib6_rt_can_mp(rt) ==
3387+
mlxsw_sp_fib6_rt_can_mp(nrt))
3388+
return fib6_entry;
3389+
if (mlxsw_sp_fib6_rt_can_mp(nrt))
3390+
fallback = fallback ?: fib6_entry;
3391+
}
33853392
if (rt->rt6i_metric > nrt->rt6i_metric)
3386-
return fib6_entry;
3393+
return fallback ?: fib6_entry;
33873394
}
33883395

3389-
return NULL;
3396+
return fallback;
33903397
}
33913398

33923399
static int
3393-
mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry *new6_entry)
3400+
mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry *new6_entry,
3401+
bool replace)
33943402
{
33953403
struct mlxsw_sp_fib_node *fib_node = new6_entry->common.fib_node;
33963404
struct rt6_info *nrt = mlxsw_sp_fib6_entry_rt(new6_entry);
33973405
struct mlxsw_sp_fib6_entry *fib6_entry;
33983406

3399-
fib6_entry = mlxsw_sp_fib6_node_entry_find(fib_node, nrt);
3407+
fib6_entry = mlxsw_sp_fib6_node_entry_find(fib_node, nrt, replace);
3408+
3409+
if (replace && WARN_ON(!fib6_entry))
3410+
return -EINVAL;
34003411

34013412
if (fib6_entry) {
34023413
list_add_tail(&new6_entry->common.list,
@@ -3430,11 +3441,12 @@ mlxsw_sp_fib6_node_list_remove(struct mlxsw_sp_fib6_entry *fib6_entry)
34303441
}
34313442

34323443
static int mlxsw_sp_fib6_node_entry_link(struct mlxsw_sp *mlxsw_sp,
3433-
struct mlxsw_sp_fib6_entry *fib6_entry)
3444+
struct mlxsw_sp_fib6_entry *fib6_entry,
3445+
bool replace)
34343446
{
34353447
int err;
34363448

3437-
err = mlxsw_sp_fib6_node_list_insert(fib6_entry);
3449+
err = mlxsw_sp_fib6_node_list_insert(fib6_entry, replace);
34383450
if (err)
34393451
return err;
34403452

@@ -3489,8 +3501,25 @@ mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp,
34893501
return NULL;
34903502
}
34913503

3504+
static void mlxsw_sp_fib6_entry_replace(struct mlxsw_sp *mlxsw_sp,
3505+
struct mlxsw_sp_fib6_entry *fib6_entry,
3506+
bool replace)
3507+
{
3508+
struct mlxsw_sp_fib_node *fib_node = fib6_entry->common.fib_node;
3509+
struct mlxsw_sp_fib6_entry *replaced;
3510+
3511+
if (!replace)
3512+
return;
3513+
3514+
replaced = list_next_entry(fib6_entry, common.list);
3515+
3516+
mlxsw_sp_fib6_node_entry_unlink(mlxsw_sp, replaced);
3517+
mlxsw_sp_fib6_entry_destroy(mlxsw_sp, replaced);
3518+
mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
3519+
}
3520+
34923521
static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
3493-
struct rt6_info *rt)
3522+
struct rt6_info *rt, bool replace)
34943523
{
34953524
struct mlxsw_sp_fib6_entry *fib6_entry;
34963525
struct mlxsw_sp_fib_node *fib_node;
@@ -3513,7 +3542,7 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
35133542
/* Before creating a new entry, try to append route to an existing
35143543
* multipath entry.
35153544
*/
3516-
fib6_entry = mlxsw_sp_fib6_node_mp_entry_find(fib_node, rt);
3545+
fib6_entry = mlxsw_sp_fib6_node_mp_entry_find(fib_node, rt, replace);
35173546
if (fib6_entry) {
35183547
err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt);
35193548
if (err)
@@ -3527,10 +3556,12 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
35273556
goto err_fib6_entry_create;
35283557
}
35293558

3530-
err = mlxsw_sp_fib6_node_entry_link(mlxsw_sp, fib6_entry);
3559+
err = mlxsw_sp_fib6_node_entry_link(mlxsw_sp, fib6_entry, replace);
35313560
if (err)
35323561
goto err_fib6_node_entry_link;
35333562

3563+
mlxsw_sp_fib6_entry_replace(mlxsw_sp, fib6_entry, replace);
3564+
35343565
return 0;
35353566

35363567
err_fib6_node_entry_link:
@@ -3795,13 +3826,16 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
37953826
container_of(work, struct mlxsw_sp_fib_event_work, work);
37963827
struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
37973828
struct fib_rule *rule;
3829+
bool replace;
37983830
int err;
37993831

38003832
rtnl_lock();
38013833
switch (fib_work->event) {
3834+
case FIB_EVENT_ENTRY_REPLACE: /* fall through */
38023835
case FIB_EVENT_ENTRY_ADD:
3836+
replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
38033837
err = mlxsw_sp_router_fib6_add(mlxsw_sp,
3804-
fib_work->fen6_info.rt);
3838+
fib_work->fen6_info.rt, replace);
38053839
if (err)
38063840
mlxsw_sp_router_fib_abort(mlxsw_sp);
38073841
mlxsw_sp_rt6_release(fib_work->fen6_info.rt);
@@ -3853,6 +3887,7 @@ static void mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work,
38533887
struct fib_notifier_info *info)
38543888
{
38553889
switch (fib_work->event) {
3890+
case FIB_EVENT_ENTRY_REPLACE: /* fall through */
38563891
case FIB_EVENT_ENTRY_ADD: /* fall through */
38573892
case FIB_EVENT_ENTRY_DEL:
38583893
memcpy(&fib_work->fen6_info, info, sizeof(fib_work->fen6_info));

0 commit comments

Comments
 (0)