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

Configure Feed

Select the types of activity you want to include in your feed.

net: ethtool: Fix symmetric-xor RSS RX flow hash check

Commit 13e59344fb9d ("net: ethtool: add support for symmetric-xor RSS hash")
adds a check to the ethtool set_rxnfc operation, which checks the RX
flow hash if the flag RXH_XFRM_SYM_XOR is set. This flag is introduced
with the same commit. It calls the ethtool get_rxfh operation to get the
RX flow hash data. If get_rxfh is not supported, then EOPNOTSUPP is
returned.

There are driver like tsnep, macb, asp2, genet, gianfar, mtk, ... which
support the ethtool operation set_rxnfc but not get_rxfh. This results
in EOPNOTSUPP returned by ethtool_set_rxnfc() without actually calling
the ethtool operation set_rxnfc. Thus, set_rxnfc got broken for all
these drivers.

Check RX flow hash in ethtool_set_rxnfc() only if driver supports RX
flow hash.

Fixes: 13e59344fb9d ("net: ethtool: add support for symmetric-xor RSS hash")
Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com>
Reviewed-by: Ravi Gunasekaran <r-gunasekaran@ti.com>
Link: https://lore.kernel.org/r/20231226205536.32003-1-gerhard@engleder-embedded.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Gerhard Engleder and committed by
Jakub Kicinski
501869fe 88b8fd97

+18 -15
+18 -15
net/ethtool/ioctl.c
··· 973 973 u32 cmd, void __user *useraddr) 974 974 { 975 975 const struct ethtool_ops *ops = dev->ethtool_ops; 976 - struct ethtool_rxfh_param rxfh = {}; 977 976 struct ethtool_rxnfc info; 978 977 size_t info_size = sizeof(info); 979 978 int rc; 980 979 981 - if (!ops->set_rxnfc || !ops->get_rxfh) 980 + if (!ops->set_rxnfc) 982 981 return -EOPNOTSUPP; 983 982 984 983 rc = ethtool_rxnfc_copy_struct(cmd, &info, &info_size, useraddr); 985 984 if (rc) 986 985 return rc; 987 986 988 - rc = ops->get_rxfh(dev, &rxfh); 989 - if (rc) 990 - return rc; 987 + if (ops->get_rxfh) { 988 + struct ethtool_rxfh_param rxfh = {}; 991 989 992 - /* Sanity check: if symmetric-xor is set, then: 993 - * 1 - no other fields besides IP src/dst and/or L4 src/dst 994 - * 2 - If src is set, dst must also be set 995 - */ 996 - if ((rxfh.input_xfrm & RXH_XFRM_SYM_XOR) && 997 - ((info.data & ~(RXH_IP_SRC | RXH_IP_DST | 998 - RXH_L4_B_0_1 | RXH_L4_B_2_3)) || 999 - (!!(info.data & RXH_IP_SRC) ^ !!(info.data & RXH_IP_DST)) || 1000 - (!!(info.data & RXH_L4_B_0_1) ^ !!(info.data & RXH_L4_B_2_3)))) 1001 - return -EINVAL; 990 + rc = ops->get_rxfh(dev, &rxfh); 991 + if (rc) 992 + return rc; 993 + 994 + /* Sanity check: if symmetric-xor is set, then: 995 + * 1 - no other fields besides IP src/dst and/or L4 src/dst 996 + * 2 - If src is set, dst must also be set 997 + */ 998 + if ((rxfh.input_xfrm & RXH_XFRM_SYM_XOR) && 999 + ((info.data & ~(RXH_IP_SRC | RXH_IP_DST | 1000 + RXH_L4_B_0_1 | RXH_L4_B_2_3)) || 1001 + (!!(info.data & RXH_IP_SRC) ^ !!(info.data & RXH_IP_DST)) || 1002 + (!!(info.data & RXH_L4_B_0_1) ^ !!(info.data & RXH_L4_B_2_3)))) 1003 + return -EINVAL; 1004 + } 1002 1005 1003 1006 rc = ops->set_rxnfc(dev, &info); 1004 1007 if (rc)