aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2010-06-30 01:05:23 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-30 17:09:37 -0400
commita5b6ee291e39e285e021cf251dbcf770c83cd74e (patch)
tree4fa96af8095cda9949fff3e79e2c5e8ef7328dbd
parentcbf2d604a1cd77944a795bb8dbe844eaa38b44c8 (diff)
ethtool: Add support for control of RX flow hash indirection
Many NICs use an indirection table to map an RX flow hash value to one of an arbitrary number of queues (not necessarily a power of 2). It can be useful to remove some queues from this indirection table so that they are only used for flows that are specifically filtered there. It may also be useful to weight the mapping to account for user processes with the same CPU-affinity as the RX interrupts. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/ethtool.h15
-rw-r--r--net/core/ethtool.c80
2 files changed, 95 insertions, 0 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 084ddb3c8032..c1be61f3938b 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -384,6 +384,15 @@ struct ethtool_rxnfc {
384 __u32 rule_locs[0]; 384 __u32 rule_locs[0];
385}; 385};
386 386
387struct ethtool_rxfh_indir {
388 __u32 cmd;
389 /* On entry, this is the array size of the user buffer. On
390 * return from ETHTOOL_GRXFHINDIR, this is the array size of
391 * the hardware indirection table. */
392 __u32 size;
393 __u32 ring_index[0]; /* ring/queue index for each hash value */
394};
395
387struct ethtool_rx_ntuple_flow_spec { 396struct ethtool_rx_ntuple_flow_spec {
388 __u32 flow_type; 397 __u32 flow_type;
389 union { 398 union {
@@ -576,6 +585,10 @@ struct ethtool_ops {
576 int (*set_rx_ntuple)(struct net_device *, 585 int (*set_rx_ntuple)(struct net_device *,
577 struct ethtool_rx_ntuple *); 586 struct ethtool_rx_ntuple *);
578 int (*get_rx_ntuple)(struct net_device *, u32 stringset, void *); 587 int (*get_rx_ntuple)(struct net_device *, u32 stringset, void *);
588 int (*get_rxfh_indir)(struct net_device *,
589 struct ethtool_rxfh_indir *);
590 int (*set_rxfh_indir)(struct net_device *,
591 const struct ethtool_rxfh_indir *);
579}; 592};
580#endif /* __KERNEL__ */ 593#endif /* __KERNEL__ */
581 594
@@ -637,6 +650,8 @@ struct ethtool_ops {
637#define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */ 650#define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */
638#define ETHTOOL_GRXNTUPLE 0x00000036 /* Get n-tuple filters from device */ 651#define ETHTOOL_GRXNTUPLE 0x00000036 /* Get n-tuple filters from device */
639#define ETHTOOL_GSSET_INFO 0x00000037 /* Get string set info */ 652#define ETHTOOL_GSSET_INFO 0x00000037 /* Get string set info */
653#define ETHTOOL_GRXFHINDIR 0x00000038 /* Get RX flow hash indir'n table */
654#define ETHTOOL_SRXFHINDIR 0x00000039 /* Set RX flow hash indir'n table */
640 655
641/* compatibility with older code */ 656/* compatibility with older code */
642#define SPARC_ETH_GSET ETHTOOL_GSET 657#define SPARC_ETH_GSET ETHTOOL_GSET
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 5d42fae520d9..072d1d3796cb 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -358,6 +358,80 @@ err_out:
358 return ret; 358 return ret;
359} 359}
360 360
361static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
362 void __user *useraddr)
363{
364 struct ethtool_rxfh_indir *indir;
365 u32 table_size;
366 size_t full_size;
367 int ret;
368
369 if (!dev->ethtool_ops->get_rxfh_indir)
370 return -EOPNOTSUPP;
371
372 if (copy_from_user(&table_size,
373 useraddr + offsetof(struct ethtool_rxfh_indir, size),
374 sizeof(table_size)))
375 return -EFAULT;
376
377 if (table_size >
378 (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index))
379 return -ENOMEM;
380 full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size;
381 indir = kmalloc(full_size, GFP_USER);
382 if (!indir)
383 return -ENOMEM;
384
385 indir->cmd = ETHTOOL_GRXFHINDIR;
386 indir->size = table_size;
387 ret = dev->ethtool_ops->get_rxfh_indir(dev, indir);
388 if (ret)
389 goto out;
390
391 if (copy_to_user(useraddr, indir, full_size))
392 ret = -EFAULT;
393
394out:
395 kfree(indir);
396 return ret;
397}
398
399static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
400 void __user *useraddr)
401{
402 struct ethtool_rxfh_indir *indir;
403 u32 table_size;
404 size_t full_size;
405 int ret;
406
407 if (!dev->ethtool_ops->set_rxfh_indir)
408 return -EOPNOTSUPP;
409
410 if (copy_from_user(&table_size,
411 useraddr + offsetof(struct ethtool_rxfh_indir, size),
412 sizeof(table_size)))
413 return -EFAULT;
414
415 if (table_size >
416 (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index))
417 return -ENOMEM;
418 full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size;
419 indir = kmalloc(full_size, GFP_USER);
420 if (!indir)
421 return -ENOMEM;
422
423 if (copy_from_user(indir, useraddr, full_size)) {
424 ret = -EFAULT;
425 goto out;
426 }
427
428 ret = dev->ethtool_ops->set_rxfh_indir(dev, indir);
429
430out:
431 kfree(indir);
432 return ret;
433}
434
361static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, 435static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
362 struct ethtool_rx_ntuple_flow_spec *spec, 436 struct ethtool_rx_ntuple_flow_spec *spec,
363 struct ethtool_rx_ntuple_flow_spec_container *fsc) 437 struct ethtool_rx_ntuple_flow_spec_container *fsc)
@@ -1526,6 +1600,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1526 case ETHTOOL_GSSET_INFO: 1600 case ETHTOOL_GSSET_INFO:
1527 rc = ethtool_get_sset_info(dev, useraddr); 1601 rc = ethtool_get_sset_info(dev, useraddr);
1528 break; 1602 break;
1603 case ETHTOOL_GRXFHINDIR:
1604 rc = ethtool_get_rxfh_indir(dev, useraddr);
1605 break;
1606 case ETHTOOL_SRXFHINDIR:
1607 rc = ethtool_set_rxfh_indir(dev, useraddr);
1608 break;
1529 default: 1609 default:
1530 rc = -EOPNOTSUPP; 1610 rc = -EOPNOTSUPP;
1531 } 1611 }