Commit 04c04725 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'support-symmetric-xor-rss-hash'

Ahmed Zaki says:

====================
Support symmetric-xor RSS hash

Patches 1 and 2 modify the get/set_rxh ethtool API to take a pointer to
struct of parameters instead of individual params. This will allow future
changes to the uAPI-shared struct ethtool_rxfh without changing the
drivers' API.

Patch 3 adds the support at the Kernel level, allowing the user to set a
symmetric-xor RSS hash for a netdevice via:

    # ethtool -X eth0 hfunc toeplitz symmetric-xor

and clears the flag via:

    # ethtool -X eth0 hfunc toeplitz

The "symmetric-xor" is set in a new "input_xfrm" field in struct
ethtool_rxfh. Support for the new "symmetric-xor" flag will be later sent
to the "ethtool" user-space tool.

Patch 4 fixes a long standing bug with the ice hash function register
values. The bug has been benign for now since only (asymmetric) Toeplitz
hash (Zero) has been used.

Patches 5 and 6 lay some groundwork refactoring. While the first is
mainly cosmetic, the second is needed since there is no more room in the
previous 64-bit RSS profile ID for the symmetric attribute introduced in
the next patch.

Finally, patches 7 and 8 add the symmetric-xor support for the ice
(E800 PFs) and the iAVF drivers.
====================

Link: https://lore.kernel.org/r/20231213003321.605376-1-ahmed.zaki@intel.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents c3f687d8 4a3de3fb
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -908,6 +908,9 @@ attribute-sets:
      -
        name: hkey
        type: binary
      -
        name: input_xfrm
        type: u32
  -
    name: plca
    attributes:
@@ -1598,6 +1601,7 @@ operations:
            - hfunc
            - indir
            - hkey
            - input_xfrm
      dump: *rss-get-op
    -
      name: plca-get-cfg
+5 −1
Original line number Diff line number Diff line
@@ -1774,12 +1774,16 @@ Kernel response contents:
  ``ETHTOOL_A_RSS_HFUNC``              u32     RSS hash func
  ``ETHTOOL_A_RSS_INDIR``              binary  Indir table bytes
  ``ETHTOOL_A_RSS_HKEY``               binary  Hash key bytes
  ``ETHTOOL_A_RSS_INPUT_XFRM``         u32     RSS input data transformation
=====================================  ======  ==========================

ETHTOOL_A_RSS_HFUNC attribute is bitmap indicating the hash function
being used. Current supported options are toeplitz, xor or crc32.
ETHTOOL_A_RSS_INDIR attribute returns RSS indrection table where each byte
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.

PLCA_GET_CFG
============
+15 −0
Original line number Diff line number Diff line
@@ -44,6 +44,21 @@ by masking out the low order seven bits of the computed hash for the
packet (usually a Toeplitz hash), taking this number as a key into the
indirection table and reading the corresponding value.

Some NICs support symmetric RSS hashing where, if the IP (source address,
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
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
programmable filters. For example, webserver bound TCP port 80 packets
can be directed to their own receive queue. Such “n-tuple” filters can
+14 −14
Original line number Diff line number Diff line
@@ -802,15 +802,15 @@ static int ena_indirection_table_get(struct ena_adapter *adapter, u32 *indir)
	return rc;
}

static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
			u8 *hfunc)
static int ena_get_rxfh(struct net_device *netdev,
			struct ethtool_rxfh_param *rxfh)
{
	struct ena_adapter *adapter = netdev_priv(netdev);
	enum ena_admin_hash_functions ena_func;
	u8 func;
	int rc;

	rc = ena_indirection_table_get(adapter, indir);
	rc = ena_indirection_table_get(adapter, rxfh->indir);
	if (rc)
		return rc;

@@ -825,7 +825,7 @@ static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
		return rc;
	}

	rc = ena_com_get_hash_key(adapter->ena_dev, key);
	rc = ena_com_get_hash_key(adapter->ena_dev, rxfh->key);
	if (rc)
		return rc;

@@ -842,27 +842,27 @@ static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
		return -EOPNOTSUPP;
	}

	if (hfunc)
		*hfunc = func;
	rxfh->hfunc = func;

	return 0;
}

static int ena_set_rxfh(struct net_device *netdev, const u32 *indir,
			const u8 *key, const u8 hfunc)
static int ena_set_rxfh(struct net_device *netdev,
			struct ethtool_rxfh_param *rxfh,
			struct netlink_ext_ack *extack)
{
	struct ena_adapter *adapter = netdev_priv(netdev);
	struct ena_com_dev *ena_dev = adapter->ena_dev;
	enum ena_admin_hash_functions func = 0;
	int rc;

	if (indir) {
		rc = ena_indirection_table_set(adapter, indir);
	if (rxfh->indir) {
		rc = ena_indirection_table_set(adapter, rxfh->indir);
		if (rc)
			return rc;
	}

	switch (hfunc) {
	switch (rxfh->hfunc) {
	case ETH_RSS_HASH_NO_CHANGE:
		func = ena_com_get_current_hash_function(ena_dev);
		break;
@@ -874,12 +874,12 @@ static int ena_set_rxfh(struct net_device *netdev, const u32 *indir,
		break;
	default:
		netif_err(adapter, drv, netdev, "Unsupported hfunc %d\n",
			  hfunc);
			  rxfh->hfunc);
		return -EOPNOTSUPP;
	}

	if (key || func) {
		rc = ena_com_fill_hash_function(ena_dev, func, key,
	if (rxfh->key || func) {
		rc = ena_com_fill_hash_function(ena_dev, func, rxfh->key,
						ENA_HASH_KEY_SIZE,
						0xFFFFFFFF);
		if (unlikely(rc)) {
+17 −16
Original line number Diff line number Diff line
@@ -527,47 +527,48 @@ static u32 xgbe_get_rxfh_indir_size(struct net_device *netdev)
	return ARRAY_SIZE(pdata->rss_table);
}

static int xgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
			 u8 *hfunc)
static int xgbe_get_rxfh(struct net_device *netdev,
			 struct ethtool_rxfh_param *rxfh)
{
	struct xgbe_prv_data *pdata = netdev_priv(netdev);
	unsigned int i;

	if (indir) {
	if (rxfh->indir) {
		for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++)
			indir[i] = XGMAC_GET_BITS(pdata->rss_table[i],
			rxfh->indir[i] = XGMAC_GET_BITS(pdata->rss_table[i],
							MAC_RSSDR, DMCH);
	}

	if (key)
		memcpy(key, pdata->rss_key, sizeof(pdata->rss_key));
	if (rxfh->key)
		memcpy(rxfh->key, pdata->rss_key, sizeof(pdata->rss_key));

	if (hfunc)
		*hfunc = ETH_RSS_HASH_TOP;
	rxfh->hfunc = ETH_RSS_HASH_TOP;

	return 0;
}

static int xgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
			 const u8 *key, const u8 hfunc)
static int xgbe_set_rxfh(struct net_device *netdev,
			 struct ethtool_rxfh_param *rxfh,
			 struct netlink_ext_ack *extack)
{
	struct xgbe_prv_data *pdata = netdev_priv(netdev);
	struct xgbe_hw_if *hw_if = &pdata->hw_if;
	unsigned int ret;

	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) {
	if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
	    rxfh->hfunc != ETH_RSS_HASH_TOP) {
		netdev_err(netdev, "unsupported hash function\n");
		return -EOPNOTSUPP;
	}

	if (indir) {
		ret = hw_if->set_rss_lookup_table(pdata, indir);
	if (rxfh->indir) {
		ret = hw_if->set_rss_lookup_table(pdata, rxfh->indir);
		if (ret)
			return ret;
	}

	if (key) {
		ret = hw_if->set_rss_hash_key(pdata, key);
	if (rxfh->key) {
		ret = hw_if->set_rss_hash_key(pdata, rxfh->key);
		if (ret)
			return ret;
	}
Loading