diff options
-rw-r--r-- | include/linux/ethtool.h | 50 | ||||
-rw-r--r-- | include/linux/netdevice.h | 3 | ||||
-rw-r--r-- | net/core/dev.c | 5 | ||||
-rw-r--r-- | net/core/ethtool.c | 329 |
4 files changed, 386 insertions, 1 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index ef4a2d84d922..a3cac53a0766 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #define _LINUX_ETHTOOL_H | 14 | #define _LINUX_ETHTOOL_H |
15 | 15 | ||
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/rculist.h> | ||
17 | 18 | ||
18 | /* This should work for both 32 and 64 bit userland. */ | 19 | /* This should work for both 32 and 64 bit userland. */ |
19 | struct ethtool_cmd { | 20 | struct ethtool_cmd { |
@@ -242,6 +243,7 @@ enum ethtool_stringset { | |||
242 | ETH_SS_TEST = 0, | 243 | ETH_SS_TEST = 0, |
243 | ETH_SS_STATS, | 244 | ETH_SS_STATS, |
244 | ETH_SS_PRIV_FLAGS, | 245 | ETH_SS_PRIV_FLAGS, |
246 | ETH_SS_NTUPLE_FILTERS, | ||
245 | }; | 247 | }; |
246 | 248 | ||
247 | /* for passing string sets for data tagging */ | 249 | /* for passing string sets for data tagging */ |
@@ -290,6 +292,7 @@ struct ethtool_perm_addr { | |||
290 | */ | 292 | */ |
291 | enum ethtool_flags { | 293 | enum ethtool_flags { |
292 | ETH_FLAG_LRO = (1 << 15), /* LRO is enabled */ | 294 | ETH_FLAG_LRO = (1 << 15), /* LRO is enabled */ |
295 | ETH_FLAG_NTUPLE = (1 << 27), /* N-tuple filters enabled */ | ||
293 | }; | 296 | }; |
294 | 297 | ||
295 | /* The following structures are for supporting RX network flow | 298 | /* The following structures are for supporting RX network flow |
@@ -363,6 +366,35 @@ struct ethtool_rxnfc { | |||
363 | __u32 rule_locs[0]; | 366 | __u32 rule_locs[0]; |
364 | }; | 367 | }; |
365 | 368 | ||
369 | struct ethtool_rx_ntuple_flow_spec { | ||
370 | __u32 flow_type; | ||
371 | union { | ||
372 | struct ethtool_tcpip4_spec tcp_ip4_spec; | ||
373 | struct ethtool_tcpip4_spec udp_ip4_spec; | ||
374 | struct ethtool_tcpip4_spec sctp_ip4_spec; | ||
375 | struct ethtool_ah_espip4_spec ah_ip4_spec; | ||
376 | struct ethtool_ah_espip4_spec esp_ip4_spec; | ||
377 | struct ethtool_rawip4_spec raw_ip4_spec; | ||
378 | struct ethtool_ether_spec ether_spec; | ||
379 | struct ethtool_usrip4_spec usr_ip4_spec; | ||
380 | __u8 hdata[64]; | ||
381 | } h_u, m_u; /* entry, mask */ | ||
382 | |||
383 | __u16 vlan_tag; | ||
384 | __u16 vlan_tag_mask; | ||
385 | __u64 data; /* user-defined flow spec data */ | ||
386 | __u64 data_mask; /* user-defined flow spec mask */ | ||
387 | |||
388 | /* signed to distinguish between queue and actions (DROP) */ | ||
389 | __s32 action; | ||
390 | #define ETHTOOL_RXNTUPLE_ACTION_DROP -1 | ||
391 | }; | ||
392 | |||
393 | struct ethtool_rx_ntuple { | ||
394 | __u32 cmd; | ||
395 | struct ethtool_rx_ntuple_flow_spec fs; | ||
396 | }; | ||
397 | |||
366 | #define ETHTOOL_FLASH_MAX_FILENAME 128 | 398 | #define ETHTOOL_FLASH_MAX_FILENAME 128 |
367 | enum ethtool_flash_op_type { | 399 | enum ethtool_flash_op_type { |
368 | ETHTOOL_FLASH_ALL_REGIONS = 0, | 400 | ETHTOOL_FLASH_ALL_REGIONS = 0, |
@@ -377,6 +409,18 @@ struct ethtool_flash { | |||
377 | 409 | ||
378 | #ifdef __KERNEL__ | 410 | #ifdef __KERNEL__ |
379 | 411 | ||
412 | struct ethtool_rx_ntuple_flow_spec_container { | ||
413 | struct ethtool_rx_ntuple_flow_spec fs; | ||
414 | struct list_head list; | ||
415 | }; | ||
416 | |||
417 | struct ethtool_rx_ntuple_list { | ||
418 | #define ETHTOOL_MAX_NTUPLE_LIST_ENTRY 1024 | ||
419 | #define ETHTOOL_MAX_NTUPLE_STRING_PER_ENTRY 14 | ||
420 | struct list_head list; | ||
421 | unsigned int count; | ||
422 | }; | ||
423 | |||
380 | struct net_device; | 424 | struct net_device; |
381 | 425 | ||
382 | /* Some generic methods drivers may use in their ethtool_ops */ | 426 | /* Some generic methods drivers may use in their ethtool_ops */ |
@@ -394,6 +438,7 @@ u32 ethtool_op_get_ufo(struct net_device *dev); | |||
394 | int ethtool_op_set_ufo(struct net_device *dev, u32 data); | 438 | int ethtool_op_set_ufo(struct net_device *dev, u32 data); |
395 | u32 ethtool_op_get_flags(struct net_device *dev); | 439 | u32 ethtool_op_get_flags(struct net_device *dev); |
396 | int ethtool_op_set_flags(struct net_device *dev, u32 data); | 440 | int ethtool_op_set_flags(struct net_device *dev, u32 data); |
441 | void ethtool_ntuple_flush(struct net_device *dev); | ||
397 | 442 | ||
398 | /** | 443 | /** |
399 | * ðtool_ops - Alter and report network device settings | 444 | * ðtool_ops - Alter and report network device settings |
@@ -500,6 +545,8 @@ struct ethtool_ops { | |||
500 | int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); | 545 | int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); |
501 | int (*flash_device)(struct net_device *, struct ethtool_flash *); | 546 | int (*flash_device)(struct net_device *, struct ethtool_flash *); |
502 | int (*reset)(struct net_device *, u32 *); | 547 | int (*reset)(struct net_device *, u32 *); |
548 | int (*set_rx_ntuple)(struct net_device *, struct ethtool_rx_ntuple *); | ||
549 | int (*get_rx_ntuple)(struct net_device *, u32 stringset, void *); | ||
503 | }; | 550 | }; |
504 | #endif /* __KERNEL__ */ | 551 | #endif /* __KERNEL__ */ |
505 | 552 | ||
@@ -559,6 +606,9 @@ struct ethtool_ops { | |||
559 | #define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */ | 606 | #define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */ |
560 | #define ETHTOOL_RESET 0x00000034 /* Reset hardware */ | 607 | #define ETHTOOL_RESET 0x00000034 /* Reset hardware */ |
561 | 608 | ||
609 | #define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */ | ||
610 | #define ETHTOOL_GRXNTUPLE 0x00000036 /* Get n-tuple filters from device */ | ||
611 | |||
562 | /* compatibility with older code */ | 612 | /* compatibility with older code */ |
563 | #define SPARC_ETH_GSET ETHTOOL_GSET | 613 | #define SPARC_ETH_GSET ETHTOOL_GSET |
564 | #define SPARC_ETH_SSET ETHTOOL_SSET | 614 | #define SPARC_ETH_SSET ETHTOOL_SSET |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e535700a3b72..cdf53a8d9ff5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -746,6 +746,7 @@ struct net_device { | |||
746 | #define NETIF_F_FCOE_CRC (1 << 24) /* FCoE CRC32 */ | 746 | #define NETIF_F_FCOE_CRC (1 << 24) /* FCoE CRC32 */ |
747 | #define NETIF_F_SCTP_CSUM (1 << 25) /* SCTP checksum offload */ | 747 | #define NETIF_F_SCTP_CSUM (1 << 25) /* SCTP checksum offload */ |
748 | #define NETIF_F_FCOE_MTU (1 << 26) /* Supports max FCoE MTU, 2158 bytes*/ | 748 | #define NETIF_F_FCOE_MTU (1 << 26) /* Supports max FCoE MTU, 2158 bytes*/ |
749 | #define NETIF_F_NTUPLE (1 << 27) /* N-tuple filters supported */ | ||
749 | 750 | ||
750 | /* Segmentation offload features */ | 751 | /* Segmentation offload features */ |
751 | #define NETIF_F_GSO_SHIFT 16 | 752 | #define NETIF_F_GSO_SHIFT 16 |
@@ -954,6 +955,8 @@ struct net_device { | |||
954 | /* max exchange id for FCoE LRO by ddp */ | 955 | /* max exchange id for FCoE LRO by ddp */ |
955 | unsigned int fcoe_ddp_xid; | 956 | unsigned int fcoe_ddp_xid; |
956 | #endif | 957 | #endif |
958 | /* n-tuple filter list attached to this device */ | ||
959 | struct ethtool_rx_ntuple_list ethtool_ntuple_list; | ||
957 | }; | 960 | }; |
958 | #define to_net_dev(d) container_of(d, struct net_device, dev) | 961 | #define to_net_dev(d) container_of(d, struct net_device, dev) |
959 | 962 | ||
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 | */ |
122 | static const u32 flags_dup_features = | 122 | static const u32 flags_dup_features = |
123 | ETH_FLAG_LRO; | 123 | (ETH_FLAG_LRO | ETH_FLAG_NTUPLE); |
124 | 124 | ||
125 | u32 ethtool_op_get_flags(struct net_device *dev) | 125 | u32 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 | ||
150 | void 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 | } | ||
160 | EXPORT_SYMBOL(ethtool_ntuple_flush); | ||
161 | |||
145 | /* Handlers for each ethtool command */ | 162 | /* Handlers for each ethtool command */ |
146 | 163 | ||
147 | static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) | 164 | static 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 | ||
286 | static 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 | |||
317 | static 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 | |||
346 | static 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++; | ||
568 | unknown_filter: | ||
569 | i++; | ||
570 | } | ||
571 | copy: | ||
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 | |||
582 | out: | ||
583 | kfree(data); | ||
584 | return ret; | ||
585 | } | ||
586 | |||
269 | static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) | 587 | static 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 | } |