diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 27b632cac991d4355e7e3b1c3a25781c2b06c225..9fe4cdb231899fef9bf04f9581891ce75f7ab74a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -5234,7 +5234,6 @@ static void mlxsw_sp_router_fib4_event_work(struct work_struct *work) struct mlxsw_sp_fib_event_work *fib_work = container_of(work, struct mlxsw_sp_fib_event_work, work); struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp; - struct fib_rule *rule; bool replace, append; int err; @@ -5256,12 +5255,11 @@ static void mlxsw_sp_router_fib4_event_work(struct work_struct *work) mlxsw_sp_router_fib4_del(mlxsw_sp, &fib_work->fen_info); fib_info_put(fib_work->fen_info.fi); break; - case FIB_EVENT_RULE_ADD: /* fall through */ - case FIB_EVENT_RULE_DEL: - rule = fib_work->fr_info.rule; - if (!fib4_rule_default(rule) && !rule->l3mdev) - mlxsw_sp_router_fib_abort(mlxsw_sp); - fib_rule_put(rule); + case FIB_EVENT_RULE_ADD: + /* if we get here, a rule was added that we do not support. + * just do the fib_abort + */ + mlxsw_sp_router_fib_abort(mlxsw_sp); break; case FIB_EVENT_NH_ADD: /* fall through */ case FIB_EVENT_NH_DEL: @@ -5279,7 +5277,6 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work) struct mlxsw_sp_fib_event_work *fib_work = container_of(work, struct mlxsw_sp_fib_event_work, work); struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp; - struct fib_rule *rule; bool replace; int err; @@ -5298,12 +5295,11 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work) mlxsw_sp_router_fib6_del(mlxsw_sp, fib_work->fen6_info.rt); mlxsw_sp_rt6_release(fib_work->fen6_info.rt); break; - case FIB_EVENT_RULE_ADD: /* fall through */ - case FIB_EVENT_RULE_DEL: - rule = fib_work->fr_info.rule; - if (!fib6_rule_default(rule) && !rule->l3mdev) - mlxsw_sp_router_fib_abort(mlxsw_sp); - fib_rule_put(rule); + case FIB_EVENT_RULE_ADD: + /* if we get here, a rule was added that we do not support. + * just do the fib_abort + */ + mlxsw_sp_router_fib_abort(mlxsw_sp); break; } rtnl_unlock(); @@ -5315,7 +5311,6 @@ static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work) struct mlxsw_sp_fib_event_work *fib_work = container_of(work, struct mlxsw_sp_fib_event_work, work); struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp; - struct fib_rule *rule; bool replace; int err; @@ -5347,12 +5342,11 @@ static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work) &fib_work->ven_info); dev_put(fib_work->ven_info.dev); break; - case FIB_EVENT_RULE_ADD: /* fall through */ - case FIB_EVENT_RULE_DEL: - rule = fib_work->fr_info.rule; - if (!ipmr_rule_default(rule) && !rule->l3mdev) - mlxsw_sp_router_fib_abort(mlxsw_sp); - fib_rule_put(rule); + case FIB_EVENT_RULE_ADD: + /* if we get here, a rule was added that we do not support. + * just do the fib_abort + */ + mlxsw_sp_router_fib_abort(mlxsw_sp); break; } rtnl_unlock(); @@ -5363,7 +5357,6 @@ static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work *fib_work, struct fib_notifier_info *info) { struct fib_entry_notifier_info *fen_info; - struct fib_rule_notifier_info *fr_info; struct fib_nh_notifier_info *fnh_info; switch (fib_work->event) { @@ -5379,13 +5372,6 @@ static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work *fib_work, */ fib_info_hold(fib_work->fen_info.fi); break; - case FIB_EVENT_RULE_ADD: /* fall through */ - case FIB_EVENT_RULE_DEL: - fr_info = container_of(info, struct fib_rule_notifier_info, - info); - fib_work->fr_info = *fr_info; - fib_rule_get(fib_work->fr_info.rule); - break; case FIB_EVENT_NH_ADD: /* fall through */ case FIB_EVENT_NH_DEL: fnh_info = container_of(info, struct fib_nh_notifier_info, @@ -5400,7 +5386,6 @@ static void mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work, struct fib_notifier_info *info) { struct fib6_entry_notifier_info *fen6_info; - struct fib_rule_notifier_info *fr_info; switch (fib_work->event) { case FIB_EVENT_ENTRY_REPLACE: /* fall through */ @@ -5411,13 +5396,6 @@ static void mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work, fib_work->fen6_info = *fen6_info; rt6_hold(fib_work->fen6_info.rt); break; - case FIB_EVENT_RULE_ADD: /* fall through */ - case FIB_EVENT_RULE_DEL: - fr_info = container_of(info, struct fib_rule_notifier_info, - info); - fib_work->fr_info = *fr_info; - fib_rule_get(fib_work->fr_info.rule); - break; } } @@ -5437,12 +5415,47 @@ mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event_work *fib_work, memcpy(&fib_work->ven_info, info, sizeof(fib_work->ven_info)); dev_hold(fib_work->ven_info.dev); break; - case FIB_EVENT_RULE_ADD: /* fall through */ - case FIB_EVENT_RULE_DEL: - memcpy(&fib_work->fr_info, info, sizeof(fib_work->fr_info)); - fib_rule_get(fib_work->fr_info.rule); + } +} + +static int mlxsw_sp_router_fib_rule_event(unsigned long event, + struct fib_notifier_info *info, + struct mlxsw_sp *mlxsw_sp) +{ + struct netlink_ext_ack *extack = info->extack; + struct fib_rule_notifier_info *fr_info; + struct fib_rule *rule; + int err = 0; + + /* nothing to do at the moment */ + if (event == FIB_EVENT_RULE_DEL) + return 0; + + if (mlxsw_sp->router->aborted) + return 0; + + fr_info = container_of(info, struct fib_rule_notifier_info, info); + rule = fr_info->rule; + + switch (info->family) { + case AF_INET: + if (!fib4_rule_default(rule) && !rule->l3mdev) + err = -1; + break; + case AF_INET6: + if (!fib6_rule_default(rule) && !rule->l3mdev) + err = -1; + break; + case RTNL_FAMILY_IPMR: + if (!ipmr_rule_default(rule) && !rule->l3mdev) + err = -1; break; } + + if (err < 0) + NL_SET_ERR_MSG(extack, "spectrum: FIB rules not supported. Aborting offload"); + + return err; } /* Called with rcu_read_lock() */ @@ -5452,17 +5465,28 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb, struct mlxsw_sp_fib_event_work *fib_work; struct fib_notifier_info *info = ptr; struct mlxsw_sp_router *router; + int err; if (!net_eq(info->net, &init_net) || (info->family != AF_INET && info->family != AF_INET6 && info->family != RTNL_FAMILY_IPMR)) return NOTIFY_DONE; + router = container_of(nb, struct mlxsw_sp_router, fib_nb); + + switch (event) { + case FIB_EVENT_RULE_ADD: /* fall through */ + case FIB_EVENT_RULE_DEL: + err = mlxsw_sp_router_fib_rule_event(event, info, + router->mlxsw_sp); + if (!err) + return NOTIFY_DONE; + } + fib_work = kzalloc(sizeof(*fib_work), GFP_ATOMIC); if (WARN_ON(!fib_work)) return NOTIFY_BAD; - router = container_of(nb, struct mlxsw_sp_router, fib_nb); fib_work->mlxsw_sp = router->mlxsw_sp; fib_work->event = event;