aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/ethtool.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/ethtool.c')
-rw-r--r--net/core/ethtool.c329
1 files changed, 328 insertions, 1 deletions
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 }