aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorPeter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>2010-02-10 23:03:05 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-10 23:03:05 -0500
commit15682bc488d4af8c9bb998844a94281025e0a333 (patch)
tree2534589c00cbf695e6c2906f5c228a0006174904 /net/core
parent375c568844e49d292885c7485d4a255f71680e56 (diff)
ethtool: Introduce n-tuple filter programming support
This patchset enables the ethtool layer to program n-tuple filters to an underlying device. The idea is to allow capable hardware to have static rules applied that can assist steering flows into appropriate queues. Hardware that is known to support these types of filters today are ixgbe and niu. Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/dev.c5
-rw-r--r--net/core/ethtool.c329
2 files changed, 333 insertions, 1 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 94c1eeed25e5..ae75f25ac0a5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5419,6 +5419,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
5419 5419
5420 netdev_init_queues(dev); 5420 netdev_init_queues(dev);
5421 5421
5422 INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
5423 dev->ethtool_ntuple_list.count = 0;
5422 INIT_LIST_HEAD(&dev->napi_list); 5424 INIT_LIST_HEAD(&dev->napi_list);
5423 INIT_LIST_HEAD(&dev->unreg_list); 5425 INIT_LIST_HEAD(&dev->unreg_list);
5424 INIT_LIST_HEAD(&dev->link_watch_list); 5426 INIT_LIST_HEAD(&dev->link_watch_list);
@@ -5455,6 +5457,9 @@ void free_netdev(struct net_device *dev)
5455 /* Flush device addresses */ 5457 /* Flush device addresses */
5456 dev_addr_flush(dev); 5458 dev_addr_flush(dev);
5457 5459
5460 /* Clear ethtool n-tuple list */
5461 ethtool_ntuple_flush(dev);
5462
5458 list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) 5463 list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
5459 netif_napi_del(p); 5464 netif_napi_del(p);
5460 5465
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index d8aee584e8d1..6ec73d3983a3 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -120,7 +120,7 @@ int ethtool_op_set_ufo(struct net_device *dev, u32 data)
120 * NETIF_F_xxx values in include/linux/netdevice.h 120 * NETIF_F_xxx values in include/linux/netdevice.h
121 */ 121 */
122static const u32 flags_dup_features = 122static const u32 flags_dup_features =
123 ETH_FLAG_LRO; 123 (ETH_FLAG_LRO | ETH_FLAG_NTUPLE);
124 124
125u32 ethtool_op_get_flags(struct net_device *dev) 125u32 ethtool_op_get_flags(struct net_device *dev)
126{ 126{
@@ -139,9 +139,26 @@ int ethtool_op_set_flags(struct net_device *dev, u32 data)
139 else 139 else
140 dev->features &= ~NETIF_F_LRO; 140 dev->features &= ~NETIF_F_LRO;
141 141
142 if (data & ETH_FLAG_NTUPLE)
143 dev->features |= NETIF_F_NTUPLE;
144 else
145 dev->features &= ~NETIF_F_NTUPLE;
146
142 return 0; 147 return 0;
143} 148}
144 149
150void ethtool_ntuple_flush(struct net_device *dev)
151{
152 struct ethtool_rx_ntuple_flow_spec_container *fsc, *f;
153
154 list_for_each_entry_safe(fsc, f, &dev->ethtool_ntuple_list.list, list) {
155 list_del(&fsc->list);
156 kfree(fsc);
157 }
158 dev->ethtool_ntuple_list.count = 0;
159}
160EXPORT_SYMBOL(ethtool_ntuple_flush);
161
145/* Handlers for each ethtool command */ 162/* Handlers for each ethtool command */
146 163
147static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) 164static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
@@ -266,6 +283,307 @@ err_out:
266 return ret; 283 return ret;
267} 284}
268 285
286static int __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
287 struct ethtool_rx_ntuple_flow_spec *spec)
288{
289 struct ethtool_rx_ntuple_flow_spec_container *fsc;
290
291 /* don't add filters forever */
292 if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY)
293 return 0;
294
295 fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC);
296 if (!fsc)
297 return -ENOMEM;
298
299 /* Copy the whole filter over */
300 fsc->fs.flow_type = spec->flow_type;
301 memcpy(&fsc->fs.h_u, &spec->h_u, sizeof(spec->h_u));
302 memcpy(&fsc->fs.m_u, &spec->m_u, sizeof(spec->m_u));
303
304 fsc->fs.vlan_tag = spec->vlan_tag;
305 fsc->fs.vlan_tag_mask = spec->vlan_tag_mask;
306 fsc->fs.data = spec->data;
307 fsc->fs.data_mask = spec->data_mask;
308 fsc->fs.action = spec->action;
309
310 /* add to the list */
311 list_add_tail_rcu(&fsc->list, &list->list);
312 list->count++;
313
314 return 0;
315}
316
317static int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr)
318{
319 struct ethtool_rx_ntuple cmd;
320 const struct ethtool_ops *ops = dev->ethtool_ops;
321 int ret;
322
323 if (!ops->set_rx_ntuple)
324 return -EOPNOTSUPP;
325
326 if (!(dev->features & NETIF_F_NTUPLE))
327 return -EINVAL;
328
329 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
330 return -EFAULT;
331
332 ret = ops->set_rx_ntuple(dev, &cmd);
333
334 /*
335 * Cache filter in dev struct for GET operation only if
336 * the underlying driver doesn't have its own GET operation, and
337 * only if the filter was added successfully.
338 */
339 if (!ops->get_rx_ntuple && !ret)
340 if (__rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs))
341 return -ENOMEM;
342
343 return ret;
344}
345
346static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr)
347{
348 struct ethtool_gstrings gstrings;
349 const struct ethtool_ops *ops = dev->ethtool_ops;
350 struct ethtool_rx_ntuple_flow_spec_container *fsc;
351 u8 *data;
352 char *p;
353 int ret, i, num_strings = 0;
354
355 if (!ops->get_sset_count)
356 return -EOPNOTSUPP;
357
358 if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
359 return -EFAULT;
360
361 ret = ops->get_sset_count(dev, gstrings.string_set);
362 if (ret < 0)
363 return ret;
364
365 gstrings.len = ret;
366
367 data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
368 if (!data)
369 return -ENOMEM;
370
371 if (ops->get_rx_ntuple) {
372 /* driver-specific filter grab */
373 ret = ops->get_rx_ntuple(dev, gstrings.string_set, data);
374 goto copy;
375 }
376
377 /* default ethtool filter grab */
378 i = 0;
379 p = (char *)data;
380 list_for_each_entry(fsc, &dev->ethtool_ntuple_list.list, list) {
381 sprintf(p, "Filter %d:\n", i);
382 p += ETH_GSTRING_LEN;
383 num_strings++;
384
385 switch (fsc->fs.flow_type) {
386 case TCP_V4_FLOW:
387 sprintf(p, "\tFlow Type: TCP\n");
388 p += ETH_GSTRING_LEN;
389 num_strings++;
390 break;
391 case UDP_V4_FLOW:
392 sprintf(p, "\tFlow Type: UDP\n");
393 p += ETH_GSTRING_LEN;
394 num_strings++;
395 break;
396 case SCTP_V4_FLOW:
397 sprintf(p, "\tFlow Type: SCTP\n");
398 p += ETH_GSTRING_LEN;
399 num_strings++;
400 break;
401 case AH_ESP_V4_FLOW:
402 sprintf(p, "\tFlow Type: AH ESP\n");
403 p += ETH_GSTRING_LEN;
404 num_strings++;
405 break;
406 case ESP_V4_FLOW:
407 sprintf(p, "\tFlow Type: ESP\n");
408 p += ETH_GSTRING_LEN;
409 num_strings++;
410 break;
411 case IP_USER_FLOW:
412 sprintf(p, "\tFlow Type: Raw IP\n");
413 p += ETH_GSTRING_LEN;
414 num_strings++;
415 break;
416 case IPV4_FLOW:
417 sprintf(p, "\tFlow Type: IPv4\n");
418 p += ETH_GSTRING_LEN;
419 num_strings++;
420 break;
421 default:
422 sprintf(p, "\tFlow Type: Unknown\n");
423 p += ETH_GSTRING_LEN;
424 num_strings++;
425 goto unknown_filter;
426 };
427
428 /* now the rest of the filters */
429 switch (fsc->fs.flow_type) {
430 case TCP_V4_FLOW:
431 case UDP_V4_FLOW:
432 case SCTP_V4_FLOW:
433 sprintf(p, "\tSrc IP addr: 0x%x\n",
434 fsc->fs.h_u.tcp_ip4_spec.ip4src);
435 p += ETH_GSTRING_LEN;
436 num_strings++;
437 sprintf(p, "\tSrc IP mask: 0x%x\n",
438 fsc->fs.m_u.tcp_ip4_spec.ip4src);
439 p += ETH_GSTRING_LEN;
440 num_strings++;
441 sprintf(p, "\tDest IP addr: 0x%x\n",
442 fsc->fs.h_u.tcp_ip4_spec.ip4dst);
443 p += ETH_GSTRING_LEN;
444 num_strings++;
445 sprintf(p, "\tDest IP mask: 0x%x\n",
446 fsc->fs.m_u.tcp_ip4_spec.ip4dst);
447 p += ETH_GSTRING_LEN;
448 num_strings++;
449 sprintf(p, "\tSrc Port: %d, mask: 0x%x\n",
450 fsc->fs.h_u.tcp_ip4_spec.psrc,
451 fsc->fs.m_u.tcp_ip4_spec.psrc);
452 p += ETH_GSTRING_LEN;
453 num_strings++;
454 sprintf(p, "\tDest Port: %d, mask: 0x%x\n",
455 fsc->fs.h_u.tcp_ip4_spec.pdst,
456 fsc->fs.m_u.tcp_ip4_spec.pdst);
457 p += ETH_GSTRING_LEN;
458 num_strings++;
459 sprintf(p, "\tTOS: %d, mask: 0x%x\n",
460 fsc->fs.h_u.tcp_ip4_spec.tos,
461 fsc->fs.m_u.tcp_ip4_spec.tos);
462 p += ETH_GSTRING_LEN;
463 num_strings++;
464 break;
465 case AH_ESP_V4_FLOW:
466 case ESP_V4_FLOW:
467 sprintf(p, "\tSrc IP addr: 0x%x\n",
468 fsc->fs.h_u.ah_ip4_spec.ip4src);
469 p += ETH_GSTRING_LEN;
470 num_strings++;
471 sprintf(p, "\tSrc IP mask: 0x%x\n",
472 fsc->fs.m_u.ah_ip4_spec.ip4src);
473 p += ETH_GSTRING_LEN;
474 num_strings++;
475 sprintf(p, "\tDest IP addr: 0x%x\n",
476 fsc->fs.h_u.ah_ip4_spec.ip4dst);
477 p += ETH_GSTRING_LEN;
478 num_strings++;
479 sprintf(p, "\tDest IP mask: 0x%x\n",
480 fsc->fs.m_u.ah_ip4_spec.ip4dst);
481 p += ETH_GSTRING_LEN;
482 num_strings++;
483 sprintf(p, "\tSPI: %d, mask: 0x%x\n",
484 fsc->fs.h_u.ah_ip4_spec.spi,
485 fsc->fs.m_u.ah_ip4_spec.spi);
486 p += ETH_GSTRING_LEN;
487 num_strings++;
488 sprintf(p, "\tTOS: %d, mask: 0x%x\n",
489 fsc->fs.h_u.ah_ip4_spec.tos,
490 fsc->fs.m_u.ah_ip4_spec.tos);
491 p += ETH_GSTRING_LEN;
492 num_strings++;
493 break;
494 case IP_USER_FLOW:
495 sprintf(p, "\tSrc IP addr: 0x%x\n",
496 fsc->fs.h_u.raw_ip4_spec.ip4src);
497 p += ETH_GSTRING_LEN;
498 num_strings++;
499 sprintf(p, "\tSrc IP mask: 0x%x\n",
500 fsc->fs.m_u.raw_ip4_spec.ip4src);
501 p += ETH_GSTRING_LEN;
502 num_strings++;
503 sprintf(p, "\tDest IP addr: 0x%x\n",
504 fsc->fs.h_u.raw_ip4_spec.ip4dst);
505 p += ETH_GSTRING_LEN;
506 num_strings++;
507 sprintf(p, "\tDest IP mask: 0x%x\n",
508 fsc->fs.m_u.raw_ip4_spec.ip4dst);
509 p += ETH_GSTRING_LEN;
510 num_strings++;
511 break;
512 case IPV4_FLOW:
513 sprintf(p, "\tSrc IP addr: 0x%x\n",
514 fsc->fs.h_u.usr_ip4_spec.ip4src);
515 p += ETH_GSTRING_LEN;
516 num_strings++;
517 sprintf(p, "\tSrc IP mask: 0x%x\n",
518 fsc->fs.m_u.usr_ip4_spec.ip4src);
519 p += ETH_GSTRING_LEN;
520 num_strings++;
521 sprintf(p, "\tDest IP addr: 0x%x\n",
522 fsc->fs.h_u.usr_ip4_spec.ip4dst);
523 p += ETH_GSTRING_LEN;
524 num_strings++;
525 sprintf(p, "\tDest IP mask: 0x%x\n",
526 fsc->fs.m_u.usr_ip4_spec.ip4dst);
527 p += ETH_GSTRING_LEN;
528 num_strings++;
529 sprintf(p, "\tL4 bytes: 0x%x, mask: 0x%x\n",
530 fsc->fs.h_u.usr_ip4_spec.l4_4_bytes,
531 fsc->fs.m_u.usr_ip4_spec.l4_4_bytes);
532 p += ETH_GSTRING_LEN;
533 num_strings++;
534 sprintf(p, "\tTOS: %d, mask: 0x%x\n",
535 fsc->fs.h_u.usr_ip4_spec.tos,
536 fsc->fs.m_u.usr_ip4_spec.tos);
537 p += ETH_GSTRING_LEN;
538 num_strings++;
539 sprintf(p, "\tIP Version: %d, mask: 0x%x\n",
540 fsc->fs.h_u.usr_ip4_spec.ip_ver,
541 fsc->fs.m_u.usr_ip4_spec.ip_ver);
542 p += ETH_GSTRING_LEN;
543 num_strings++;
544 sprintf(p, "\tProtocol: %d, mask: 0x%x\n",
545 fsc->fs.h_u.usr_ip4_spec.proto,
546 fsc->fs.m_u.usr_ip4_spec.proto);
547 p += ETH_GSTRING_LEN;
548 num_strings++;
549 break;
550 };
551 sprintf(p, "\tVLAN: %d, mask: 0x%x\n",
552 fsc->fs.vlan_tag, fsc->fs.vlan_tag_mask);
553 p += ETH_GSTRING_LEN;
554 num_strings++;
555 sprintf(p, "\tUser-defined: 0x%Lx\n", fsc->fs.data);
556 p += ETH_GSTRING_LEN;
557 num_strings++;
558 sprintf(p, "\tUser-defined mask: 0x%Lx\n", fsc->fs.data_mask);
559 p += ETH_GSTRING_LEN;
560 num_strings++;
561 if (fsc->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP)
562 sprintf(p, "\tAction: Drop\n");
563 else
564 sprintf(p, "\tAction: Direct to queue %d\n",
565 fsc->fs.action);
566 p += ETH_GSTRING_LEN;
567 num_strings++;
568unknown_filter:
569 i++;
570 }
571copy:
572 /* indicate to userspace how many strings we actually have */
573 gstrings.len = num_strings;
574 ret = -EFAULT;
575 if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
576 goto out;
577 useraddr += sizeof(gstrings);
578 if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
579 goto out;
580 ret = 0;
581
582out:
583 kfree(data);
584 return ret;
585}
586
269static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) 587static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
270{ 588{
271 struct ethtool_regs regs; 589 struct ethtool_regs regs;
@@ -313,6 +631,9 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr)
313 if (copy_from_user(&reset, useraddr, sizeof(reset))) 631 if (copy_from_user(&reset, useraddr, sizeof(reset)))
314 return -EFAULT; 632 return -EFAULT;
315 633
634 /* Clear ethtool n-tuple list */
635 ethtool_ntuple_flush(dev);
636
316 ret = dev->ethtool_ops->reset(dev, &reset.data); 637 ret = dev->ethtool_ops->reset(dev, &reset.data);
317 if (ret) 638 if (ret)
318 return ret; 639 return ret;
@@ -1112,6 +1433,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1112 case ETHTOOL_RESET: 1433 case ETHTOOL_RESET:
1113 rc = ethtool_reset(dev, useraddr); 1434 rc = ethtool_reset(dev, useraddr);
1114 break; 1435 break;
1436 case ETHTOOL_SRXNTUPLE:
1437 rc = ethtool_set_rx_ntuple(dev, useraddr);
1438 break;
1439 case ETHTOOL_GRXNTUPLE:
1440 rc = ethtool_get_rx_ntuple(dev, useraddr);
1441 break;
1115 default: 1442 default:
1116 rc = -EOPNOTSUPP; 1443 rc = -EOPNOTSUPP;
1117 } 1444 }