Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+142 -6
+4 -2
drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
··· 573 573 574 574 static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) 575 575 { 576 + enum mlxsw_reg_mgpir_device_type device_type; 576 577 int index, max_index, sensor_index; 577 578 char mgpir_pl[MLXSW_REG_MGPIR_LEN]; 578 579 char mtmp_pl[MLXSW_REG_MTMP_LEN]; ··· 585 584 if (err) 586 585 return err; 587 586 588 - mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL, NULL); 589 - if (!gbox_num) 587 + mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, NULL); 588 + if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || 589 + !gbox_num) 590 590 return 0; 591 591 592 592 index = mlxsw_hwmon->module_sensor_max;
+6 -2
drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
··· 895 895 mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, 896 896 struct mlxsw_thermal *thermal) 897 897 { 898 + enum mlxsw_reg_mgpir_device_type device_type; 898 899 struct mlxsw_thermal_module *gearbox_tz; 899 900 char mgpir_pl[MLXSW_REG_MGPIR_LEN]; 901 + u8 gbox_num; 900 902 int i; 901 903 int err; 902 904 ··· 910 908 if (err) 911 909 return err; 912 910 913 - mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL, 911 + mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, 914 912 NULL); 915 - if (!thermal->tz_gearbox_num) 913 + if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || 914 + !gbox_num) 916 915 return 0; 917 916 917 + thermal->tz_gearbox_num = gbox_num; 918 918 thermal->tz_gearbox_arr = kcalloc(thermal->tz_gearbox_num, 919 919 sizeof(*thermal->tz_gearbox_arr), 920 920 GFP_KERNEL);
+2 -1
drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
··· 215 215 start_again: 216 216 err = devlink_dpipe_entry_ctx_prepare(dump_ctx); 217 217 if (err) 218 - return err; 218 + goto err_ctx_prepare; 219 219 j = 0; 220 220 for (; i < rif_count; i++) { 221 221 struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); ··· 247 247 return 0; 248 248 err_entry_append: 249 249 err_entry_get: 250 + err_ctx_prepare: 250 251 rtnl_unlock(); 251 252 devlink_dpipe_entry_clear(&entry); 252 253 return err;
+54 -1
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
··· 4844 4844 fib_node->fib_entry = NULL; 4845 4845 } 4846 4846 4847 + static bool mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry *fib4_entry) 4848 + { 4849 + struct mlxsw_sp_fib_node *fib_node = fib4_entry->common.fib_node; 4850 + struct mlxsw_sp_fib4_entry *fib4_replaced; 4851 + 4852 + if (!fib_node->fib_entry) 4853 + return true; 4854 + 4855 + fib4_replaced = container_of(fib_node->fib_entry, 4856 + struct mlxsw_sp_fib4_entry, common); 4857 + if (fib4_entry->tb_id == RT_TABLE_MAIN && 4858 + fib4_replaced->tb_id == RT_TABLE_LOCAL) 4859 + return false; 4860 + 4861 + return true; 4862 + } 4863 + 4847 4864 static int 4848 4865 mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp, 4849 4866 const struct fib_entry_notifier_info *fen_info) ··· 4887 4870 dev_warn(mlxsw_sp->bus_info->dev, "Failed to create FIB entry\n"); 4888 4871 err = PTR_ERR(fib4_entry); 4889 4872 goto err_fib4_entry_create; 4873 + } 4874 + 4875 + if (!mlxsw_sp_fib4_allow_replace(fib4_entry)) { 4876 + mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry); 4877 + mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); 4878 + return 0; 4890 4879 } 4891 4880 4892 4881 replaced = fib_node->fib_entry; ··· 4931 4908 return; 4932 4909 4933 4910 fib4_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info); 4934 - if (WARN_ON(!fib4_entry)) 4911 + if (!fib4_entry) 4935 4912 return; 4936 4913 fib_node = fib4_entry->common.fib_node; 4937 4914 ··· 4993 4970 4994 4971 static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6) 4995 4972 { 4973 + struct fib6_nh *fib6_nh = mlxsw_sp_rt6->rt->fib6_nh; 4974 + 4975 + fib6_nh->fib_nh_flags &= ~RTNH_F_OFFLOAD; 4996 4976 mlxsw_sp_rt6_release(mlxsw_sp_rt6->rt); 4997 4977 kfree(mlxsw_sp_rt6); 4998 4978 } ··· 5434 5408 return NULL; 5435 5409 } 5436 5410 5411 + static bool mlxsw_sp_fib6_allow_replace(struct mlxsw_sp_fib6_entry *fib6_entry) 5412 + { 5413 + struct mlxsw_sp_fib_node *fib_node = fib6_entry->common.fib_node; 5414 + struct mlxsw_sp_fib6_entry *fib6_replaced; 5415 + struct fib6_info *rt, *rt_replaced; 5416 + 5417 + if (!fib_node->fib_entry) 5418 + return true; 5419 + 5420 + fib6_replaced = container_of(fib_node->fib_entry, 5421 + struct mlxsw_sp_fib6_entry, 5422 + common); 5423 + rt = mlxsw_sp_fib6_entry_rt(fib6_entry); 5424 + rt_replaced = mlxsw_sp_fib6_entry_rt(fib6_replaced); 5425 + if (rt->fib6_table->tb6_id == RT_TABLE_MAIN && 5426 + rt_replaced->fib6_table->tb6_id == RT_TABLE_LOCAL) 5427 + return false; 5428 + 5429 + return true; 5430 + } 5431 + 5437 5432 static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp, 5438 5433 struct fib6_info **rt_arr, 5439 5434 unsigned int nrt6) ··· 5487 5440 if (IS_ERR(fib6_entry)) { 5488 5441 err = PTR_ERR(fib6_entry); 5489 5442 goto err_fib6_entry_create; 5443 + } 5444 + 5445 + if (!mlxsw_sp_fib6_allow_replace(fib6_entry)) { 5446 + mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry); 5447 + mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); 5448 + return 0; 5490 5449 } 5491 5450 5492 5451 replaced = fib_node->fib_entry;
+76
tools/testing/selftests/drivers/net/mlxsw/fib.sh
··· 14 14 ipv4_plen 15 15 ipv4_replay 16 16 ipv4_flush 17 + ipv4_local_replace 17 18 ipv6_add 18 19 ipv6_metric 19 20 ipv6_append_single ··· 27 26 ipv6_delete_multipath 28 27 ipv6_replay_single 29 28 ipv6_replay_multipath 29 + ipv6_local_replace 30 30 " 31 31 NUM_NETIFS=0 32 32 source $lib_dir/lib.sh ··· 91 89 fib_ipv4_flush_test "testns1" 92 90 } 93 91 92 + ipv4_local_replace() 93 + { 94 + local ns="testns1" 95 + 96 + RET=0 97 + 98 + ip -n $ns link add name dummy1 type dummy 99 + ip -n $ns link set dev dummy1 up 100 + 101 + ip -n $ns route add table local 192.0.2.1/32 dev dummy1 102 + fib4_trap_check $ns "table local 192.0.2.1/32 dev dummy1" false 103 + check_err $? "Local table route not in hardware when should" 104 + 105 + ip -n $ns route add table main 192.0.2.1/32 dev dummy1 106 + fib4_trap_check $ns "table main 192.0.2.1/32 dev dummy1" true 107 + check_err $? "Main table route in hardware when should not" 108 + 109 + fib4_trap_check $ns "table local 192.0.2.1/32 dev dummy1" false 110 + check_err $? "Local table route was replaced when should not" 111 + 112 + # Test that local routes can replace routes in main table. 113 + ip -n $ns route add table main 192.0.2.2/32 dev dummy1 114 + fib4_trap_check $ns "table main 192.0.2.2/32 dev dummy1" false 115 + check_err $? "Main table route not in hardware when should" 116 + 117 + ip -n $ns route add table local 192.0.2.2/32 dev dummy1 118 + fib4_trap_check $ns "table local 192.0.2.2/32 dev dummy1" false 119 + check_err $? "Local table route did not replace route in main table when should" 120 + 121 + fib4_trap_check $ns "table main 192.0.2.2/32 dev dummy1" true 122 + check_err $? "Main table route was not replaced when should" 123 + 124 + log_test "IPv4 local table route replacement" 125 + 126 + ip -n $ns link del dev dummy1 127 + } 128 + 94 129 ipv6_add() 95 130 { 96 131 fib_ipv6_add_test "testns1" ··· 186 147 ipv6_replay_multipath() 187 148 { 188 149 fib_ipv6_replay_multipath_test "testns1" "$DEVLINK_DEV" 150 + } 151 + 152 + ipv6_local_replace() 153 + { 154 + local ns="testns1" 155 + 156 + RET=0 157 + 158 + ip -n $ns link add name dummy1 type dummy 159 + ip -n $ns link set dev dummy1 up 160 + 161 + ip -n $ns route add table local 2001:db8:1::1/128 dev dummy1 162 + fib6_trap_check $ns "table local 2001:db8:1::1/128 dev dummy1" false 163 + check_err $? "Local table route not in hardware when should" 164 + 165 + ip -n $ns route add table main 2001:db8:1::1/128 dev dummy1 166 + fib6_trap_check $ns "table main 2001:db8:1::1/128 dev dummy1" true 167 + check_err $? "Main table route in hardware when should not" 168 + 169 + fib6_trap_check $ns "table local 2001:db8:1::1/128 dev dummy1" false 170 + check_err $? "Local table route was replaced when should not" 171 + 172 + # Test that local routes can replace routes in main table. 173 + ip -n $ns route add table main 2001:db8:1::2/128 dev dummy1 174 + fib6_trap_check $ns "table main 2001:db8:1::2/128 dev dummy1" false 175 + check_err $? "Main table route not in hardware when should" 176 + 177 + ip -n $ns route add table local 2001:db8:1::2/128 dev dummy1 178 + fib6_trap_check $ns "table local 2001:db8:1::2/128 dev dummy1" false 179 + check_err $? "Local route route did not replace route in main table when should" 180 + 181 + fib6_trap_check $ns "table main 2001:db8:1::2/128 dev dummy1" true 182 + check_err $? "Main table route was not replaced when should" 183 + 184 + log_test "IPv6 local table route replacement" 185 + 186 + ip -n $ns link del dev dummy1 189 187 } 190 188 191 189 setup_prepare()