Commit 35c35692 authored by Ido Schimmel's avatar Ido Schimmel Committed by Jakub Kicinski

mlxsw: spectrum: Fix incorrect parsing depth after reload

Spectrum ASICs have a configurable limit on how deep into the packet
they parse. By default, the limit is 96 bytes.

There are several cases where this parsing depth is not enough and there
is a need to increase it. For example, timestamping of PTP packets and a
FIB multipath hash policy that requires hashing on inner fields. The
driver therefore maintains a reference count that reflects the number of
consumers that require an increased parsing depth.

During reload_down() the parsing depth reference count does not
necessarily drop to zero, but the parsing depth itself is restored to
the default during reload_up() when the firmware is reset. It is
therefore possible to end up in situations where the driver thinks that
the parsing depth was increased (reference count is non-zero), when it
is not.

Fix by making sure that all the consumers that increase the parsing
depth reference count also decrease it during reload_down().
Specifically, make sure that when the routing code is de-initialized it
drops the reference count if it was increased because of a FIB multipath
hash policy that requires hashing on inner fields.

Add a warning if the reference count is not zero after the driver was
de-initialized and explicitly reset it to zero during initialization for
good measures.

Fixes: 2d91f080 ("mlxsw: spectrum: Add infrastructure for parsing configuration")
Reported-by: default avatarMaksym Yaremchuk <maksymy@nvidia.com>
Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarPetr Machata <petrm@nvidia.com>
Link: https://lore.kernel.org/r/9c35e1b3e6c1d8f319a2449d14e2b86373f3b3ba.1678727526.git.petrm@nvidia.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 5ce76fe1
...@@ -2937,6 +2937,7 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *unused, ...@@ -2937,6 +2937,7 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
static void mlxsw_sp_parsing_init(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp_parsing_init(struct mlxsw_sp *mlxsw_sp)
{ {
refcount_set(&mlxsw_sp->parsing.parsing_depth_ref, 0);
mlxsw_sp->parsing.parsing_depth = MLXSW_SP_DEFAULT_PARSING_DEPTH; mlxsw_sp->parsing.parsing_depth = MLXSW_SP_DEFAULT_PARSING_DEPTH;
mlxsw_sp->parsing.vxlan_udp_dport = MLXSW_SP_DEFAULT_VXLAN_UDP_DPORT; mlxsw_sp->parsing.vxlan_udp_dport = MLXSW_SP_DEFAULT_VXLAN_UDP_DPORT;
mutex_init(&mlxsw_sp->parsing.lock); mutex_init(&mlxsw_sp->parsing.lock);
...@@ -2945,6 +2946,7 @@ static void mlxsw_sp_parsing_init(struct mlxsw_sp *mlxsw_sp) ...@@ -2945,6 +2946,7 @@ static void mlxsw_sp_parsing_init(struct mlxsw_sp *mlxsw_sp)
static void mlxsw_sp_parsing_fini(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp_parsing_fini(struct mlxsw_sp *mlxsw_sp)
{ {
mutex_destroy(&mlxsw_sp->parsing.lock); mutex_destroy(&mlxsw_sp->parsing.lock);
WARN_ON_ONCE(refcount_read(&mlxsw_sp->parsing.parsing_depth_ref));
} }
struct mlxsw_sp_ipv6_addr_node { struct mlxsw_sp_ipv6_addr_node {
......
...@@ -10381,11 +10381,23 @@ static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp) ...@@ -10381,11 +10381,23 @@ static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp)
old_inc_parsing_depth); old_inc_parsing_depth);
return err; return err;
} }
static void mlxsw_sp_mp_hash_fini(struct mlxsw_sp *mlxsw_sp)
{
bool old_inc_parsing_depth = mlxsw_sp->router->inc_parsing_depth;
mlxsw_sp_mp_hash_parsing_depth_adjust(mlxsw_sp, old_inc_parsing_depth,
false);
}
#else #else
static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp)
{ {
return 0; return 0;
} }
static void mlxsw_sp_mp_hash_fini(struct mlxsw_sp *mlxsw_sp)
{
}
#endif #endif
static int mlxsw_sp_dscp_init(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_dscp_init(struct mlxsw_sp *mlxsw_sp)
...@@ -10615,6 +10627,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, ...@@ -10615,6 +10627,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
err_register_inetaddr_notifier: err_register_inetaddr_notifier:
mlxsw_core_flush_owq(); mlxsw_core_flush_owq();
err_dscp_init: err_dscp_init:
mlxsw_sp_mp_hash_fini(mlxsw_sp);
err_mp_hash_init: err_mp_hash_init:
mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_neigh_fini(mlxsw_sp);
err_neigh_init: err_neigh_init:
...@@ -10655,6 +10668,7 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) ...@@ -10655,6 +10668,7 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
unregister_inet6addr_notifier(&mlxsw_sp->router->inet6addr_nb); unregister_inet6addr_notifier(&mlxsw_sp->router->inet6addr_nb);
unregister_inetaddr_notifier(&mlxsw_sp->router->inetaddr_nb); unregister_inetaddr_notifier(&mlxsw_sp->router->inetaddr_nb);
mlxsw_core_flush_owq(); mlxsw_core_flush_owq();
mlxsw_sp_mp_hash_fini(mlxsw_sp);
mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_neigh_fini(mlxsw_sp);
mlxsw_sp_lb_rif_fini(mlxsw_sp); mlxsw_sp_lb_rif_fini(mlxsw_sp);
mlxsw_sp_vrs_fini(mlxsw_sp); mlxsw_sp_vrs_fini(mlxsw_sp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment