Merge branch 'mlxsw-Various-fixes'

Ido Schimmel says:

====================
mlxsw: Various fixes

This patch set contains various fixes for the mlxsw driver.

Patch #1 fixes an issue introduced in 5.6 in which a route in the main
table can replace an identical route in the local table despite the
local table having an higher precedence.

Patch #2 contains a test case for the bug fixed in patch #1.

Patch #3 also fixes an issue introduced in 5.6 in which the driver
failed to clear the offload indication from IPv6 nexthops upon abort.

Patch #4 fixes an issue that prevents the driver from loading on
Spectrum-3 systems. The problem and solution are explained in detail in
the commit message.

Patch #5 adds a missing error path. Discovered using smatch.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-02-07 18:47:01 +01:00
commit e036c587ca
5 changed files with 142 additions and 6 deletions

View File

@ -573,6 +573,7 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon)
static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon)
{
enum mlxsw_reg_mgpir_device_type device_type;
int index, max_index, sensor_index;
char mgpir_pl[MLXSW_REG_MGPIR_LEN];
char mtmp_pl[MLXSW_REG_MTMP_LEN];
@ -584,8 +585,9 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon)
if (err)
return err;
mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL, NULL);
if (!gbox_num)
mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, NULL);
if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE ||
!gbox_num)
return 0;
index = mlxsw_hwmon->module_sensor_max;

View File

@ -895,8 +895,10 @@ static int
mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
struct mlxsw_thermal *thermal)
{
enum mlxsw_reg_mgpir_device_type device_type;
struct mlxsw_thermal_module *gearbox_tz;
char mgpir_pl[MLXSW_REG_MGPIR_LEN];
u8 gbox_num;
int i;
int err;
@ -908,11 +910,13 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
if (err)
return err;
mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL,
mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL,
NULL);
if (!thermal->tz_gearbox_num)
if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE ||
!gbox_num)
return 0;
thermal->tz_gearbox_num = gbox_num;
thermal->tz_gearbox_arr = kcalloc(thermal->tz_gearbox_num,
sizeof(*thermal->tz_gearbox_arr),
GFP_KERNEL);

View File

@ -215,7 +215,7 @@ mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
start_again:
err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
if (err)
return err;
goto err_ctx_prepare;
j = 0;
for (; i < rif_count; i++) {
struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i);
@ -247,6 +247,7 @@ mlxsw_sp_dpipe_table_erif_entries_dump(void *priv, bool counters_enabled,
return 0;
err_entry_append:
err_entry_get:
err_ctx_prepare:
rtnl_unlock();
devlink_dpipe_entry_clear(&entry);
return err;

View File

@ -4844,6 +4844,23 @@ mlxsw_sp_fib_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
fib_node->fib_entry = NULL;
}
static bool mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry *fib4_entry)
{
struct mlxsw_sp_fib_node *fib_node = fib4_entry->common.fib_node;
struct mlxsw_sp_fib4_entry *fib4_replaced;
if (!fib_node->fib_entry)
return true;
fib4_replaced = container_of(fib_node->fib_entry,
struct mlxsw_sp_fib4_entry, common);
if (fib4_entry->tb_id == RT_TABLE_MAIN &&
fib4_replaced->tb_id == RT_TABLE_LOCAL)
return false;
return true;
}
static int
mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
const struct fib_entry_notifier_info *fen_info)
@ -4872,6 +4889,12 @@ mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
goto err_fib4_entry_create;
}
if (!mlxsw_sp_fib4_allow_replace(fib4_entry)) {
mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
return 0;
}
replaced = fib_node->fib_entry;
err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib4_entry->common);
if (err) {
@ -4908,7 +4931,7 @@ static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
return;
fib4_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info);
if (WARN_ON(!fib4_entry))
if (!fib4_entry)
return;
fib_node = fib4_entry->common.fib_node;
@ -4970,6 +4993,9 @@ static void mlxsw_sp_rt6_release(struct fib6_info *rt)
static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
{
struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh;
fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD;
mlxsw_sp_rt6_release(mlxsw_sp_rt6->rt);
kfree(mlxsw_sp_rt6);
}
@ -5408,6 +5434,27 @@ mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp,
return NULL;
}
static bool mlxsw_sp_fib6_allow_replace(struct mlxsw_sp_fib6_entry *fib6_entry)
{
struct mlxsw_sp_fib_node *fib_node = fib6_entry->common.fib_node;
struct mlxsw_sp_fib6_entry *fib6_replaced;
struct fib6_info *rt, *rt_replaced;
if (!fib_node->fib_entry)
return true;
fib6_replaced = container_of(fib_node->fib_entry,
struct mlxsw_sp_fib6_entry,
common);
rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
rt_replaced = mlxsw_sp_fib6_entry_rt(fib6_replaced);
if (rt->fib6_table->tb6_id == RT_TABLE_MAIN &&
rt_replaced->fib6_table->tb6_id == RT_TABLE_LOCAL)
return false;
return true;
}
static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
struct fib6_info **rt_arr,
unsigned int nrt6)
@ -5442,6 +5489,12 @@ static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
goto err_fib6_entry_create;
}
if (!mlxsw_sp_fib6_allow_replace(fib6_entry)) {
mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
return 0;
}
replaced = fib_node->fib_entry;
err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib6_entry->common);
if (err)

View File

@ -14,6 +14,7 @@ ALL_TESTS="
ipv4_plen
ipv4_replay
ipv4_flush
ipv4_local_replace
ipv6_add
ipv6_metric
ipv6_append_single
@ -26,6 +27,7 @@ ALL_TESTS="
ipv6_delete_multipath
ipv6_replay_single
ipv6_replay_multipath
ipv6_local_replace
"
NUM_NETIFS=0
source $lib_dir/lib.sh
@ -89,6 +91,43 @@ ipv4_flush()
fib_ipv4_flush_test "testns1"
}
ipv4_local_replace()
{
local ns="testns1"
RET=0
ip -n $ns link add name dummy1 type dummy
ip -n $ns link set dev dummy1 up
ip -n $ns route add table local 192.0.2.1/32 dev dummy1
fib4_trap_check $ns "table local 192.0.2.1/32 dev dummy1" false
check_err $? "Local table route not in hardware when should"
ip -n $ns route add table main 192.0.2.1/32 dev dummy1
fib4_trap_check $ns "table main 192.0.2.1/32 dev dummy1" true
check_err $? "Main table route in hardware when should not"
fib4_trap_check $ns "table local 192.0.2.1/32 dev dummy1" false
check_err $? "Local table route was replaced when should not"
# Test that local routes can replace routes in main table.
ip -n $ns route add table main 192.0.2.2/32 dev dummy1
fib4_trap_check $ns "table main 192.0.2.2/32 dev dummy1" false
check_err $? "Main table route not in hardware when should"
ip -n $ns route add table local 192.0.2.2/32 dev dummy1
fib4_trap_check $ns "table local 192.0.2.2/32 dev dummy1" false
check_err $? "Local table route did not replace route in main table when should"
fib4_trap_check $ns "table main 192.0.2.2/32 dev dummy1" true
check_err $? "Main table route was not replaced when should"
log_test "IPv4 local table route replacement"
ip -n $ns link del dev dummy1
}
ipv6_add()
{
fib_ipv6_add_test "testns1"
@ -149,6 +188,43 @@ ipv6_replay_multipath()
fib_ipv6_replay_multipath_test "testns1" "$DEVLINK_DEV"
}
ipv6_local_replace()
{
local ns="testns1"
RET=0
ip -n $ns link add name dummy1 type dummy
ip -n $ns link set dev dummy1 up
ip -n $ns route add table local 2001:db8:1::1/128 dev dummy1
fib6_trap_check $ns "table local 2001:db8:1::1/128 dev dummy1" false
check_err $? "Local table route not in hardware when should"
ip -n $ns route add table main 2001:db8:1::1/128 dev dummy1
fib6_trap_check $ns "table main 2001:db8:1::1/128 dev dummy1" true
check_err $? "Main table route in hardware when should not"
fib6_trap_check $ns "table local 2001:db8:1::1/128 dev dummy1" false
check_err $? "Local table route was replaced when should not"
# Test that local routes can replace routes in main table.
ip -n $ns route add table main 2001:db8:1::2/128 dev dummy1
fib6_trap_check $ns "table main 2001:db8:1::2/128 dev dummy1" false
check_err $? "Main table route not in hardware when should"
ip -n $ns route add table local 2001:db8:1::2/128 dev dummy1
fib6_trap_check $ns "table local 2001:db8:1::2/128 dev dummy1" false
check_err $? "Local route route did not replace route in main table when should"
fib6_trap_check $ns "table main 2001:db8:1::2/128 dev dummy1" true
check_err $? "Main table route was not replaced when should"
log_test "IPv6 local table route replacement"
ip -n $ns link del dev dummy1
}
setup_prepare()
{
ip netns add testns1