Skip to content

Commit 84a1d9c

Browse files
ecree-solarflaredavem330
authored andcommitted
net: ethtool: extend RXNFC API to support RSS spreading of filter matches
We use a two-step process to configure a filter with RSS spreading. First, the RSS context is allocated and configured using ETHTOOL_SRSSH; this returns an identifier (rss_context) which can then be passed to subsequent invocations of ETHTOOL_SRXCLSRLINS to specify that the offset from the RSS indirection table lookup should be added to the queue number (ring_cookie) when delivering the packet. Drivers for devices which can only use the indirection table entry directly (not add it to a base queue number) should reject rule insertions combining RSS with a nonzero ring_cookie. Signed-off-by: Edward Cree <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 571e677 commit 84a1d9c

File tree

3 files changed

+80
-21
lines changed

3 files changed

+80
-21
lines changed

include/linux/ethtool.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,11 @@ struct ethtool_ops {
371371
u8 *hfunc);
372372
int (*set_rxfh)(struct net_device *, const u32 *indir,
373373
const u8 *key, const u8 hfunc);
374+
int (*get_rxfh_context)(struct net_device *, u32 *indir, u8 *key,
375+
u8 *hfunc, u32 rss_context);
376+
int (*set_rxfh_context)(struct net_device *, const u32 *indir,
377+
const u8 *key, const u8 hfunc,
378+
u32 *rss_context, bool delete);
374379
void (*get_channels)(struct net_device *, struct ethtool_channels *);
375380
int (*set_channels)(struct net_device *, struct ethtool_channels *);
376381
int (*get_dump_flag)(struct net_device *, struct ethtool_dump *);

include/uapi/linux/ethtool.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -914,12 +914,15 @@ static inline __u64 ethtool_get_flow_spec_ring_vf(__u64 ring_cookie)
914914
* @flow_type: Type of flow to be affected, e.g. %TCP_V4_FLOW
915915
* @data: Command-dependent value
916916
* @fs: Flow classification rule
917+
* @rss_context: RSS context to be affected
917918
* @rule_cnt: Number of rules to be affected
918919
* @rule_locs: Array of used rule locations
919920
*
920921
* For %ETHTOOL_GRXFH and %ETHTOOL_SRXFH, @data is a bitmask indicating
921922
* the fields included in the flow hash, e.g. %RXH_IP_SRC. The following
922-
* structure fields must not be used.
923+
* structure fields must not be used, except that if @flow_type includes
924+
* the %FLOW_RSS flag, then @rss_context determines which RSS context to
925+
* act on.
923926
*
924927
* For %ETHTOOL_GRXRINGS, @data is set to the number of RX rings/queues
925928
* on return.
@@ -931,7 +934,9 @@ static inline __u64 ethtool_get_flow_spec_ring_vf(__u64 ring_cookie)
931934
* set in @data then special location values should not be used.
932935
*
933936
* For %ETHTOOL_GRXCLSRULE, @fs.@location specifies the location of an
934-
* existing rule on entry and @fs contains the rule on return.
937+
* existing rule on entry and @fs contains the rule on return; if
938+
* @fs.@flow_type includes the %FLOW_RSS flag, then @rss_context is
939+
* filled with the RSS context ID associated with the rule.
935940
*
936941
* For %ETHTOOL_GRXCLSRLALL, @rule_cnt specifies the array size of the
937942
* user buffer for @rule_locs on entry. On return, @data is the size
@@ -942,7 +947,11 @@ static inline __u64 ethtool_get_flow_spec_ring_vf(__u64 ring_cookie)
942947
* For %ETHTOOL_SRXCLSRLINS, @fs specifies the rule to add or update.
943948
* @fs.@location either specifies the location to use or is a special
944949
* location value with %RX_CLS_LOC_SPECIAL flag set. On return,
945-
* @fs.@location is the actual rule location.
950+
* @fs.@location is the actual rule location. If @fs.@flow_type
951+
* includes the %FLOW_RSS flag, @rss_context is the RSS context ID to
952+
* use for flow spreading traffic which matches this rule. The value
953+
* from the rxfh indirection table will be added to @fs.@ring_cookie
954+
* to choose which ring to deliver to.
946955
*
947956
* For %ETHTOOL_SRXCLSRLDEL, @fs.@location specifies the location of an
948957
* existing rule on entry.
@@ -963,7 +972,10 @@ struct ethtool_rxnfc {
963972
__u32 flow_type;
964973
__u64 data;
965974
struct ethtool_rx_flow_spec fs;
966-
__u32 rule_cnt;
975+
union {
976+
__u32 rule_cnt;
977+
__u32 rss_context;
978+
};
967979
__u32 rule_locs[0];
968980
};
969981

@@ -990,7 +1002,11 @@ struct ethtool_rxfh_indir {
9901002
/**
9911003
* struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key.
9921004
* @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH
993-
* @rss_context: RSS context identifier.
1005+
* @rss_context: RSS context identifier. Context 0 is the default for normal
1006+
* traffic; other contexts can be referenced as the destination for RX flow
1007+
* classification rules. %ETH_RXFH_CONTEXT_ALLOC is used with command
1008+
* %ETHTOOL_SRSSH to allocate a new RSS context; on return this field will
1009+
* contain the ID of the newly allocated context.
9941010
* @indir_size: On entry, the array size of the user buffer for the
9951011
* indirection table, which may be zero, or (for %ETHTOOL_SRSSH),
9961012
* %ETH_RXFH_INDIR_NO_CHANGE. On return from %ETHTOOL_GRSSH,
@@ -1009,7 +1025,8 @@ struct ethtool_rxfh_indir {
10091025
* size should be returned. For %ETHTOOL_SRSSH, an @indir_size of
10101026
* %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested
10111027
* and a @indir_size of zero means the indir table should be reset to default
1012-
* values. An hfunc of zero means that hash function setting is not requested.
1028+
* values (if @rss_context == 0) or that the RSS context should be deleted.
1029+
* An hfunc of zero means that hash function setting is not requested.
10131030
*/
10141031
struct ethtool_rxfh {
10151032
__u32 cmd;
@@ -1021,6 +1038,7 @@ struct ethtool_rxfh {
10211038
__u32 rsvd32;
10221039
__u32 rss_config[0];
10231040
};
1041+
#define ETH_RXFH_CONTEXT_ALLOC 0xffffffff
10241042
#define ETH_RXFH_INDIR_NO_CHANGE 0xffffffff
10251043

10261044
/**
@@ -1635,6 +1653,8 @@ static inline int ethtool_validate_duplex(__u8 duplex)
16351653
/* Flag to enable additional fields in struct ethtool_rx_flow_spec */
16361654
#define FLOW_EXT 0x80000000
16371655
#define FLOW_MAC_EXT 0x40000000
1656+
/* Flag to enable RSS spreading of traffic matching rule (nfc only) */
1657+
#define FLOW_RSS 0x20000000
16381658

16391659
/* L3-L4 network traffic flow hash options */
16401660
#define RXH_L2DA (1 << 1)

net/core/ethtool.c

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,15 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
10221022
if (copy_from_user(&info, useraddr, info_size))
10231023
return -EFAULT;
10241024

1025+
/* If FLOW_RSS was requested then user-space must be using the
1026+
* new definition, as FLOW_RSS is newer.
1027+
*/
1028+
if (cmd == ETHTOOL_GRXFH && info.flow_type & FLOW_RSS) {
1029+
info_size = sizeof(info);
1030+
if (copy_from_user(&info, useraddr, info_size))
1031+
return -EFAULT;
1032+
}
1033+
10251034
if (info.cmd == ETHTOOL_GRXCLSRLALL) {
10261035
if (info.rule_cnt > 0) {
10271036
if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32))
@@ -1251,9 +1260,11 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
12511260
user_key_size = rxfh.key_size;
12521261

12531262
/* Check that reserved fields are 0 for now */
1254-
if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] ||
1255-
rxfh.rsvd8[2] || rxfh.rsvd32)
1263+
if (rxfh.rsvd8[0] || rxfh.rsvd8[1] || rxfh.rsvd8[2] || rxfh.rsvd32)
12561264
return -EINVAL;
1265+
/* Most drivers don't handle rss_context, check it's 0 as well */
1266+
if (rxfh.rss_context && !ops->get_rxfh_context)
1267+
return -EOPNOTSUPP;
12571268

12581269
rxfh.indir_size = dev_indir_size;
12591270
rxfh.key_size = dev_key_size;
@@ -1276,7 +1287,12 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
12761287
if (user_key_size)
12771288
hkey = rss_config + indir_bytes;
12781289

1279-
ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc);
1290+
if (rxfh.rss_context)
1291+
ret = dev->ethtool_ops->get_rxfh_context(dev, indir, hkey,
1292+
&dev_hfunc,
1293+
rxfh.rss_context);
1294+
else
1295+
ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc);
12801296
if (ret)
12811297
goto out;
12821298

@@ -1306,6 +1322,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
13061322
u8 *hkey = NULL;
13071323
u8 *rss_config;
13081324
u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
1325+
bool delete = false;
13091326

13101327
if (!ops->get_rxnfc || !ops->set_rxfh)
13111328
return -EOPNOTSUPP;
@@ -1319,9 +1336,11 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
13191336
return -EFAULT;
13201337

13211338
/* Check that reserved fields are 0 for now */
1322-
if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] ||
1323-
rxfh.rsvd8[2] || rxfh.rsvd32)
1339+
if (rxfh.rsvd8[0] || rxfh.rsvd8[1] || rxfh.rsvd8[2] || rxfh.rsvd32)
13241340
return -EINVAL;
1341+
/* Most drivers don't handle rss_context, check it's 0 as well */
1342+
if (rxfh.rss_context && !ops->set_rxfh_context)
1343+
return -EOPNOTSUPP;
13251344

13261345
/* If either indir, hash key or function is valid, proceed further.
13271346
* Must request at least one change: indir size, hash key or function.
@@ -1346,7 +1365,8 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
13461365
if (ret)
13471366
goto out;
13481367

1349-
/* rxfh.indir_size == 0 means reset the indir table to default.
1368+
/* rxfh.indir_size == 0 means reset the indir table to default (master
1369+
* context) or delete the context (other RSS contexts).
13501370
* rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged.
13511371
*/
13521372
if (rxfh.indir_size &&
@@ -1359,9 +1379,13 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
13591379
if (ret)
13601380
goto out;
13611381
} else if (rxfh.indir_size == 0) {
1362-
indir = (u32 *)rss_config;
1363-
for (i = 0; i < dev_indir_size; i++)
1364-
indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
1382+
if (rxfh.rss_context == 0) {
1383+
indir = (u32 *)rss_config;
1384+
for (i = 0; i < dev_indir_size; i++)
1385+
indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
1386+
} else {
1387+
delete = true;
1388+
}
13651389
}
13661390

13671391
if (rxfh.key_size) {
@@ -1374,15 +1398,25 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
13741398
}
13751399
}
13761400

1377-
ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc);
1401+
if (rxfh.rss_context)
1402+
ret = ops->set_rxfh_context(dev, indir, hkey, rxfh.hfunc,
1403+
&rxfh.rss_context, delete);
1404+
else
1405+
ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc);
13781406
if (ret)
13791407
goto out;
13801408

1381-
/* indicate whether rxfh was set to default */
1382-
if (rxfh.indir_size == 0)
1383-
dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
1384-
else if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
1385-
dev->priv_flags |= IFF_RXFH_CONFIGURED;
1409+
if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, rss_context),
1410+
&rxfh.rss_context, sizeof(rxfh.rss_context)))
1411+
ret = -EFAULT;
1412+
1413+
if (!rxfh.rss_context) {
1414+
/* indicate whether rxfh was set to default */
1415+
if (rxfh.indir_size == 0)
1416+
dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
1417+
else if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
1418+
dev->priv_flags |= IFF_RXFH_CONFIGURED;
1419+
}
13861420

13871421
out:
13881422
kfree(rss_config);

0 commit comments

Comments
 (0)