Symmetric OR-XOR RSS hash
Subsystems (8)
v4 cover Symmetric OR-XOR RSS hash
Add support for a new type of input_xfrm: Symmetric OR-XOR. Symmetric OR-XOR performs hash as follows:
(SRC_IP | DST_IP, SRC_IP ^ DST_IP, SRC_PORT | DST_PORT, SRC_PORT ^ DST_PORT)
Configuration is done through ethtool -x/X command.
For mlx5, the default is already symmetric hash, this patch now exposes this to userspace and allows enabling/disabling of the feature.
Changelog -v3->v4: https://lore.kernel.org/netdev/[email protected]/
* Test adjustments (Jakub)
v2->v3: https://lore.kernel.org/netdev/[email protected]/
* Reorder fields in ethtool_ops (Jakub)
* Add a selftest (Jakub)
v1->v2: https://lore.kernel.org/all/[email protected]/
* Fix wording in comments (Edward)
Thanks,
Gal
Gal Pressman (5):
ethtool: Symmetric OR-XOR RSS hash
net/mlx5e: Symmetric OR-XOR RSS hash control
selftests: drv-net: Make rand_port() get a port more reliably
selftests: drv-net: Introduce a function that checks whether a port is
available on remote host
selftests: drv-net-hw: Add a test for symmetric RSS hash
Documentation/networking/ethtool-netlink.rst | 2 +- Documentation/networking/scaling.rst | 14 ++- .../net/ethernet/intel/iavf/iavf_ethtool.c | 2 +- drivers/net/ethernet/intel/ice/ice_ethtool.c | 2 +- .../net/ethernet/mellanox/mlx5/core/en/rss.c | 13 ++- .../net/ethernet/mellanox/mlx5/core/en/rss.h | 4 +- .../ethernet/mellanox/mlx5/core/en/rx_res.c | 11 +-- .../ethernet/mellanox/mlx5/core/en/rx_res.h | 5 +- .../net/ethernet/mellanox/mlx5/core/en/tir.c | 2 +- .../net/ethernet/mellanox/mlx5/core/en/tir.h | 1 + .../ethernet/mellanox/mlx5/core/en_ethtool.c | 17 +++- include/linux/ethtool.h | 5 +- include/uapi/linux/ethtool.h | 4 + net/ethtool/ioctl.c | 8 +- .../testing/selftests/drivers/net/hw/Makefile | 1 + .../drivers/net/hw/rss_input_xfrm.py | 85 +++++++++++++++++++ tools/testing/selftests/net/lib/py/utils.py | 22 ++--- 17 files changed, 158 insertions(+), 40 deletions(-) create mode 100755 tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py
Signature · 1 line
2.40.1
PATCH v4 1/5 ethtool: Symmetric OR-XOR RSS hash
Add an additional type of symmetric RSS hash type: OR-XOR. The "Symmetric-OR-XOR" algorithm transforms the input as follows:
(SRC_IP | DST_IP, SRC_IP ^ DST_IP, SRC_PORT | DST_PORT, SRC_PORT ^ DST_PORT)
Change 'cap_rss_sym_xor_supported' to 'supported_input_xfrm', a bitmap of supported RXH_XFRM_* types.
--- Documentation/networking/ethtool-netlink.rst | 2 +- Documentation/networking/scaling.rst | 14 ++++++++++---- drivers/net/ethernet/intel/iavf/iavf_ethtool.c | 2 +- drivers/net/ethernet/intel/ice/ice_ethtool.c | 2 +- include/linux/ethtool.h | 5 ++--- include/uapi/linux/ethtool.h | 4 ++++ net/ethtool/ioctl.c | 8 ++++---- 7 files changed, 23 insertions(+), 14 deletions(-)
Documentation/networking/ethtool-netlink.rst +1 -1
@@ -1934,7 +1934,7 @@ ETHTOOL_A_RSS_INDIR attribute returns RSS indirection table where each byte indicates queue number. ETHTOOL_A_RSS_INPUT_XFRM attribute is a bitmap indicating the type of transformation applied to the input protocol fields before given to the RSS -hfunc. Current supported option is symmetric-xor. +hfunc. Current supported options are symmetric-xor and symmetric-or-xor. PLCA_GET_CFG ============
Documentation/networking/scaling.rst +10 -4
@@ -49,14 +49,20 @@ destination address) and TCP/UDP (source port, destination port) tuples are swapped, the computed hash is the same. This is beneficial in some applications that monitor TCP/IP flows (IDS, firewalls, ...etc) and need both directions of the flow to land on the same Rx queue (and CPU). The -"Symmetric-XOR" is a type of RSS algorithms that achieves this hash -symmetry by XORing the input source and destination fields of the IP -and/or L4 protocols. This, however, results in reduced input entropy and -could potentially be exploited. Specifically, the algorithm XORs the input +"Symmetric-XOR" and "Symmetric-OR-XOR" are types of RSS algorithms that +achieve this hash symmetry by XOR/ORing the input source and destination +fields of the IP and/or L4 protocols. This, however, results in reduced +input entropy and could potentially be exploited. + +Specifically, the "Symmetric-XOR" algorithm XORs the input as follows:: # (SRC_IP ^ DST_IP, SRC_IP ^ DST_IP, SRC_PORT ^ DST_PORT, SRC_PORT ^ DST_PORT) +The "Symmetric-OR-XOR" algorithm transforms the input as follows:: + + # (SRC_IP | DST_IP, SRC_IP ^ DST_IP, SRC_PORT | DST_PORT, SRC_PORT ^ DST_PORT) + The result is then fed to the underlying RSS algorithm. Some advanced NICs allow steering packets to queues based on
drivers/net/ethernet/intel/iavf/iavf_ethtool.c +1 -1
@@ -1808,7 +1808,7 @@ static int iavf_set_rxfh(struct net_device *netdev,static const struct ethtool_ops iavf_ethtool_ops = { .supported_coalesce_params =ETHTOOL_COALESCE_USECS |ETHTOOL_COALESCE_USE_ADAPTIVE , - .cap_rss_sym_xor_supported = true, + .supported_input_xfrm =RXH_XFRM_SYM_XOR , .get_drvinfo = iavf_get_drvinfo, .get_link = ethtool_op_get_link, .get_ringparam = iavf_get_ringparam,
drivers/net/ethernet/intel/ice/ice_ethtool.c +1 -1
@@ -4770,7 +4770,7 @@ static const struct ethtool_ops ice_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS |ETHTOOL_COALESCE_USE_ADAPTIVE | ETHTOOL_COALESCE_RX_USECS_HIGH, - .cap_rss_sym_xor_supported = true, + .supported_input_xfrm = RXH_XFRM_SYM_XOR, .rxfh_per_ctx_key = true, .get_link_ksettings = ice_get_link_ksettings, .set_link_ksettings = ice_set_link_ksettings,
include/linux/ethtool.h +2 -3
@@ -763,13 +763,12 @@ struct kernel_ethtool_ts_info {/** * struct ethtool_ops - optional netdev operations +* @supported_input_xfrm: supported types of input xfrm from %RXH_XFRM_*. * @cap_link_lanes_supported: indicates if the driver supports lanes * parameter. * @cap_rss_ctx_supported: indicates if the driver supports RSS * contexts via legacy API, drivers implementing @create_rxfh_context * do not have to set this bit. -* @cap_rss_sym_xor_supported: indicates if the driver supports symmetric-xor -* RSS. * @rxfh_per_ctx_key: device supports setting different RSS key for each * additional context. Netlink API should report hfunc, key, and input_xfrm * for every context, not just context 0.
@@ -995,9 +994,9 @@ struct kernel_ethtool_ts_info {* of the generic netdev features interface. */ struct ethtool_ops { +u32 supported_input_xfrm:8 ;u32 cap_link_lanes_supported:1 ;u32 cap_rss_ctx_supported:1 ; -u32 cap_rss_sym_xor_supported:1 ;u32 rxfh_per_ctx_key:1 ;u32 cap_rss_rxnfc_adds:1 ;u32 rxfh_indir_space;
include/uapi/linux/ethtool.h +4 -0
@@ -2289,6 +2289,10 @@ static inline int ethtool_validate_duplex(__u8 duplex)* be exploited to reduce the RSS queue spread. */ #define RXH_XFRM_SYM_XOR (1 << 0) +/* Similar to SYM_XOR, except that one copy of the XOR'ed fields is replaced by +* an OR of the same fields +*/ +#define RXH_XFRM_SYM_OR_XOR (1 << 1)#define RXH_XFRM_NO_CHANGE 0xff/* L2-L4 network traffic flow types */
net/ethtool/ioctl.c +4 -4
@@ -1011,11 +1011,11 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,if (rc)return rc; -/* Sanity check: if symmetric-xor is set, then: +/* Sanity check: if symmetric-xor/symmetric-or-xor is set, then: * 1 - no other fields besides IP src/dst and/or L4 src/dst * 2 - If src is set, dst must also be set */ - if ((rxfh.input_xfrm & RXH_XFRM_SYM_XOR) && + if ((rxfh.input_xfrm & (RXH_XFRM_SYM_XOR | RXH_XFRM_SYM_OR_XOR)) && ((info.data & ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)) || (!!(info.data & RXH_IP_SRC) ^ !!(info.data & RXH_IP_DST)) ||
@@ -1388,11 +1388,11 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,return -EOPNOTSUPP ;/* Check input data transformation capabilities */ if (rxfh.input_xfrm && rxfh.input_xfrm !=RXH_XFRM_SYM_XOR && + rxfh.input_xfrm !=RXH_XFRM_SYM_OR_XOR && rxfh.input_xfrm !=RXH_XFRM_NO_CHANGE )return -EINVAL ;if (rxfh.input_xfrm !=RXH_XFRM_NO_CHANGE && - (rxfh.input_xfrm &RXH_XFRM_SYM_XOR ) && - !ops->cap_rss_sym_xor_supported) + rxfh.input_xfrm & ~ops->supported_input_xfrm)return -EOPNOTSUPP ; create = rxfh.rss_context ==ETH_RXFH_CONTEXT_ALLOC ;
Signature · 1 line
2.40.1
Re: [PATCH net-next v4 1/5] ethtool: Symmetric OR-XOR RSS hash
Quoted 1 line · Gal Pressman
+Specifically, the "Symmetric-XOR" algorithm XORs the input
or transforms?
Quoted 5 lines
as follows::
# (
SRC_IP^DST_IP,SRC_IP^DST_IP,SRC_PORT^DST_PORT,SRC_PORT^DST_PORT)+The "Symmetric-OR-XOR" algorithm transforms the input as follows::
"..., on the other hand, transforms the input ..."
Documentation/networking/scaling.rst destination address) and TCP/UDP (source port, destination port) tuples · line 65
Quoted 3 lines
Documentation/networking/scaling.rst +3
-0+ + # (SRC_IP | DST_IP, SRC_IP ^ DST_IP, SRC_PORT | DST_PORT, SRC_PORT ^ DST_PORT) +
Thanks.
Signature · 1 line
An old man doll... just what I always wanted! - Clara
Re: [PATCH net-next v4 1/5] ethtool: Symmetric OR-XOR RSS hash
Quoted 7 lines · Bagas Sanjaya
Quoted 1 line · Gal Pressman
+Specifically, the "Symmetric-XOR" algorithm XORs the input
or transforms?
Quoted 4 lines
as follows::
# (
SRC_IP^DST_IP,SRC_IP^DST_IP,SRC_PORT^DST_PORT,SRC_PORT^DST_PORT)
Quoted 8 lines
Quoted 1 line
+The "Symmetric-OR-XOR" algorithm transforms the input as follows::
"..., on the other hand, transforms the input ..."
Documentation/networking/scaling.rst destination address) and TCP/UDP (source port, destination port) tuples · line 65
Quoted 3 lines
Documentation/networking/scaling.rst +3
-0+ + # (SRC_IP | DST_IP, SRC_IP ^ DST_IP, SRC_PORT | DST_PORT, SRC_PORT ^ DST_PORT) +Thanks.
Ack, thanks.
PATCH v4 2/5 net/mlx5e: Symmetric OR-XOR RSS hash control
In reply to Gal PressmanAllow control over the symmetric RSS hash, which was previously set to enabled by default by the driver.
Symmetric OR-XOR RSS can now be queried and controlled using the 'ethtool -x/X' command.
--- .../net/ethernet/mellanox/mlx5/core/en/rss.c | 13 +++++++++++-- .../net/ethernet/mellanox/mlx5/core/en/rss.h | 4 ++-- .../net/ethernet/mellanox/mlx5/core/en/rx_res.c | 11 ++++++----- .../net/ethernet/mellanox/mlx5/core/en/rx_res.h | 5 +++-- .../net/ethernet/mellanox/mlx5/core/en/tir.c | 2 +- .../net/ethernet/mellanox/mlx5/core/en/tir.h | 1 + .../ethernet/mellanox/mlx5/core/en_ethtool.c | 17 ++++++++++++++--- 7 files changed, 38 insertions(+), 15 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en/rss.c +11 -2
@@ -161,6 +161,7 @@ static void mlx5e_rss_params_init(struct mlx5e_rss *rss) {enum mlx5_traffic_types tt; + rss->hash.symmetric = true; rss->hash.hfunc =ETH_RSS_HASH_TOP ;netdev_rss_key_fill (rss->hash.toeplitz_hash_key,sizeof (rss->hash.toeplitz_hash_key));
@@ -566,7 +567,7 @@ int mlx5e_rss_packet_merge_set_param(struct mlx5e_rss *rss,return final_err; } -int mlx5e_rss_get_rxfh (struct mlx5e_rss *rss,u32 *indir,u8 *key,u8 *hfunc) +int mlx5e_rss_get_rxfh (struct mlx5e_rss *rss,u32 *indir,u8 *key,u8 *hfunc,bool *symmetric) {if (indir) memcpy(indir, rss->indir.table,
@@ -579,11 +580,14 @@ int mlx5e_rss_get_rxfh(struct mlx5e_rss *rss, u32 *indir, u8 *key, u8 *hfunc)if (hfunc) *hfunc = rss->hash.hfunc; +if (symmetric) + *symmetric = rss->hash.symmetric; +return 0 ; }int mlx5e_rss_set_rxfh (struct mlx5e_rss *rss,const u32 *indir, -const u8 *key,const u8 *hfunc, +const u8 *key,const u8 *hfunc,const bool *symmetric,u32 *rqns,u32 *vhca_ids,unsigned int num_rqns) {bool changed_indir = false;
@@ -623,6 +627,11 @@ int mlx5e_rss_set_rxfh(struct mlx5e_rss *rss, const u32 *indir, rss->indir.actual_table_size * sizeof(*rss->indir.table)); } +if (symmetric) { + rss->hash.symmetric = *symmetric; + changed_hash = true; + } +if (changed_indir && rss->enabled) { err =mlx5e_rss_apply (rss, rqns, vhca_ids, num_rqns);if (err) {
drivers/net/ethernet/mellanox/mlx5/core/en/rss.h +2 -2
@@ -47,9 +47,9 @@ void mlx5e_rss_disable(struct mlx5e_rss *rss);int mlx5e_rss_packet_merge_set_param (struct mlx5e_rss *rss,struct mlx5e_packet_merge_param *pkt_merge_param); -int mlx5e_rss_get_rxfh (struct mlx5e_rss *rss,u32 *indir,u8 *key,u8 *hfunc); +int mlx5e_rss_get_rxfh (struct mlx5e_rss *rss,u32 *indir,u8 *key,u8 *hfunc,bool *symmetric);int mlx5e_rss_set_rxfh (struct mlx5e_rss *rss,const u32 *indir, -const u8 *key,const u8 *hfunc, +const u8 *key,const u8 *hfunc,const bool *symmetric,u32 *rqns,u32 *vhca_ids,unsigned int num_rqns);struct mlx5e_rss_params_hash mlx5e_rss_get_hash (struct mlx5e_rss *rss);u8 mlx5e_rss_get_hash_fields (struct mlx5e_rss *rss,enum mlx5_traffic_types tt);
drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c +6 -5
@@ -194,7 +194,7 @@ void mlx5e_rx_res_rss_set_indir_uniform(struct mlx5e_rx_res *res, unsigned int n }int mlx5e_rx_res_rss_get_rxfh (struct mlx5e_rx_res *res,u32 rss_idx, -u32 *indir,u8 *key,u8 *hfunc) +u32 *indir,u8 *key,u8 *hfunc,bool *symmetric) {struct mlx5e_rss *rss;
@@ -205,11 +205,12 @@ int mlx5e_rx_res_rss_get_rxfh(struct mlx5e_rx_res *res, u32 rss_idx,if (!rss)return -ENOENT ; -return mlx5e_rss_get_rxfh (rss, indir, key, hfunc); +return mlx5e_rss_get_rxfh (rss, indir, key, hfunc, symmetric); }int mlx5e_rx_res_rss_set_rxfh (struct mlx5e_rx_res *res,u32 rss_idx, -const u32 *indir,const u8 *key,const u8 *hfunc) +const u32 *indir,const u8 *key,const u8 *hfunc, +const bool *symmetric) {u32 *vhca_ids =get_vhca_ids (res,0 );struct mlx5e_rss *rss;
@@ -221,8 +222,8 @@ int mlx5e_rx_res_rss_set_rxfh(struct mlx5e_rx_res *res, u32 rss_idx,if (!rss)return -ENOENT ; -return mlx5e_rss_set_rxfh (rss, indir, key, hfunc, res->rss_rqns, vhca_ids, - res->rss_nch); +return mlx5e_rss_set_rxfh (rss, indir, key, hfunc, symmetric, + res->rss_rqns, vhca_ids, res->rss_nch); } int mlx5e_rx_res_rss_get_hash_fields(struct mlx5e_rx_res *res, u32 rss_idx,
drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h +3 -2
@@ -49,9 +49,10 @@ void mlx5e_rx_res_xsk_update(struct mlx5e_rx_res *res, struct mlx5e_channels *ch/* Configuration API */ void mlx5e_rx_res_rss_set_indir_uniform (struct mlx5e_rx_res *res,unsigned int nch);int mlx5e_rx_res_rss_get_rxfh (struct mlx5e_rx_res *res,u32 rss_idx, -u32 *indir,u8 *key,u8 *hfunc); +u32 *indir,u8 *key,u8 *hfunc,bool *symmetric);int mlx5e_rx_res_rss_set_rxfh (struct mlx5e_rx_res *res,u32 rss_idx, -const u32 *indir,const u8 *key,const u8 *hfunc); +const u32 *indir,const u8 *key,const u8 *hfunc, +const bool *symmetric);int mlx5e_rx_res_rss_get_hash_fields (struct mlx5e_rx_res *res,u32 rss_idx,enum mlx5_traffic_types tt);
drivers/net/ethernet/mellanox/mlx5/core/en/tir.c +1 -1
@@ -124,7 +124,7 @@ void mlx5e_tir_builder_build_rss(struct mlx5e_tir_builder *builder,const size_t len =MLX5_FLD_SZ_BYTES (tirc, rx_hash_toeplitz_key);void *rss_key =MLX5_ADDR_OF (tirc, tirc, rx_hash_toeplitz_key); -MLX5_SET (tirc, tirc, rx_hash_symmetric,1 ); +MLX5_SET (tirc, tirc, rx_hash_symmetric, rss_hash->symmetric);memcpy (rss_key, rss_hash->toeplitz_hash_key, len); }
drivers/net/ethernet/mellanox/mlx5/core/en/tir.h +1 -0
@@ -9,6 +9,7 @@struct mlx5e_rss_params_hash {u8 hfunc;u8 toeplitz_hash_key[40 ]; +bool symmetric; };struct mlx5e_rss_params_traffic_type {
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +14 -3
@@ -1480,18 +1480,27 @@ static int mlx5e_get_rxfh(struct net_device *netdev, struct ethtool_rxfh_param * {struct mlx5e_priv *priv =netdev_priv (netdev);u32 rss_context = rxfh->rss_context; +bool symmetric;int err;mutex_lock (&priv->state_lock); err =mlx5e_rx_res_rss_get_rxfh (priv->rx_res, rss_context, - rxfh->indir, rxfh->key, &rxfh->hfunc); + rxfh->indir, rxfh->key, &rxfh->hfunc, &symmetric);mutex_unlock (&priv->state_lock); -return err; + +if (err) +return err; + +if (symmetric) + rxfh->input_xfrm =RXH_XFRM_SYM_OR_XOR ; + +return 0 ; }static int mlx5e_set_rxfh (struct net_device *dev,struct ethtool_rxfh_param *rxfh,struct netlink_ext_ack *extack) { +bool symmetric = rxfh->input_xfrm ==RXH_XFRM_SYM_OR_XOR ;struct mlx5e_priv *priv =netdev_priv (dev);u32 *rss_context = &rxfh->rss_context;u8 hfunc = rxfh->hfunc;
@@ -1526,7 +1535,8 @@ static int mlx5e_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxf err =mlx5e_rx_res_rss_set_rxfh (priv->rx_res, *rss_context, rxfh->indir, rxfh->key, - hfunc ==ETH_RSS_HASH_NO_CHANGE ?NULL : &hfunc); + hfunc ==ETH_RSS_HASH_NO_CHANGE ?NULL : &hfunc, + rxfh->input_xfrm ==RXH_XFRM_NO_CHANGE ?NULL : &symmetric); unlock:mutex_unlock (&priv->state_lock);
@@ -2635,6 +2645,7 @@ const struct ethtool_ops mlx5e_ethtool_ops = {ETHTOOL_COALESCE_MAX_FRAMES |ETHTOOL_COALESCE_USE_ADAPTIVE | ETHTOOL_COALESCE_USE_CQE, + .supported_input_xfrm = RXH_XFRM_SYM_OR_XOR, .get_drvinfo = mlx5e_get_drvinfo, .get_link = ethtool_op_get_link, .get_link_ext_state = mlx5e_get_link_ext_state,
Signature · 1 line
2.40.1
PATCH v4 3/5 selftests: drv-net: Make rand_port() get a port more reliably
In reply to Gal PressmanInstead of guessing a port and checking whether it's available, get an available port from the OS.
--- tools/testing/selftests/net/lib/py/utils.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-)
tools/testing/selftests/net/lib/py/utils.py +4 -11
@@ -125,18 +125,11 @@ def ethtool(args, json=None, ns=None, host=None): def rand_port(): """ - Get a random unprivileged port, try to make sure it's not already used. + Get a random unprivileged port. """ - for _ in range(1000): - port = random.randint(10000, 65535) - try: - with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s: - s.bind(("", port)) - return port - except OSError as e: - if e.errno != errno.EADDRINUSE: - raise - raise Exception("Can't find any free unprivileged port") + with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s: + s.bind(("", 0)) + return s.getsockname()[1] def wait_port_listen(port, proto="tcp", ns=None, host=None, sleep=0.005, deadline=5):
Signature · 1 line
2.40.1
PATCH v4 4/5 selftests: drv-net: Introduce a function that checks whether a port is available on remote host
In reply to Gal PressmanAdd a function that checks whether a port is available on the remote host, this will be used downstream to verify that ports that were allocated locally are also available on the remote side.
--- tools/testing/selftests/net/lib/py/utils.py | 7 +++++++ 1 file changed, 7 insertions(+)
tools/testing/selftests/net/lib/py/utils.py +7 -0
@@ -123,6 +123,13 @@ def ethtool(args, json=None, ns=None, host=None): return tool('ethtool', args, json=json, ns=ns, host=host) +def check_port_available_remote(port, host): + """ + Check if a port is available on remote host. + Raise exception if not available. + """ + cmd(f"python3 -c 'import socket; s=socket.socket(socket.AF_INET6, socket.SOCK_STREAM); s.bind((\"\", {port}))'", host=host) + def rand_port(): """ Get a random unprivileged port.
Signature · 1 line
2.40.1
PATCH v4 5/5 selftests: drv-net-hw: Add a test for symmetric RSS hash
In reply to Gal PressmanAdd a selftest that verifies symmetric RSS hash is working as intended. The test runs iterations of traffic, swapping the src/dst UDP ports, and verifies that the same RX queue is receiving the traffic in both cases.
--- .../testing/selftests/drivers/net/hw/Makefile | 1 + .../drivers/net/hw/rss_input_xfrm.py | 85 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100755 tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py
tools/testing/selftests/drivers/net/hw/Makefile +1 -0
@@ -16,6 +16,7 @@ TEST_PROGS = \ pp_alloc_fail.py \ rss_ctx.py \ tso.py \ + rss_input_xfrm.py \ # TEST_FILES := \
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file +85 -0
85 lines not on this page · raw message
Signature · 1 line
2.40.1
Jakub Kicinski
maintainerRe: [PATCH net-next v4 5/5] selftests: drv-net-hw: Add a test for symmetric RSS hash
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py line 21
Quoted 10 lines · On Thu, 20 Feb 2025 13:34:35 +0200 Gal Pressman wrote:
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file +10
-0+def _get_rand_port(remote): + for _ in range(1000): + port = rand_port() + try: + check_port_available_remote(port, remote) + return port + except: + continue + + raise Exception("Can't find any free unprivileged port")
TCP and UDP port spaces are separate, I think your checking if the ports are available on TCP here, and then use them for UDP below.
We don't really care about the 100% success, I don't think we should be checking the ports. Pick two ports, send a A<>B packet, send a B<>A packet, if either fails to connect or doesn't arrive just ignore. As long as we can get ~10? successful pairs in 100? ties it's good.
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py line 31
Quoted 8 lines
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file +8
-0+def traffic(cfg, local_port, remote_port, ipver): + af_inet = socket.AF_INET if ipver == "4" else socket.AF_INET6 + sock = socket.socket(af_inet, socket.SOCK_DGRAM) + sock.bind(('', local_port)) + sock.connect((cfg.remote_addr_v[ipver], remote_port)) + tgt = f"{ipver}:[{cfg.addr_v[ipver]}]:{local_port},sourceport={remote_port}" + cmd("echo a | socat - UDP" + tgt, host=cfg.remote) + sock.recvmsg(100)
Could you use fd_read_timeout():
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/tools/testing/selftests/net/lib/py/utils.py#n20
In case the packet got lost?
Quoted 16 lines
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file +16
-0+ return sock.getsockopt(socket.SOL_SOCKET, socket.SO_INCOMING_CPU) + + +def test_rss_input_xfrm(cfg, ipver): + """ + Test symmetric input_xfrm. + If symmetric RSS hash is configured, send traffic twice, swapping the + src/dst UDP ports, and verify that the same queue is receiving the traffic + in both cases (IPs are constant). + """ + + input_xfrm = cfg.ethnl.rss_get( + {'header': {'dev-name': cfg.ifname}}).get('input_xfrm') + + # Check for symmetric xor/or-xor + if input_xfrm and (input_xfrm == 1 or input_xfrm == 2):
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py line 57
Quoted 10 lines
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file +10
-0+ cpus = set() + for _ in range(8): + port1 = _get_rand_port(cfg.remote) + port2 = _get_rand_port(cfg.remote) + cpu1 = traffic(cfg, port1, port2, ipver) + cpu2 = traffic(cfg, port2, port1, ipver) + cpus.update([cpu1, cpu2]) + + ksft_eq( + cpu1, cpu2, comment=f"Received traffic on different cpus ({cpu1} != {cpu2}) with ports ({port1 = }, {port2 = }) while symmetric hash is configured")
the cpu1 cpu2 values will already be printed by the helper, no need to format them in
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py line 61
Quoted 4 lines
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file +4
-0+ + ksft_ge(len(cpus), 2, comment=f"Received traffic on less than two cpus") + else: + raise KsftSkipEx("Symmetric RSS hash not requested")
Flip the condition, raise the exception right after the if, then the rest of the code doesn't have to be indented?
I'd also add a:
if len(cpus) == 1:
raise KsftSkipEx(f"Only one CPU seen traffic: {cpus}")Signature · 1 line
pw-bot: cr
Re: [PATCH net-next v4 5/5] selftests: drv-net-hw: Add a test for symmetric RSS hash
Quoted 15 lines · Jakub Kicinski
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py line 21
Quoted 10 lines · On Thu, 20 Feb 2025 13:34:35 +0200 Gal Pressman wrote:
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file +10
-0+def _get_rand_port(remote): + for _ in range(1000): + port = rand_port() + try: + check_port_available_remote(port, remote) + return port + except: + continue + + raise Exception("Can't find any free unprivileged port")TCP and UDP port spaces are separate, I think your checking if the ports are available on TCP here, and then use them for UDP below.
Quoted 4 lines
We don't really care about the 100% success, I don't think we should be checking the ports. Pick two ports, send a A<>B packet, send a B<>A packet, if either fails to connect or doesn't arrive just ignore. As long as we can get ~10? successful pairs in 100? ties it's good.
Ack.
Quoted 10 lines
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py line 31
Quoted 9 lines
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file +8
-0+def traffic(cfg, local_port, remote_port, ipver): + af_inet = socket.AF_INET if ipver == "4" else socket.AF_INET6 + sock = socket.socket(af_inet, socket.SOCK_DGRAM) + sock.bind(('', local_port)) + sock.connect((cfg.remote_addr_v[ipver], remote_port)) + tgt = f"{ipver}:[{cfg.addr_v[ipver]}]:{local_port},sourceport={remote_port}" + cmd("echo a | socat - UDP" + tgt, host=cfg.remote) + sock.recvmsg(100)
Quoted 4 lines
Could you use
fd_read_timeout():
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/tools/testing/selftests/net/lib/py/utils.py#n20In case the packet got lost?
Yes.
Quoted 31 lines
Quoted 17 lines
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file +16
-0+ return sock.getsockopt(socket.SOL_SOCKET, socket.SO_INCOMING_CPU) + + +def test_rss_input_xfrm(cfg, ipver): + """ + Test symmetric input_xfrm. + If symmetric RSS hash is configured, send traffic twice, swapping the + src/dst UDP ports, and verify that the same queue is receiving the traffic + in both cases (IPs are constant). + """ + + input_xfrm = cfg.ethnl.rss_get( + {'header': {'dev-name': cfg.ifname}}).get('input_xfrm') + + # Check for symmetric xor/or-xor + if input_xfrm and (input_xfrm == 1 or input_xfrm == 2):tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py line 57
Quoted 10 lines
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file +10
-0+ cpus = set() + for _ in range(8): + port1 = _get_rand_port(cfg.remote) + port2 = _get_rand_port(cfg.remote) + cpu1 = traffic(cfg, port1, port2, ipver) + cpu2 = traffic(cfg, port2, port1, ipver) + cpus.update([cpu1, cpu2]) + + ksft_eq( + cpu1, cpu2, comment=f"Received traffic on different cpus ({cpu1} != {cpu2}) with ports ({port1 = }, {port2 = }) while symmetric hash is configured")the cpu1 cpu2 values will already be printed by the helper, no need to format them in
Quoted 7 lines
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py line 61
Quoted 4 lines
tools/testing/selftests/drivers/net/hw/rss_input_xfrm.py new file +4
-0+ + ksft_ge(len(cpus), 2, comment=f"Received traffic on less than two cpus") + else: + raise KsftSkipEx("Symmetric RSS hash not requested")Flip the condition, raise the exception right after the if, then the rest of the code doesn't have to be indented?
Ack.
Quoted 5 lines
I'd also add a:
if len(cpus) == 1: raise KsftSkipEx(f"Only one CPU seen traffic: {cpus}")
It's covered by the less than two CPUs check, I added a print of cpus to the existing check.