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

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 <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Edward Cree and committed by
David S. Miller
84a1d9c4 571e6776

+80 -21
+5
include/linux/ethtool.h
··· 371 371 u8 *hfunc); 372 372 int (*set_rxfh)(struct net_device *, const u32 *indir, 373 373 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); 374 379 void (*get_channels)(struct net_device *, struct ethtool_channels *); 375 380 int (*set_channels)(struct net_device *, struct ethtool_channels *); 376 381 int (*get_dump_flag)(struct net_device *, struct ethtool_dump *);
+26 -6
include/uapi/linux/ethtool.h
··· 914 914 * @flow_type: Type of flow to be affected, e.g. %TCP_V4_FLOW 915 915 * @data: Command-dependent value 916 916 * @fs: Flow classification rule 917 + * @rss_context: RSS context to be affected 917 918 * @rule_cnt: Number of rules to be affected 918 919 * @rule_locs: Array of used rule locations 919 920 * 920 921 * For %ETHTOOL_GRXFH and %ETHTOOL_SRXFH, @data is a bitmask indicating 921 922 * 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. 923 926 * 924 927 * For %ETHTOOL_GRXRINGS, @data is set to the number of RX rings/queues 925 928 * on return. ··· 934 931 * set in @data then special location values should not be used. 935 932 * 936 933 * For %ETHTOOL_GRXCLSRULE, @fs.@location specifies the location of an 937 - * existing rule on entry and @fs contains the rule on return. 934 + * existing rule on entry and @fs contains the rule on return; if 935 + * @fs.@flow_type includes the %FLOW_RSS flag, then @rss_context is 936 + * filled with the RSS context ID associated with the rule. 938 937 * 939 938 * For %ETHTOOL_GRXCLSRLALL, @rule_cnt specifies the array size of the 940 939 * user buffer for @rule_locs on entry. On return, @data is the size ··· 947 942 * For %ETHTOOL_SRXCLSRLINS, @fs specifies the rule to add or update. 948 943 * @fs.@location either specifies the location to use or is a special 949 944 * location value with %RX_CLS_LOC_SPECIAL flag set. On return, 950 - * @fs.@location is the actual rule location. 945 + * @fs.@location is the actual rule location. If @fs.@flow_type 946 + * includes the %FLOW_RSS flag, @rss_context is the RSS context ID to 947 + * use for flow spreading traffic which matches this rule. The value 948 + * from the rxfh indirection table will be added to @fs.@ring_cookie 949 + * to choose which ring to deliver to. 951 950 * 952 951 * For %ETHTOOL_SRXCLSRLDEL, @fs.@location specifies the location of an 953 952 * existing rule on entry. ··· 972 963 __u32 flow_type; 973 964 __u64 data; 974 965 struct ethtool_rx_flow_spec fs; 975 - __u32 rule_cnt; 966 + union { 967 + __u32 rule_cnt; 968 + __u32 rss_context; 969 + }; 976 970 __u32 rule_locs[0]; 977 971 }; 978 972 ··· 1002 990 /** 1003 991 * struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key. 1004 992 * @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH 1005 - * @rss_context: RSS context identifier. 993 + * @rss_context: RSS context identifier. Context 0 is the default for normal 994 + * traffic; other contexts can be referenced as the destination for RX flow 995 + * classification rules. %ETH_RXFH_CONTEXT_ALLOC is used with command 996 + * %ETHTOOL_SRSSH to allocate a new RSS context; on return this field will 997 + * contain the ID of the newly allocated context. 1006 998 * @indir_size: On entry, the array size of the user buffer for the 1007 999 * indirection table, which may be zero, or (for %ETHTOOL_SRSSH), 1008 1000 * %ETH_RXFH_INDIR_NO_CHANGE. On return from %ETHTOOL_GRSSH, ··· 1025 1009 * size should be returned. For %ETHTOOL_SRSSH, an @indir_size of 1026 1010 * %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested 1027 1011 * and a @indir_size of zero means the indir table should be reset to default 1028 - * values. An hfunc of zero means that hash function setting is not requested. 1012 + * values (if @rss_context == 0) or that the RSS context should be deleted. 1013 + * An hfunc of zero means that hash function setting is not requested. 1029 1014 */ 1030 1015 struct ethtool_rxfh { 1031 1016 __u32 cmd; ··· 1038 1021 __u32 rsvd32; 1039 1022 __u32 rss_config[0]; 1040 1023 }; 1024 + #define ETH_RXFH_CONTEXT_ALLOC 0xffffffff 1041 1025 #define ETH_RXFH_INDIR_NO_CHANGE 0xffffffff 1042 1026 1043 1027 /** ··· 1653 1635 /* Flag to enable additional fields in struct ethtool_rx_flow_spec */ 1654 1636 #define FLOW_EXT 0x80000000 1655 1637 #define FLOW_MAC_EXT 0x40000000 1638 + /* Flag to enable RSS spreading of traffic matching rule (nfc only) */ 1639 + #define FLOW_RSS 0x20000000 1656 1640 1657 1641 /* L3-L4 network traffic flow hash options */ 1658 1642 #define RXH_L2DA (1 << 1)
+49 -15
net/core/ethtool.c
··· 1022 1022 if (copy_from_user(&info, useraddr, info_size)) 1023 1023 return -EFAULT; 1024 1024 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 + 1025 1034 if (info.cmd == ETHTOOL_GRXCLSRLALL) { 1026 1035 if (info.rule_cnt > 0) { 1027 1036 if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32)) ··· 1260 1251 user_key_size = rxfh.key_size; 1261 1252 1262 1253 /* Check that reserved fields are 0 for now */ 1263 - if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] || 1264 - rxfh.rsvd8[2] || rxfh.rsvd32) 1254 + if (rxfh.rsvd8[0] || rxfh.rsvd8[1] || rxfh.rsvd8[2] || rxfh.rsvd32) 1265 1255 return -EINVAL; 1256 + /* Most drivers don't handle rss_context, check it's 0 as well */ 1257 + if (rxfh.rss_context && !ops->get_rxfh_context) 1258 + return -EOPNOTSUPP; 1266 1259 1267 1260 rxfh.indir_size = dev_indir_size; 1268 1261 rxfh.key_size = dev_key_size; ··· 1287 1276 if (user_key_size) 1288 1277 hkey = rss_config + indir_bytes; 1289 1278 1290 - ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc); 1279 + if (rxfh.rss_context) 1280 + ret = dev->ethtool_ops->get_rxfh_context(dev, indir, hkey, 1281 + &dev_hfunc, 1282 + rxfh.rss_context); 1283 + else 1284 + ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc); 1291 1285 if (ret) 1292 1286 goto out; 1293 1287 ··· 1322 1306 u8 *hkey = NULL; 1323 1307 u8 *rss_config; 1324 1308 u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); 1309 + bool delete = false; 1325 1310 1326 1311 if (!ops->get_rxnfc || !ops->set_rxfh) 1327 1312 return -EOPNOTSUPP; ··· 1336 1319 return -EFAULT; 1337 1320 1338 1321 /* Check that reserved fields are 0 for now */ 1339 - if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] || 1340 - rxfh.rsvd8[2] || rxfh.rsvd32) 1322 + if (rxfh.rsvd8[0] || rxfh.rsvd8[1] || rxfh.rsvd8[2] || rxfh.rsvd32) 1341 1323 return -EINVAL; 1324 + /* Most drivers don't handle rss_context, check it's 0 as well */ 1325 + if (rxfh.rss_context && !ops->set_rxfh_context) 1326 + return -EOPNOTSUPP; 1342 1327 1343 1328 /* If either indir, hash key or function is valid, proceed further. 1344 1329 * Must request at least one change: indir size, hash key or function. ··· 1365 1346 if (ret) 1366 1347 goto out; 1367 1348 1368 - /* rxfh.indir_size == 0 means reset the indir table to default. 1349 + /* rxfh.indir_size == 0 means reset the indir table to default (master 1350 + * context) or delete the context (other RSS contexts). 1369 1351 * rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged. 1370 1352 */ 1371 1353 if (rxfh.indir_size && ··· 1379 1359 if (ret) 1380 1360 goto out; 1381 1361 } else if (rxfh.indir_size == 0) { 1382 - indir = (u32 *)rss_config; 1383 - for (i = 0; i < dev_indir_size; i++) 1384 - indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); 1362 + if (rxfh.rss_context == 0) { 1363 + indir = (u32 *)rss_config; 1364 + for (i = 0; i < dev_indir_size; i++) 1365 + indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); 1366 + } else { 1367 + delete = true; 1368 + } 1385 1369 } 1386 1370 1387 1371 if (rxfh.key_size) { ··· 1398 1374 } 1399 1375 } 1400 1376 1401 - ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc); 1377 + if (rxfh.rss_context) 1378 + ret = ops->set_rxfh_context(dev, indir, hkey, rxfh.hfunc, 1379 + &rxfh.rss_context, delete); 1380 + else 1381 + ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc); 1402 1382 if (ret) 1403 1383 goto out; 1404 1384 1405 - /* indicate whether rxfh was set to default */ 1406 - if (rxfh.indir_size == 0) 1407 - dev->priv_flags &= ~IFF_RXFH_CONFIGURED; 1408 - else if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) 1409 - dev->priv_flags |= IFF_RXFH_CONFIGURED; 1385 + if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, rss_context), 1386 + &rxfh.rss_context, sizeof(rxfh.rss_context))) 1387 + ret = -EFAULT; 1388 + 1389 + if (!rxfh.rss_context) { 1390 + /* indicate whether rxfh was set to default */ 1391 + if (rxfh.indir_size == 0) 1392 + dev->priv_flags &= ~IFF_RXFH_CONFIGURED; 1393 + else if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) 1394 + dev->priv_flags |= IFF_RXFH_CONFIGURED; 1395 + } 1410 1396 1411 1397 out: 1412 1398 kfree(rss_config);