Skip to content

Commit 4c2cb7d

Browse files
committed
Merge: CNB101: ethtool: Block setting of symmetric RSS when non-symmetric rx-flow-hash is requested
MR: https://gitlab.com/redhat/rhel/src/kernel/rhel-10/-/merge_requests/323 JIRA: https://issues.redhat.com/browse/RHEL-107023 commit 1b2900d Author: Gal Pressman <gal@nvidia.com> Date: Thu May 8 13:30:34 2025 +0300 ethtool: Block setting of symmetric RSS when non-symmetric rx-flow-hash is requested Symmetric RSS hash requires that: * No other fields besides IP src/dst and/or L4 src/dst are set * If src is set, dst must also be set This restriction was only enforced when RXNFC was configured after symmetric hash was enabled. In the opposite order of operations (RXNFC then symmetric enablement) the check was not performed. Perform the sanity check on set_rxfh as well, by iterating over all flow types hash fields and making sure they are all symmetric. Introduce a function that returns whether a flow type is hashable (not spec only) and needs to be iterated over. To make sure that no one forgets to update the list of hashable flow types when adding new flow types, a static assert is added to draw the developer's attention. The conversion of uapi #defines to enum is not ideal, but as Jakub mentioned [1], we have precedent for that. [1] https://lore.kernel.org/netdev/20250324073509.6571ade3@kernel.org/ Reviewed-by: Tariq Toukan <tariqt@nvidia.com> Signed-off-by: Gal Pressman <gal@nvidia.com> Reviewed-by: Simon Horman <horms@kernel.org> Link: https://patch.msgid.link/20250508103034.885536-1-gal@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com> Approved-by: Ivan Vecera <ivecera@redhat.com> Approved-by: mheib <mheib@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Jan Stancek <jstancek@redhat.com>
2 parents b98c012 + 358952b commit 4c2cb7d

File tree

2 files changed

+158
-75
lines changed

2 files changed

+158
-75
lines changed

include/uapi/linux/ethtool.h

Lines changed: 69 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2295,71 +2295,75 @@ static inline int ethtool_validate_duplex(__u8 duplex)
22952295
#define RXH_XFRM_SYM_OR_XOR (1 << 1)
22962296
#define RXH_XFRM_NO_CHANGE 0xff
22972297

2298-
/* L2-L4 network traffic flow types */
2299-
#define TCP_V4_FLOW 0x01 /* hash or spec (tcp_ip4_spec) */
2300-
#define UDP_V4_FLOW 0x02 /* hash or spec (udp_ip4_spec) */
2301-
#define SCTP_V4_FLOW 0x03 /* hash or spec (sctp_ip4_spec) */
2302-
#define AH_ESP_V4_FLOW 0x04 /* hash only */
2303-
#define TCP_V6_FLOW 0x05 /* hash or spec (tcp_ip6_spec; nfc only) */
2304-
#define UDP_V6_FLOW 0x06 /* hash or spec (udp_ip6_spec; nfc only) */
2305-
#define SCTP_V6_FLOW 0x07 /* hash or spec (sctp_ip6_spec; nfc only) */
2306-
#define AH_ESP_V6_FLOW 0x08 /* hash only */
2307-
#define AH_V4_FLOW 0x09 /* hash or spec (ah_ip4_spec) */
2308-
#define ESP_V4_FLOW 0x0a /* hash or spec (esp_ip4_spec) */
2309-
#define AH_V6_FLOW 0x0b /* hash or spec (ah_ip6_spec; nfc only) */
2310-
#define ESP_V6_FLOW 0x0c /* hash or spec (esp_ip6_spec; nfc only) */
2311-
#define IPV4_USER_FLOW 0x0d /* spec only (usr_ip4_spec) */
2312-
#define IP_USER_FLOW IPV4_USER_FLOW
2313-
#define IPV6_USER_FLOW 0x0e /* spec only (usr_ip6_spec; nfc only) */
2314-
#define IPV4_FLOW 0x10 /* hash only */
2315-
#define IPV6_FLOW 0x11 /* hash only */
2316-
#define ETHER_FLOW 0x12 /* spec only (ether_spec) */
2317-
2318-
/* Used for GTP-U IPv4 and IPv6.
2319-
* The format of GTP packets only includes
2320-
* elements such as TEID and GTP version.
2321-
* It is primarily intended for data communication of the UE.
2322-
*/
2323-
#define GTPU_V4_FLOW 0x13 /* hash only */
2324-
#define GTPU_V6_FLOW 0x14 /* hash only */
2325-
2326-
/* Use for GTP-C IPv4 and v6.
2327-
* The format of these GTP packets does not include TEID.
2328-
* Primarily expected to be used for communication
2329-
* to create sessions for UE data communication,
2330-
* commonly referred to as CSR (Create Session Request).
2331-
*/
2332-
#define GTPC_V4_FLOW 0x15 /* hash only */
2333-
#define GTPC_V6_FLOW 0x16 /* hash only */
2334-
2335-
/* Use for GTP-C IPv4 and v6.
2336-
* Unlike GTPC_V4_FLOW, the format of these GTP packets includes TEID.
2337-
* After session creation, it becomes this packet.
2338-
* This is mainly used for requests to realize UE handover.
2339-
*/
2340-
#define GTPC_TEID_V4_FLOW 0x17 /* hash only */
2341-
#define GTPC_TEID_V6_FLOW 0x18 /* hash only */
2342-
2343-
/* Use for GTP-U and extended headers for the PSC (PDU Session Container).
2344-
* The format of these GTP packets includes TEID and QFI.
2345-
* In 5G communication using UPF (User Plane Function),
2346-
* data communication with this extended header is performed.
2347-
*/
2348-
#define GTPU_EH_V4_FLOW 0x19 /* hash only */
2349-
#define GTPU_EH_V6_FLOW 0x1a /* hash only */
2350-
2351-
/* Use for GTP-U IPv4 and v6 PSC (PDU Session Container) extended headers.
2352-
* This differs from GTPU_EH_V(4|6)_FLOW in that it is distinguished by
2353-
* UL/DL included in the PSC.
2354-
* There are differences in the data included based on Downlink/Uplink,
2355-
* and can be used to distinguish packets.
2356-
* The functions described so far are useful when you want to
2357-
* handle communication from the mobile network in UPF, PGW, etc.
2358-
*/
2359-
#define GTPU_UL_V4_FLOW 0x1b /* hash only */
2360-
#define GTPU_UL_V6_FLOW 0x1c /* hash only */
2361-
#define GTPU_DL_V4_FLOW 0x1d /* hash only */
2362-
#define GTPU_DL_V6_FLOW 0x1e /* hash only */
2298+
enum {
2299+
/* L2-L4 network traffic flow types */
2300+
TCP_V4_FLOW = 0x01, /* hash or spec (tcp_ip4_spec) */
2301+
UDP_V4_FLOW = 0x02, /* hash or spec (udp_ip4_spec) */
2302+
SCTP_V4_FLOW = 0x03, /* hash or spec (sctp_ip4_spec) */
2303+
AH_ESP_V4_FLOW = 0x04, /* hash only */
2304+
TCP_V6_FLOW = 0x05, /* hash or spec (tcp_ip6_spec; nfc only) */
2305+
UDP_V6_FLOW = 0x06, /* hash or spec (udp_ip6_spec; nfc only) */
2306+
SCTP_V6_FLOW = 0x07, /* hash or spec (sctp_ip6_spec; nfc only) */
2307+
AH_ESP_V6_FLOW = 0x08, /* hash only */
2308+
AH_V4_FLOW = 0x09, /* hash or spec (ah_ip4_spec) */
2309+
ESP_V4_FLOW = 0x0a, /* hash or spec (esp_ip4_spec) */
2310+
AH_V6_FLOW = 0x0b, /* hash or spec (ah_ip6_spec; nfc only) */
2311+
ESP_V6_FLOW = 0x0c, /* hash or spec (esp_ip6_spec; nfc only) */
2312+
IPV4_USER_FLOW = 0x0d, /* spec only (usr_ip4_spec) */
2313+
IP_USER_FLOW = IPV4_USER_FLOW,
2314+
IPV6_USER_FLOW = 0x0e, /* spec only (usr_ip6_spec; nfc only) */
2315+
IPV4_FLOW = 0x10, /* hash only */
2316+
IPV6_FLOW = 0x11, /* hash only */
2317+
ETHER_FLOW = 0x12, /* spec only (ether_spec) */
2318+
2319+
/* Used for GTP-U IPv4 and IPv6.
2320+
* The format of GTP packets only includes
2321+
* elements such as TEID and GTP version.
2322+
* It is primarily intended for data communication of the UE.
2323+
*/
2324+
GTPU_V4_FLOW = 0x13, /* hash only */
2325+
GTPU_V6_FLOW = 0x14, /* hash only */
2326+
2327+
/* Use for GTP-C IPv4 and v6.
2328+
* The format of these GTP packets does not include TEID.
2329+
* Primarily expected to be used for communication
2330+
* to create sessions for UE data communication,
2331+
* commonly referred to as CSR (Create Session Request).
2332+
*/
2333+
GTPC_V4_FLOW = 0x15, /* hash only */
2334+
GTPC_V6_FLOW = 0x16, /* hash only */
2335+
2336+
/* Use for GTP-C IPv4 and v6.
2337+
* Unlike GTPC_V4_FLOW, the format of these GTP packets includes TEID.
2338+
* After session creation, it becomes this packet.
2339+
* This is mainly used for requests to realize UE handover.
2340+
*/
2341+
GTPC_TEID_V4_FLOW = 0x17, /* hash only */
2342+
GTPC_TEID_V6_FLOW = 0x18, /* hash only */
2343+
2344+
/* Use for GTP-U and extended headers for the PSC (PDU Session Container).
2345+
* The format of these GTP packets includes TEID and QFI.
2346+
* In 5G communication using UPF (User Plane Function),
2347+
* data communication with this extended header is performed.
2348+
*/
2349+
GTPU_EH_V4_FLOW = 0x19, /* hash only */
2350+
GTPU_EH_V6_FLOW = 0x1a, /* hash only */
2351+
2352+
/* Use for GTP-U IPv4 and v6 PSC (PDU Session Container) extended headers.
2353+
* This differs from GTPU_EH_V(4|6)_FLOW in that it is distinguished by
2354+
* UL/DL included in the PSC.
2355+
* There are differences in the data included based on Downlink/Uplink,
2356+
* and can be used to distinguish packets.
2357+
* The functions described so far are useful when you want to
2358+
* handle communication from the mobile network in UPF, PGW, etc.
2359+
*/
2360+
GTPU_UL_V4_FLOW = 0x1b, /* hash only */
2361+
GTPU_UL_V6_FLOW = 0x1c, /* hash only */
2362+
GTPU_DL_V4_FLOW = 0x1d, /* hash only */
2363+
GTPU_DL_V6_FLOW = 0x1e, /* hash only */
2364+
2365+
__FLOW_TYPE_COUNT,
2366+
};
23632367

23642368
/* Flag to enable additional fields in struct ethtool_rx_flow_spec */
23652369
#define FLOW_EXT 0x80000000

net/ethtool/ioctl.c

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,88 @@ static int ethtool_rxnfc_copy_to_user(void __user *useraddr,
977977
return 0;
978978
}
979979

980+
static bool flow_type_hashable(u32 flow_type)
981+
{
982+
switch (flow_type) {
983+
case TCP_V4_FLOW:
984+
case UDP_V4_FLOW:
985+
case SCTP_V4_FLOW:
986+
case AH_ESP_V4_FLOW:
987+
case TCP_V6_FLOW:
988+
case UDP_V6_FLOW:
989+
case SCTP_V6_FLOW:
990+
case AH_ESP_V6_FLOW:
991+
case AH_V4_FLOW:
992+
case ESP_V4_FLOW:
993+
case AH_V6_FLOW:
994+
case ESP_V6_FLOW:
995+
case IPV4_FLOW:
996+
case IPV6_FLOW:
997+
case GTPU_V4_FLOW:
998+
case GTPU_V6_FLOW:
999+
case GTPC_V4_FLOW:
1000+
case GTPC_V6_FLOW:
1001+
case GTPC_TEID_V4_FLOW:
1002+
case GTPC_TEID_V6_FLOW:
1003+
case GTPU_EH_V4_FLOW:
1004+
case GTPU_EH_V6_FLOW:
1005+
case GTPU_UL_V4_FLOW:
1006+
case GTPU_UL_V6_FLOW:
1007+
case GTPU_DL_V4_FLOW:
1008+
case GTPU_DL_V6_FLOW:
1009+
return true;
1010+
}
1011+
1012+
return false;
1013+
}
1014+
1015+
/* When adding a new type, update the assert and, if it's hashable, add it to
1016+
* the flow_type_hashable switch case.
1017+
*/
1018+
static_assert(GTPU_DL_V6_FLOW + 1 == __FLOW_TYPE_COUNT);
1019+
1020+
static int ethtool_check_xfrm_rxfh(u32 input_xfrm, u64 rxfh)
1021+
{
1022+
/* Sanity check: if symmetric-xor/symmetric-or-xor is set, then:
1023+
* 1 - no other fields besides IP src/dst and/or L4 src/dst are set
1024+
* 2 - If src is set, dst must also be set
1025+
*/
1026+
if ((input_xfrm != RXH_XFRM_NO_CHANGE &&
1027+
input_xfrm & (RXH_XFRM_SYM_XOR | RXH_XFRM_SYM_OR_XOR)) &&
1028+
((rxfh & ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)) ||
1029+
(!!(rxfh & RXH_IP_SRC) ^ !!(rxfh & RXH_IP_DST)) ||
1030+
(!!(rxfh & RXH_L4_B_0_1) ^ !!(rxfh & RXH_L4_B_2_3))))
1031+
return -EINVAL;
1032+
1033+
return 0;
1034+
}
1035+
1036+
static int ethtool_check_flow_types(struct net_device *dev, u32 input_xfrm)
1037+
{
1038+
const struct ethtool_ops *ops = dev->ethtool_ops;
1039+
struct ethtool_rxnfc info = {
1040+
.cmd = ETHTOOL_GRXFH,
1041+
};
1042+
int err;
1043+
u32 i;
1044+
1045+
for (i = 0; i < __FLOW_TYPE_COUNT; i++) {
1046+
if (!flow_type_hashable(i))
1047+
continue;
1048+
1049+
info.flow_type = i;
1050+
err = ops->get_rxnfc(dev, &info, NULL);
1051+
if (err)
1052+
continue;
1053+
1054+
err = ethtool_check_xfrm_rxfh(input_xfrm, info.data);
1055+
if (err)
1056+
return err;
1057+
}
1058+
1059+
return 0;
1060+
}
1061+
9801062
static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
9811063
u32 cmd, void __user *useraddr)
9821064
{
@@ -1012,16 +1094,9 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
10121094
if (rc)
10131095
return rc;
10141096

1015-
/* Sanity check: if symmetric-xor/symmetric-or-xor is set, then:
1016-
* 1 - no other fields besides IP src/dst and/or L4 src/dst
1017-
* 2 - If src is set, dst must also be set
1018-
*/
1019-
if ((rxfh.input_xfrm & (RXH_XFRM_SYM_XOR | RXH_XFRM_SYM_OR_XOR)) &&
1020-
((info.data & ~(RXH_IP_SRC | RXH_IP_DST |
1021-
RXH_L4_B_0_1 | RXH_L4_B_2_3)) ||
1022-
(!!(info.data & RXH_IP_SRC) ^ !!(info.data & RXH_IP_DST)) ||
1023-
(!!(info.data & RXH_L4_B_0_1) ^ !!(info.data & RXH_L4_B_2_3))))
1024-
return -EINVAL;
1097+
rc = ethtool_check_xfrm_rxfh(rxfh.input_xfrm, info.data);
1098+
if (rc)
1099+
return rc;
10251100
}
10261101

10271102
rc = ops->set_rxnfc(dev, &info);
@@ -1413,6 +1488,10 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
14131488
rxfh.input_xfrm == RXH_XFRM_NO_CHANGE))
14141489
return -EINVAL;
14151490

1491+
ret = ethtool_check_flow_types(dev, rxfh.input_xfrm);
1492+
if (ret)
1493+
return ret;
1494+
14161495
indir_bytes = dev_indir_size * sizeof(rxfh_dev.indir[0]);
14171496

14181497
/* Check settings which may be global rather than per RSS-context */

0 commit comments

Comments
 (0)