DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/2] User-space Ethtool
@ 2015-05-30  0:37 Liang-Min Larry Wang
  2015-05-30  0:37 ` [dpdk-dev] [PATCH 1/2] ethdev: add api to set default mac address Liang-Min Larry Wang
                   ` (15 more replies)
  0 siblings, 16 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-05-30  0:37 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.
ethtool: adding new ethtool api support

v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (2):
  ethdev: add api to set default mac address
  ethtool: add new library to provide ethtool-alike APIs

 MAINTAINERS                                |   4 +
 config/common_linuxapp                     |   5 +
 lib/Makefile                               |   1 +
 lib/librte_ether/rte_ethdev.c              |  18 ++
 lib/librte_ether/rte_ethdev.h              |  14 ++
 lib/librte_ether/rte_ether_version.map     |   1 +
 lib/librte_ethtool/Makefile                |  56 +++++++
 lib/librte_ethtool/rte_ethtool.c           | 155 +++++++++++++++++
 lib/librte_ethtool/rte_ethtool.h           | 257 +++++++++++++++++++++++++++++
 lib/librte_ethtool/rte_ethtool_version.map |  18 ++
 mk/rte.app.mk                              |   1 +
 11 files changed, 530 insertions(+)
 create mode 100644 lib/librte_ethtool/Makefile
 create mode 100644 lib/librte_ethtool/rte_ethtool.c
 create mode 100644 lib/librte_ethtool/rte_ethtool.h
 create mode 100644 lib/librte_ethtool/rte_ethtool_version.map

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH 1/2] ethdev: add api to set default mac address
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
@ 2015-05-30  0:37 ` Liang-Min Larry Wang
  2015-05-30  1:57   ` Andrew Harvey (agh)
  2015-05-30  0:37 ` [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs Liang-Min Larry Wang
                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-05-30  0:37 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add a new api: rte_eth_dev_default_mac_addr_set to
support changing default mac address of a NIC

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/rte_ethdev.c          | 18 ++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 14 ++++++++++++++
 lib/librte_ether/rte_ether_version.map |  1 +
 3 files changed, 33 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 024fe8b..85ce72e 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2752,6 +2752,24 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 16dbe00..5f07e0d 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -2982,6 +2982,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index a2d25a6..2dbbaa7 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,7 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
  2015-05-30  0:37 ` [dpdk-dev] [PATCH 1/2] ethdev: add api to set default mac address Liang-Min Larry Wang
@ 2015-05-30  0:37 ` Liang-Min Larry Wang
  2015-05-30 15:48   ` Stephen Hemminger
  2015-06-01 12:42   ` David Harton (dharton)
  2015-06-10 15:09 ` [dpdk-dev] [PATCH v4 0/4] User-space Ethtool Liang-Min Larry Wang
                   ` (13 subsequent siblings)
  15 siblings, 2 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-05-30  0:37 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

adding a new library based upon ethdev APIs to provide API's that bear
the same functionality as ethtool_ops (linux/ethtool.h) and net_device_ops
(linux/netdevice.h).

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 MAINTAINERS                                |   4 +
 config/common_linuxapp                     |   5 +
 lib/Makefile                               |   1 +
 lib/librte_ethtool/Makefile                |  56 +++++++
 lib/librte_ethtool/rte_ethtool.c           | 155 +++++++++++++++++
 lib/librte_ethtool/rte_ethtool.h           | 257 +++++++++++++++++++++++++++++
 lib/librte_ethtool/rte_ethtool_version.map |  18 ++
 mk/rte.app.mk                              |   1 +
 8 files changed, 497 insertions(+)
 create mode 100644 lib/librte_ethtool/Makefile
 create mode 100644 lib/librte_ethtool/rte_ethtool.c
 create mode 100644 lib/librte_ethtool/rte_ethtool.h
 create mode 100644 lib/librte_ethtool/rte_ethtool_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 9362c19..b8b481f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -186,6 +186,10 @@ M: Thomas Monjalon <thomas.monjalon@6wind.com>
 F: lib/librte_ether/
 F: scripts/test-null.sh
 
+Ethtool API
+M: Liang-Min Larry Wang <liang-min.wang@intel.com>
+F: lib/librte_ethtool/
+
 
 Drivers
 -------
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 0078dc9..f5759fd 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -129,6 +129,11 @@ CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y
 CONFIG_RTE_LIBRTE_KVARGS=y
 
 #
+# Compile user-space ethtool library
+#
+CONFIG_RTE_LIBRTE_ETHTOOL=y
+
+#
 # Compile generic ethernet library
 #
 CONFIG_RTE_LIBRTE_ETHER=y
diff --git a/lib/Makefile b/lib/Makefile
index 5f480f9..a6c7375 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -41,6 +41,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_TIMER) += librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_CFGFILE) += librte_cfgfile
 DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
+DIRS-$(CONFIG_RTE_LIBRTE_ETHTOOL) += librte_ethtool
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
diff --git a/lib/librte_ethtool/Makefile b/lib/librte_ethtool/Makefile
new file mode 100644
index 0000000..1d981f6
--- /dev/null
+++ b/lib/librte_ethtool/Makefile
@@ -0,0 +1,56 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_ethtool.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_ethtool_version.map
+
+LIBABIVER := 1
+
+SRCS-y += rte_ethtool.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_ethtool.h
+
+# this lib depends upon:
+DEPDIRS-y += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ethtool/rte_ethtool.c b/lib/librte_ethtool/rte_ethtool.c
new file mode 100644
index 0000000..2ccf06f
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.c
@@ -0,0 +1,155 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/lib/librte_ethtool/rte_ethtool.h b/lib/librte_ethtool/rte_ethtool.h
new file mode 100644
index 0000000..cb68d94
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.h
@@ -0,0 +1,257 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::ndo_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/lib/librte_ethtool/rte_ethtool_version.map b/lib/librte_ethtool/rte_ethtool_version.map
new file mode 100644
index 0000000..82fc0d3
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool_version.map
@@ -0,0 +1,18 @@
+DPDK_2.0 {
+	global:
+
+	rte_ethtool_net_open;
+	rte_ethtool_net_stop;
+	rte_ethtool_net_get_mac_addr;
+	rte_ethtool_net_get_mac_addr;
+	rte_ethtool_net_validate_addr;
+	rte_ethtool_net_set_config;
+	rte_ethtool_net_change_mtu;
+	rte_ethtool_net_get_stats64;
+	rte_ethtool_net_vlan_rx_add_vid;
+	rte_ethtool_net_vlan_rx_kill_vid;
+	rte_ethtool_get_drvinfo;
+	rte_ethtool_get_link;
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 1a2043a..86867a6 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -105,6 +105,7 @@ ifeq ($(CONFIG_RTE_BUILD_COMBINE_LIBS),n)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS)         += -lrte_kvargs
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
+_LDLIBS-$(CONFIG_RTE_LIBRTE_ETHTOOL)        += -lrte_ethtool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MALLOC)         += -lrte_malloc
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 1/2] ethdev: add api to set default mac address
  2015-05-30  0:37 ` [dpdk-dev] [PATCH 1/2] ethdev: add api to set default mac address Liang-Min Larry Wang
@ 2015-05-30  1:57   ` Andrew Harvey (agh)
  0 siblings, 0 replies; 174+ messages in thread
From: Andrew Harvey (agh) @ 2015-05-30  1:57 UTC (permalink / raw)
  To: Liang-Min Larry Wang, dev

On 5/29/15, 5:37 PM, "Liang-Min Larry Wang" <liang-min.wang@intel.com>
wrote:
>add a new api: rte_eth_dev_default_mac_addr_set to
>support changing default mac address of a NIC
>
>Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
>---
> lib/librte_ether/rte_ethdev.c          | 18 ++++++++++++++++++
> lib/librte_ether/rte_ethdev.h          | 14 ++++++++++++++
> lib/librte_ether/rte_ether_version.map |  1 +
> 3 files changed, 33 insertions(+)
>
>diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
>index 024fe8b..85ce72e 100644
>--- a/lib/librte_ether/rte_ethdev.c
>+++ b/lib/librte_ether/rte_ethdev.c
>@@ -2752,6 +2752,24 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id,
>struct ether_addr *addr)
> }
> 
> int
>+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr
>*addr)
>+{
>+	struct rte_eth_dev *dev;
>+
>+	if (!rte_eth_dev_is_valid_port(port_id)) {
>+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
>+		return -ENODEV;
>+	}
>+
>+	dev = &rte_eth_devices[port_id];
>+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
>+
>+	(*dev->dev_ops->mac_addr_set)(dev, addr);
>+
>+	return 0;
>+}
>+
>+int
> rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
> 				uint16_t rx_mode, uint8_t on)
> {
>diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
>index 16dbe00..5f07e0d 100644
>--- a/lib/librte_ether/rte_ethdev.h
>+++ b/lib/librte_ether/rte_ethdev.h
>@@ -2982,6 +2982,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct
>ether_addr *mac_addr,
> int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr
>*mac_addr);
> 
> /**
>+ * Set the default MAC address.
>+ *
>+ * @param port
>+ *   The port identifier of the Ethernet device.
>+ * @param mac_addr
>+ *   New default MAC address.
>+ * @return
>+ *   - (0) if successful, or *mac_addr* didn't exist.
>+ *   - (-ENOTSUP) if hardware doesn't support.
>+ *   - (-ENODEV) if *port* invalid.
>+ */
>+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr
>*mac_addr);
>+
>+/**
>  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet
>device.
>  *
>  * @param port
>diff --git a/lib/librte_ether/rte_ether_version.map
>b/lib/librte_ether/rte_ether_version.map
>index a2d25a6..2dbbaa7 100644
>--- a/lib/librte_ether/rte_ether_version.map
>+++ b/lib/librte_ether/rte_ether_version.map
>@@ -102,6 +102,7 @@ DPDK_2.0 {
> 	rte_eth_tx_queue_setup;
> 	rte_eth_xstats_get;
> 	rte_eth_xstats_reset;
>+	rte_eth_dev_default_mac_addr_set;
> 
> 	local: *;
> };
>-- 
>2.1.4

Acked-by: Andrew Harvey (agh) <agh@cisco.com>

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-30  0:37 ` [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs Liang-Min Larry Wang
@ 2015-05-30 15:48   ` Stephen Hemminger
  2015-05-30 16:16     ` Wang, Liang-min
  2015-06-01 12:42   ` David Harton (dharton)
  1 sibling, 1 reply; 174+ messages in thread
From: Stephen Hemminger @ 2015-05-30 15:48 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

On Fri, 29 May 2015 20:37:56 -0400
Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:

> adding a new library based upon ethdev APIs to provide API's that bear
> the same functionality as ethtool_ops (linux/ethtool.h) and net_device_ops
> (linux/netdevice.h).

The API's for ethtool like things are valuable, but please contain
it more.

I think you should contain this to only those things which are in
the original Linux ethtool. Adding yet another layer that calls DPDK
for open/close/start stop just adds more layers with out providing any
value.

The ones I would keep:
	get_driverinfo
	get_link

The ones I would add:
	cmd - for speed/duplex negotiation
	eeprom - for eeprom access
	eee - for energy awareness
	coalesce - for packet coalescing
	ringparam - to allow changing ring parameters
              (existing rx config model is limiting)
	pauseparam - existing flow control in DPDK is mess
	gstrings/stats - map to XSTATS
	test - for  offline tests
	dump - for register dump
	features - control offload features
	perm_addr - base mac address

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-30 15:48   ` Stephen Hemminger
@ 2015-05-30 16:16     ` Wang, Liang-min
  2015-05-30 19:26       ` Stephen Hemminger
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-05-30 16:16 UTC (permalink / raw)
  To: Stephen Hemminger, Richardson, Bruce, Ananyev, Konstantin; +Cc: dev


>On Fri, 29 May 2015 20:37:56 -0400
>Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
>
>> adding a new library based upon ethdev APIs to provide API's that bear 
>> the same functionality as ethtool_ops (linux/ethtool.h) and 
> >net_device_ops (linux/netdevice.h).

>The API's for ethtool like things are valuable, but please contain it more.
>
>I think you should contain this to only those things which are in the original Linux ethtool. Adding yet another layer that calls DPDK for open/close/start stop just adds more layers with out providing any value.
>
>The ones I would keep:
>	get_driverinfo
>	get_link
>
>The ones I would add:
>	cmd - for speed/duplex negotiation
>	eeprom - for eeprom access
>	eee - for energy awareness
>	coalesce - for packet coalescing
>	ringparam - to allow changing ring parameters
>              (existing rx config model is limiting)
>	pauseparam - existing flow control in DPDK is mess
>	gstrings/stats - map to XSTATS
>	test - for  offline tests
>	dump - for register dump
>	features - control offload features
>	perm_addr - base mac address

The design decision is to keep ethdev as THE interface for all the external API, so ethtool APIs are designed based upon ethdev API. At the meantime, the ethtool APIs are designed to enable users to migrate designs based upon kernel-space ethtool. The open/close/start are put in place to enable quick migration.

As for the suggestion, eeprom/ringparam/pauseparam/register-dump are on their way for latter release. For other ops, I will take the feedback for future planning.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-30 16:16     ` Wang, Liang-min
@ 2015-05-30 19:26       ` Stephen Hemminger
  2015-05-30 19:40         ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Stephen Hemminger @ 2015-05-30 19:26 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

On Sat, 30 May 2015 16:16:01 +0000
"Wang, Liang-min" <liang-min.wang@intel.com> wrote:

> The design decision is to keep ethdev as THE interface for all the external API, so ethtool APIs are designed based upon ethdev API. At the meantime, the ethtool APIs are designed to enable users to migrate designs based upon kernel-space ethtool. The open/close/start are put in place to enable quick migration.

But there is no open/close/start in ethtool in kernel.
Anyway ethtool is currently on the disfavored list from kernel developers.
What about netlink or something better?

Remember each new API creates more long term compatiablity and ABI issues.
So I am against introducing any new API that does the same thing as existing API's.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-30 19:26       ` Stephen Hemminger
@ 2015-05-30 19:40         ` Wang, Liang-min
  2015-05-31 16:48           ` Stephen Hemminger
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-05-30 19:40 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev


On Sat, 30 May 2015 16:16:01 +0000
"Wang, Liang-min" <liang-min.wang@intel.com> wrote:

> >The design decision is to keep ethdev as THE interface for all the external API, so ethtool APIs are designed based upon ethdev API. At the meantime, the ethtool APIs are designed to enable users to migrate designs based upon kernel-space ethtool. The open/close/start are put in place to enable quick migration.
>
>But there is no open/close/start in ethtool in kernel.
>Anyway ethtool is currently on the disfavored list from kernel developers.
>What about netlink or something better?
>
>Remember each new API creates more long term compatiablity and ABI issues.
>So I am against introducing any new API that does the same thing as existing API's.

Just to clarify APIs supported by this ethtool api: there are net_open and net_stop and no net_start. Both functions are put in place to support net_device_ops::ndo_open and net_device_ops::ndo_close as defined in linux/netdevice.h

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-30 19:40         ` Wang, Liang-min
@ 2015-05-31 16:48           ` Stephen Hemminger
  2015-05-31 17:30             ` Wang, Liang-min
  2015-05-31 18:31             ` Wang, Liang-min
  0 siblings, 2 replies; 174+ messages in thread
From: Stephen Hemminger @ 2015-05-31 16:48 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

On Sat, 30 May 2015 19:40:46 +0000
"Wang, Liang-min" <liang-min.wang@intel.com> wrote:

> 
> On Sat, 30 May 2015 16:16:01 +0000
> "Wang, Liang-min" <liang-min.wang@intel.com> wrote:
> 
> > >The design decision is to keep ethdev as THE interface for all the external API, so ethtool APIs are designed based upon ethdev API. At the meantime, the ethtool APIs are designed to enable users to migrate designs based upon kernel-space ethtool. The open/close/start are put in place to enable quick migration.
> >
> >But there is no open/close/start in ethtool in kernel.
> >Anyway ethtool is currently on the disfavored list from kernel developers.
> >What about netlink or something better?
> >
> >Remember each new API creates more long term compatiablity and ABI issues.
> >So I am against introducing any new API that does the same thing as existing API's.
> 
> Just to clarify APIs supported by this ethtool api: there are net_open and net_stop and no net_start. Both functions are put in place to support net_device_ops::ndo_open and net_device_ops::ndo_close as defined in linux/netdevice.h


I get the feeling there is some use case you are not telling the list about.
What kind of application would use this api only. Why or how would DPDK application
be involved in net_device_ops. If you are planning on putting DPDK in the kernel
there are lots of other issues including kernel ABI stability and licensing
that need to be dealt with.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-31 16:48           ` Stephen Hemminger
@ 2015-05-31 17:30             ` Wang, Liang-min
  2015-05-31 18:31             ` Wang, Liang-min
  1 sibling, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-05-31 17:30 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev


>On Sat, 30 May 2015 19:40:46 +0000
>"Wang, Liang-min" <liang-min.wang@intel.com> wrote:
>
>> 
> >On Sat, 30 May 2015 16:16:01 +0000
> >"Wang, Liang-min" <liang-min.wang@intel.com> wrote:
> >
> >> >The design decision is to keep ethdev as THE interface for all the external API, so ethtool APIs are designed based upon ethdev API. At the meantime, the ethtool APIs are designed to enable users to migrate designs based upon kernel-space ethtool. The open/close/start are put in place to enable quick migration.
> >>
> >>But there is no open/close/start in ethtool in kernel.
> >>Anyway ethtool is currently on the disfavored list from kernel developers.
> >>What about netlink or something better?
> >>
> >>Remember each new API creates more long term compatiablity and ABI issues.
> >>So I am against introducing any new API that does the same thing as existing API's.
> >
>> Just to clarify APIs supported by this ethtool api: there are net_open 
> >and net_stop and no net_start. Both functions are put in place to 
> >support net_device_ops::ndo_open and net_device_ops::ndo_close as 
> >defined in linux/netdevice.h
>
>
>I get the feeling there is some use case you are not telling the list about.
>What kind of application would use this api only. Why or how would DPDK application be involved in net_device_ops. If you are planning on putting DPDK in the kernel there are lots of other issues >including kernel ABI stability and licensing that need to be dealt with.

(I'm manually adding ">" through my email, outlook, to make my reply. I apology if I make any mistake on adding ">" in wrong place)
No, we don't plan to put DPDK into kernel space, and this patch has nothing to do with bifurcated driver that was announced for DPDK 2.0 then got scrubbed (or deferred). In contrary, the entire ethtool API (more support is coming) is designed to assist applications that were designed based upon kernel ethtool to migrate into user-space driver based DPDK libraries. Being said that, as you are aware the kernel version of ndo_open/ndo_close is more than just start and stop device. The initial implementation is to provide minimum functionality (strip off all the kernel related state management). In the future release (we need comments like yours), we will continue make improvement. So this new API can be another alternative for applications to run device management.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-31 16:48           ` Stephen Hemminger
  2015-05-31 17:30             ` Wang, Liang-min
@ 2015-05-31 18:31             ` Wang, Liang-min
  1 sibling, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-05-31 18:31 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev


>>On Sat, 30 May 2015 19:40:46 +0000
>>"Wang, Liang-min" <liang-min.wang@intel.com> wrote:
>>
>>> 
> >>On Sat, 30 May 2015 16:16:01 +0000
> >>"Wang, Liang-min" <liang-min.wang@intel.com> wrote:
> >>
> >> >>The design decision is to keep ethdev as THE interface for all the external API, so ethtool APIs are designed based upon ethdev API. At the meantime, the ethtool APIs are designed to enable users to migrate designs based upon kernel-space ethtool. The open/close/start are put in place to enable quick migration.
> >>>
> >>>But there is no open/close/start in ethtool in kernel.
> >>>Anyway ethtool is currently on the disfavored list from kernel developers.
> >>>What about netlink or something better?
> >>>
> >>>Remember each new API creates more long term compatiablity and ABI issues.
> >>>So I am against introducing any new API that does the same thing as existing API's.
> >>
>>> Just to clarify APIs supported by this ethtool api: there are 
>>> net_open
> >>and net_stop and no net_start. Both functions are put in place to 
> >>support net_device_ops::ndo_open and net_device_ops::ndo_close as 
> >>defined in linux/netdevice.h
>>
>>
>>I get the feeling there is some use case you are not telling the list about.
>>What kind of application would use this api only. Why or how would DPDK application be involved in net_device_ops. If you are planning on putting DPDK in the kernel there are lots of other issues >>including kernel ABI stability and licensing that need to be dealt with.
>
>(I'm manually adding ">" through my email, outlook, to make my reply. I apology if I make any mistake on adding ">" in wrong place) No, we don't plan to put DPDK into kernel space, and this patch has >nothing to do with bifurcated driver that was announced for DPDK 2.0 then got scrubbed (or deferred). In contrary, the entire ethtool API (more support is coming) is designed to assist applications that >were designed based upon kernel ethtool to migrate into user-space driver based DPDK libraries. Being said that, as you are aware the kernel version of ndo_open/ndo_close is more than just start and >stop device. The initial implementation is to provide minimum functionality (strip off all the kernel related state management). In the future release (we need comments like yours), we will continue >make improvement. So this new API can be another alternative for applications to run device management.

Just to clarify my last reply: when I said "... based upon kernel ethtool to migrate ...", I was referring to both ethtool and net_device_op.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-30  0:37 ` [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs Liang-Min Larry Wang
  2015-05-30 15:48   ` Stephen Hemminger
@ 2015-06-01 12:42   ` David Harton (dharton)
  1 sibling, 0 replies; 174+ messages in thread
From: David Harton (dharton) @ 2015-06-01 12:42 UTC (permalink / raw)
  To: Liang-Min Larry Wang, dev

Acked-by: David Harton (dharton) <dharton@cisco.com>

> -----Original Message-----
> From: Liang-Min Larry Wang [mailto:liang-min.wang@intel.com]
> Sent: Friday, May 29, 2015 8:38 PM
> To: dev@dpdk.org
> Cc: bruce.richardson@intel.com; konstantin.ananyev@intel.com; David Harton
> (dharton); Andrew Harvey (agh); Liang-Min Larry Wang
> Subject: [PATCH 2/2] ethtool: add new library to provide ethtool-alike
> APIs
> 
> adding a new library based upon ethdev APIs to provide API's that bear
> the same functionality as ethtool_ops (linux/ethtool.h) and net_device_ops
> (linux/netdevice.h).
> 
> Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> ---
>  MAINTAINERS                                |   4 +
>  config/common_linuxapp                     |   5 +
>  lib/Makefile                               |   1 +
>  lib/librte_ethtool/Makefile                |  56 +++++++
>  lib/librte_ethtool/rte_ethtool.c           | 155 +++++++++++++++++
>  lib/librte_ethtool/rte_ethtool.h           | 257
> +++++++++++++++++++++++++++++
>  lib/librte_ethtool/rte_ethtool_version.map |  18 ++
>  mk/rte.app.mk                              |   1 +
>  8 files changed, 497 insertions(+)
>  create mode 100644 lib/librte_ethtool/Makefile
>  create mode 100644 lib/librte_ethtool/rte_ethtool.c
>  create mode 100644 lib/librte_ethtool/rte_ethtool.h
>  create mode 100644 lib/librte_ethtool/rte_ethtool_version.map
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9362c19..b8b481f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -186,6 +186,10 @@ M: Thomas Monjalon <thomas.monjalon@6wind.com>
>  F: lib/librte_ether/
>  F: scripts/test-null.sh
> 
> +Ethtool API
> +M: Liang-Min Larry Wang <liang-min.wang@intel.com>
> +F: lib/librte_ethtool/
> +
> 
>  Drivers
>  -------
> diff --git a/config/common_linuxapp b/config/common_linuxapp
> index 0078dc9..f5759fd 100644
> --- a/config/common_linuxapp
> +++ b/config/common_linuxapp
> @@ -129,6 +129,11 @@ CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y
>  CONFIG_RTE_LIBRTE_KVARGS=y
> 
>  #
> +# Compile user-space ethtool library
> +#
> +CONFIG_RTE_LIBRTE_ETHTOOL=y
> +
> +#
>  # Compile generic ethernet library
>  #
>  CONFIG_RTE_LIBRTE_ETHER=y
> diff --git a/lib/Makefile b/lib/Makefile
> index 5f480f9..a6c7375 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -41,6 +41,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_TIMER) += librte_timer
>  DIRS-$(CONFIG_RTE_LIBRTE_CFGFILE) += librte_cfgfile
>  DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
>  DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
> +DIRS-$(CONFIG_RTE_LIBRTE_ETHTOOL) += librte_ethtool
>  DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
>  DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
>  DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
> diff --git a/lib/librte_ethtool/Makefile b/lib/librte_ethtool/Makefile
> new file mode 100644
> index 0000000..1d981f6
> --- /dev/null
> +++ b/lib/librte_ethtool/Makefile
> @@ -0,0 +1,56 @@
> +#   BSD LICENSE
> +#
> +#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
> +#   All rights reserved.
> +#
> +#   Redistribution and use in source and binary forms, with or without
> +#   modification, are permitted provided that the following conditions
> +#   are met:
> +#
> +#     * Redistributions of source code must retain the above copyright
> +#       notice, this list of conditions and the following disclaimer.
> +#     * Redistributions in binary form must reproduce the above copyright
> +#       notice, this list of conditions and the following disclaimer in
> +#       the documentation and/or other materials provided with the
> +#       distribution.
> +#     * Neither the name of Intel Corporation nor the names of its
> +#       contributors may be used to endorse or promote products derived
> +#       from this software without specific prior written permission.
> +#
> +#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> +#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> +#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> +#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> +#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> +#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> +#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> +#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> +#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> +#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> +#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +include $(RTE_SDK)/mk/rte.vars.mk
> +
> +#
> +# library name
> +#
> +LIB = librte_ethtool.a
> +
> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +
> +EXPORT_MAP := rte_ethtool_version.map
> +
> +LIBABIVER := 1
> +
> +SRCS-y += rte_ethtool.c
> +
> +#
> +# Export include files
> +#
> +SYMLINK-y-include += rte_ethtool.h
> +
> +# this lib depends upon:
> +DEPDIRS-y += lib/librte_ether
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/lib/librte_ethtool/rte_ethtool.c
> b/lib/librte_ethtool/rte_ethtool.c
> new file mode 100644
> index 0000000..2ccf06f
> --- /dev/null
> +++ b/lib/librte_ethtool/rte_ethtool.c
> @@ -0,0 +1,155 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
> + *   All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above
> copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of Intel Corporation nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
> USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdint.h>
> +#include <rte_version.h>
> +#include <rte_ethdev.h>
> +#include "rte_ethtool.h"
> +
> +int
> +rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
> +{
> +	struct rte_eth_dev_info dev_info;
> +
> +	memset(&dev_info, 0, sizeof(dev_info));
> +	rte_eth_dev_info_get(port_id, &dev_info);
> +
> +	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
> +		dev_info.driver_name);
> +	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
> +		rte_version());
> +	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
> +		"%04x:%02x:%02x.%x",
> +		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
> +		dev_info.pci_dev->addr.devid, dev_info.pci_dev-
> >addr.function);
> +
> +	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
> +	drvinfo->testinfo_len = 0;
> +
> +	return 0;
> +}
> +
> +int
> +rte_ethtool_get_link(uint8_t port_id)
> +{
> +	struct rte_eth_link link;
> +
> +	rte_eth_link_get(port_id, &link);
> +	return link.link_status;
> +}
> +
> +int
> +rte_ethtool_net_open(uint8_t port_id)
> +{
> +	rte_eth_dev_stop(port_id);
> +
> +	return rte_eth_dev_start(port_id);
> +}
> +
> +int
> +rte_ethtool_net_stop(uint8_t port_id)
> +{
> +	rte_eth_dev_stop(port_id);
> +
> +	return 0;
> +}
> +
> +int
> +rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
> +{
> +	rte_eth_macaddr_get(port_id, addr);
> +
> +	return 0;
> +}
> +
> +int
> +rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
> +{
> +	return rte_eth_dev_default_mac_addr_set(port_id, addr);
> +}
> +
> +int
> +rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
> +	struct ether_addr *addr)
> +{
> +	return is_valid_assigned_ether_addr(addr);
> +}
> +
> +int
> +rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
> +{
> +	struct rte_eth_link link;
> +
> +	memset(&link, 0, sizeof(link));
> +	rte_eth_link_get(port_id, &link);
> +	if (link.link_status == 1)
> +		return -EINVAL;
> +	return 0;
> +}
> +
> +int
> +rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
> +{
> +	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
> +}
> +
> +int
> +rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
> +{
> +	return rte_eth_stats_get(port_id, stats);
> +}
> +
> +int
> +rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
> +{
> +	return rte_eth_dev_vlan_filter(port_id, vid, 1);
> +}
> +
> +int
> +rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
> +{
> +	return rte_eth_dev_vlan_filter(port_id, vid, 0);
> +}
> +
> +int
> +rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
> +{
> +	/*
> +	 * The set_rx_mode op is part of pmd driver start operation, and
> +	 * the ethdev api maintains software configuration parameters and
> under-
> +	 * line hardware states consistent, so no operation is needed for
> +	 * rte_ethtool_net_set_rx_mode().
> +	 */
> +	return 0;
> +}
> diff --git a/lib/librte_ethtool/rte_ethtool.h
> b/lib/librte_ethtool/rte_ethtool.h
> new file mode 100644
> index 0000000..cb68d94
> --- /dev/null
> +++ b/lib/librte_ethtool/rte_ethtool.h
> @@ -0,0 +1,257 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
> + *   All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above
> copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of Intel Corporation nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
> USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#ifndef _RTE_ETHTOOL_H_
> +#define _RTE_ETHTOOL_H_
> +
> +/*
> + * This new interface is designed to provide a user-space shim layer for
> + * Ethtool and Netdevice op API.
> + *
> + * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
> + * rte_ethtool_get_link:            ethtool_ops::get_link
> + *
> + * rte_ethtool_net_open:            net_device_ops::ndo_open
> + * rte_ethtool_net_stop:            net_device_ops::ndo_stop
> + * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
> + * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
> + * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
> + * rte_ethtool_net_change_mtu:      net_device_ops::ndo_net_change_mtu
> + * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
> + * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
> + * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
> + * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
> + *
> + */
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <stdint.h>
> +#include <rte_ethdev.h>
> +#include <linux/ethtool.h>
> +
> +/**
> + * Retrieve the Ethernet device driver information according to
> attributes described by
> + * ethtool data structure, ethtool_drvinfo
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param drvinfo
> + *   A pointer to get driver information
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo
> *drvinfo);
> +
> +/**
> + * Retrieve the Ethernet device link status
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @return
> + *   - (1) if link up.
> + *   - (0) if link down.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_get_link(uint8_t port_id);
> +
> +/**
> + * Start the Ethernet device.
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_net_open(uint8_t port_id);
> +
> +/**
> + * Stop the Ethernet device.
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_net_stop(uint8_t port_id);
> +
> +/**
> + * Get the Ethernet device MAC address.
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param addr
> + *	 MAC address of the Ethernet device.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr
> *addr);
> +
> +/**
> + * Setting the Ethernet device MAC address.
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param addr
> + *	 The new MAC addr.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr
> *addr);
> +
> +/**
> + * Validate if the provided MAC address is valid unicast address
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param addr
> + *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr
> *addr);
> +
> +/**
> + * Setting the Ethernet device configuration.
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param config
> + *	 A opintr to a configuration parameter.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_net_set_config(uint8_t port_id, void *config);
> +
> +/**
> + * Setting the Ethernet device maximum Tx unit.
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param mtu
> + *	 New MTU
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
> +
> +/**
> + * Retrieve the Ethernet device traffic statistics
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param stats
> + *	 A pointer to struct rte_eth_stats for statistics parameters
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats
> *stats);
> +
> +/**
> + * Update the Ethernet device VLAN filter with new vid
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param vid
> + *	 A new VLAN id
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
> +
> +/**
> + * Remove VLAN id from Ethernet device.
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param vid
> + *	 A new VLAN id
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
> +
> +/**
> + * Setting the Ethernet device rx mode.
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_ethtool_net_set_rx_mode(uint8_t port_id);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* _RTE_ETHTOOL_H_ */
> diff --git a/lib/librte_ethtool/rte_ethtool_version.map
> b/lib/librte_ethtool/rte_ethtool_version.map
> new file mode 100644
> index 0000000..82fc0d3
> --- /dev/null
> +++ b/lib/librte_ethtool/rte_ethtool_version.map
> @@ -0,0 +1,18 @@
> +DPDK_2.0 {
> +	global:
> +
> +	rte_ethtool_net_open;
> +	rte_ethtool_net_stop;
> +	rte_ethtool_net_get_mac_addr;
> +	rte_ethtool_net_get_mac_addr;
> +	rte_ethtool_net_validate_addr;
> +	rte_ethtool_net_set_config;
> +	rte_ethtool_net_change_mtu;
> +	rte_ethtool_net_get_stats64;
> +	rte_ethtool_net_vlan_rx_add_vid;
> +	rte_ethtool_net_vlan_rx_kill_vid;
> +	rte_ethtool_get_drvinfo;
> +	rte_ethtool_get_link;
> +
> +	local: *;
> +};
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index 1a2043a..86867a6 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -105,6 +105,7 @@ ifeq ($(CONFIG_RTE_BUILD_COMBINE_LIBS),n)
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS)         += -lrte_kvargs
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_ETHTOOL)        += -lrte_ethtool
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_MALLOC)         += -lrte_malloc
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
> --
> 2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v4 0/4] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
  2015-05-30  0:37 ` [dpdk-dev] [PATCH 1/2] ethdev: add api to set default mac address Liang-Min Larry Wang
  2015-05-30  0:37 ` [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs Liang-Min Larry Wang
@ 2015-06-10 15:09 ` Liang-Min Larry Wang
  2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (3 more replies)
  2015-06-11 21:43 ` [dpdk-dev] [PATCH v5 0/4] User-space Ethtool Liang-Min Larry Wang
                   ` (12 subsequent siblings)
  15 siblings, 4 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-10 15:09 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:s
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (4):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  190 ++++
 drivers/net/e1000/igb_regs.h                     |  212 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  207 +++++
 drivers/net/ixgbe/ixgbe_regs.h                   |  357 ++++++++
 drivers/net/ixgbe/ixgbe_rxtx.c                   |   16 +
 drivers/net/ixgbe/ixgbe_rxtx.h                   |    1 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1048 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  821 +++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  153 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  335 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  412 +++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  417 +++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   80 ++
 lib/librte_ether/rte_ethdev.c                    |  159 ++++
 lib/librte_ether/rte_ethdev.h                    |  158 ++++
 lib/librte_ether/rte_ether_version.map           |    8 +
 21 files changed, 4798 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-10 15:09 ` [dpdk-dev] [PATCH v4 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-06-10 15:09   ` Liang-Min Larry Wang
  2015-06-10 15:21     ` David Harton (dharton)
  2015-06-11 12:26     ` Ananyev, Konstantin
  2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  3 siblings, 2 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-10 15:09 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add new apis:
- rte_eth_dev_default_mac_addr_set
- rte_eth_dev_reg_leng
- rte_eth_dev_reg_info
- rte_eth_dev_eeprom_leng
- rte_eth_dev_get_eeprom
- rte_eth_dev_set_eeprom
- rte_eth_dev_get_ringparam
- rte_eth_dev_set_ringparam

to enable reading device parameters (mac-addr, register,
eeprom, ring) based upon ethtool alike
data parameter specification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  80 +++++++++++++++++
 lib/librte_ether/rte_ethdev.c          | 159 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 158 ++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   8 ++
 5 files changed, 406 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..002c4b5
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,80 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+/*
+ * Placeholder for accessing device ring parameters
+ */
+struct rte_dev_ring_info {
+	uint32_t rx_pending; /**< Number of outstanding Rx ring */
+	uint32_t tx_pending; /**< Number of outstanding Tx ring */
+	uint32_t rx_max_pending; /**< Maximum number of outstanding Rx ring */
+	uint32_t tx_max_pending; /**< Maximum number of outstanding Tx ring */
+};
+
+/*
+ * A data structure captures information as defined in struct ifla_vf_info
+ * for user-space api
+ */
+struct rte_dev_vf_info {
+	uint32_t vf;
+	uint8_t mac[ETHER_ADDR_LEN];
+	uint32_t vlan;
+	uint32_t tx_rate;
+	uint32_t spoofchk;
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 5a94654..186e85c 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2751,6 +2751,32 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+	const int index = 0;
+	const uint32_t pool = 0;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_remove, -ENOTSUP);
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -ENOTSUP);
+
+	/* Update NIC default MAC address*/
+	(*dev->dev_ops->mac_addr_remove)(dev, index);
+	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3627,3 +3653,136 @@ rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 	/* Callback wasn't found. */
 	return -EINVAL;
 }
+
+int
+rte_eth_dev_reg_leng(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_leng(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -ENOTSUP);
+	return (*dev->dev_ops->get_ringparam)(dev, info);
+}
+
+int
+rte_eth_dev_set_ringparam(uint8_t port_id, struct rte_dev_ring_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_ringparam, -ENOTSUP);
+	return (*dev->dev_ops->set_ringparam)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 16dbe00..8f99f0d 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1228,6 +1229,31 @@ typedef int (*eth_udp_tunnel_del_t)(struct rte_eth_dev *dev,
 				    struct rte_eth_udp_tunnel *tunnel_udp);
 /**< @internal Delete tunneling UDP info */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
+typedef int (*eth_get_ringparam_t)(struct rte_eth_dev *dev,
+				struct rte_dev_ring_info *info);
+/**< @internal Retrieve device ring descriptor  */
+
+typedef int (*eth_set_ringparam_t)(struct rte_eth_dev *dev,
+				struct rte_dev_ring_info *info);
+/**< @internal Set device ring descriptor  */
 
 #ifdef RTE_NIC_BYPASS
 
@@ -1368,6 +1394,21 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
+	eth_get_ringparam_t get_ringparam;
+	/**< Get descriptor ring parameters */
+	eth_set_ringparam_t set_ringparam;
+	/**< Set descriptor ring parameters */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -2982,6 +3023,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3611,6 +3666,109 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_leng(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_leng(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Retrieve device descriptor ring information
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes device ring descriptor usage information.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info *info);
+
+/**
+ * Set device ring descriptor parameters
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes descriptor ring parameters to be set.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_ringparam(uint8_t port_id, struct rte_dev_ring_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index a2d25a6..1b1e092 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,14 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_leng;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_leng;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
+	rte_eth_dev_get_ringparam;
+	rte_eth_dev_set_ringparam;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v4 2/4] ixgbe: add ops to support ethtool ops
  2015-06-10 15:09 ` [dpdk-dev] [PATCH v4 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-10 15:09   ` Liang-Min Larry Wang
  2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 3/4] igb: " Liang-Min Larry Wang
  2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-10 15:09 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_ringparam
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 207 +++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_regs.h   | 357 +++++++++++++++++++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.c   |  16 ++
 drivers/net/ixgbe/ixgbe_rxtx.h   |   1 +
 4 files changed, 581 insertions(+)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 0d9f9b2..f3b80a8 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -179,6 +183,7 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -223,6 +228,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+		struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -257,6 +264,17 @@ static int ixgbe_dev_filter_ctrl(struct rte_eth_dev *dev,
 		     void *arg);
 static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 
+/* Ethtool op support */
+static int ixgbe_get_ringparam(struct rte_eth_dev *dev, struct rte_dev_ring_info *param);
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
+
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
  */
@@ -355,6 +373,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -381,6 +400,12 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.rss_hash_update      = ixgbe_dev_rss_hash_update,
 	.rss_hash_conf_get    = ixgbe_dev_rss_hash_conf_get,
 	.filter_ctrl          = ixgbe_dev_filter_ctrl,
+	.get_ringparam        = ixgbe_get_ringparam,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -406,6 +431,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.tx_queue_release     = ixgbe_dev_tx_queue_release,
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2883,6 +2911,16 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3713,6 +3751,16 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4439,6 +4487,165 @@ ixgbe_dev_filter_ctrl(struct rte_eth_dev *dev,
 	return ret;
 }
 
+static int
+ixgbe_get_ringparam(struct rte_eth_dev *dev,
+	struct rte_dev_ring_info *ring_param)
+{
+	/* Pending rx/tx descriptors in queue #0 */
+	struct ixgbe_tx_queue *txq = dev->data->tx_queues[0];
+	struct ixgbe_rx_queue *rxq = dev->data->rx_queues[0];
+
+	ring_param->rx_pending = rxq->nb_rx_desc - ixgbe_dev_rx_queue_count(dev, 0);
+	ring_param->tx_pending = txq->nb_tx_desc - ixgbe_dev_tx_queue_count(dev, 0);
+	/* The ixgbe descriptor ring is multiple of 8 descriptor, i.e. module by 8*16 bytes */
+	ring_param->rx_max_pending = IXGBE_MAX_RING_DESC;
+	ring_param->tx_max_pending = IXGBE_MAX_RING_DESC;
+
+	return 0;
+}
+
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+	reg_info **reg_set =
+		(hw->mac.type == ixgbe_mac_82598EB)?ixgbe_regs_mac_82598EB:ixgbe_regs_others;
+
+	reg_group = reg_set[g_ind++];
+	while(reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = reg_set[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = ixgbevf_regs[g_ind++];
+	while(reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = ixgbevf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+	reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB)?
+					ixgbe_regs_mac_82598EB:ixgbe_regs_others;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = reg_set[g_ind++];
+		while(reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = reg_set[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = ixgbevf_regs[g_ind++];
+		while(reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = ixgbevf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size*2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+		((first+leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+		((first+leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..7025ed8
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,357 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+typedef struct _reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_nvm [] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_interrupt [] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_interrupt [] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_rx [] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_tx [] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_tx [] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_wakeup [] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_dcb [] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_mac [] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_diagnostic [] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static reg_info* ixgbe_regs_others[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+                                ixgbe_regs_fctl_others, ixgbe_regs_rxdma, ixgbe_regs_rx,
+                                ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
+                                ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
+
+static reg_info* ixgbe_regs_mac_82598EB[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+                                ixgbe_regs_fctl_mac_82598EB, ixgbe_regs_rxdma, ixgbe_regs_rx,
+                                ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
+                                ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
+
+/* VF registers */
+static reg_info* ixgbevf_regs[] = { ixgbevf_regs_general, ixgbevf_regs_interrupt,
+                                ixgbevf_regs_rxdma, ixgbevf_regs_tx, NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for(i = 0; i < reg->count; i++) {
+		reg_buf[i] = IXGBE_READ_REG(hw, reg->base_addr + i*reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += ixgbe_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif // _IXGBE_REGS_H_
diff --git a/drivers/net/ixgbe/ixgbe_rxtx.c b/drivers/net/ixgbe/ixgbe_rxtx.c
index 4f9ab22..762d303 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx.c
+++ b/drivers/net/ixgbe/ixgbe_rxtx.c
@@ -2448,6 +2448,22 @@ ixgbe_dev_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)
 	return desc;
 }
 
+uint32_t
+ixgbe_dev_tx_queue_count(struct rte_eth_dev *dev, uint16_t tx_queue_id)
+{
+	struct ixgbe_tx_queue *txq;
+
+	if (tx_queue_id >= dev->data->nb_tx_queues) {
+		PMD_TX_LOG(ERR, "Invalid TX queue id=%d", tx_queue_id);
+		return 0;
+	}
+
+	txq = dev->data->tx_queues[tx_queue_id];
+	if (txq->tx_ring[txq->tx_next_dd].wb.status & IXGBE_ADVTXD_STAT_DD)
+		return (txq->nb_tx_free + txq->tx_rs_thresh);
+	return txq->nb_tx_free;
+}
+
 int
 ixgbe_dev_rx_descriptor_done(void *rx_queue, uint16_t offset)
 {
diff --git a/drivers/net/ixgbe/ixgbe_rxtx.h b/drivers/net/ixgbe/ixgbe_rxtx.h
index af36438..3b3163c 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx.h
+++ b/drivers/net/ixgbe/ixgbe_rxtx.h
@@ -282,6 +282,7 @@ uint16_t ixgbe_recv_scattered_pkts_vec(void *rx_queue,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 int ixgbe_rx_vec_dev_conf_condition_check(struct rte_eth_dev *dev);
 int ixgbe_rxq_vec_setup(struct ixgbe_rx_queue *rxq);
+uint32_t ixgbe_dev_tx_queue_count(struct rte_eth_dev *dev, uint16_t tx_queue_id);
 
 #ifdef RTE_IXGBE_INC_VECTOR
 
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v4 3/4] igb: add ops to support ethtool ops
  2015-06-10 15:09 ` [dpdk-dev] [PATCH v4 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-06-10 15:09   ` Liang-Min Larry Wang
  2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-10 15:09 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 190 ++++++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 212 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 402 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index e4b370d..a350009 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -129,6 +130,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -142,6 +145,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -193,6 +202,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -264,11 +281,17 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
 	.rss_hash_conf_get    = eth_igb_rss_hash_conf_get,
 	.filter_ctrl          = eth_igb_filter_ctrl,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -289,6 +312,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.rx_queue_release     = eth_igb_rx_queue_release,
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2107,6 +2133,16 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+	                     struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2341,6 +2377,18 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	hw->mac.ops.rar_set(hw, (void *)addr, 0); /* index is not used by rar_set() */
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3642,6 +3690,148 @@ eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 	return ret;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = igb_regs[g_ind++];
+	while(reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igb_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = igbvf_regs[g_ind++];
+	while(reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igbvf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igb_regs[g_ind++];
+		while(reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = igb_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igbvf_regs[g_ind++];
+		while(reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = igbvf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size*2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) || ((first+leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) || ((first+leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..3a1230a
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,212 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+typedef struct _reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_nvm [] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_interrupt [] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_rx [] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_tx [] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_wakeup [] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_mac [] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info* igb_regs[] = { igb_regs_general, igb_regs_nvm,
+                                igb_regs_interrupt, igb_regs_fctl,
+                                igb_regs_rxdma, igb_regs_rx,
+                                igb_regs_tx, igb_regs_wakeup, igb_regs_mac,
+                                NULL};
+
+static reg_info* igbvf_regs[] = { igb_regs_general, igb_regs_interrupt,
+                                  igb_regs_rxdma, igb_regs_tx, NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for(i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw, reg->base_addr + i*reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += igb_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif // _IGB_REGS_H_
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v4 4/4] examples: new example: l2fwd-ethtool
  2015-06-10 15:09 ` [dpdk-dev] [PATCH v4 0/4] User-space Ethtool Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 3/4] igb: " Liang-Min Larry Wang
@ 2015-06-10 15:09   ` Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-10 15:09 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1048 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  821 +++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  153 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  335 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  412 +++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  417 +++++++++
 10 files changed, 3409 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..a753c33
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..3d31cb1
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -lrte_ethtool
+LDFLAGS += -L$(SRCDIR)/../lib/build
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..2fd9607
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1048 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id)            ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id)     ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask = 0;
+
+/* virtio setup enable */
+static int virtio_setup = 0;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+    return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done (void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ------------------------------"
+			   "\nPackets sent: %24"PRIu64
+			   "\nPackets received: %20"PRIu64
+			   "\nPackets dropped: %21"PRIu64,
+			   portid,
+			   port_statistics[portid].tx,
+			   port_statistics[portid].rx,
+			   port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ==============================="
+		   "\nTotal packets sent: %18"PRIu64
+		   "\nTotal packets received: %14"PRIu64
+		   "\nTotal packets dropped: %15"PRIu64,
+		   total_packets_tx,
+		   total_packets_rx,
+		   total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid =0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+    if(virtio_setup) {
+        while (is_ipc_done() == 0) usleep(50);
+    }
+	while (1) {
+
+		cur_tsc = rte_rdtsc();
+
+		/*
+		 * TX burst queue drain
+		 */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >= (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id == rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+	       "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+	       "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+           "  -V : setting rx/tx mode to enable virtio\n"
+		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
+	       prgname);
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+            virtio_setup = l2fwd_parse_virtio_setup(optarg);
+            if (virtio_setup) {
+			    port_conf.rxmode.hw_vlan_strip = 0;
+			    port_conf.rxmode.hw_vlan_extend = 0;
+            }
+            break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status)
+					printf("Port %d Link Up - speed %u "
+						"Mbps - %s\n", (uint8_t)portid,
+						(unsigned)link.link_speed,
+				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+					("full-duplex") : ("half-duplex\n"));
+				else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+inline static char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+    static char addr_string[MAC_STR_SIZE];
+
+    snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+        mac_addr[0], mac_addr[1], mac_addr[2],
+        mac_addr[3], mac_addr[4], mac_addr[5]);
+    return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+    uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for(port_id = 0; port_id < num_of_ports; port_id++){
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of rte_eth_promiscuous_enable */
+		/* to test rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data = (struct rte_eth_dev_data*)dev->data;
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is %s", port_id, mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			if (rte_ethtool_net_set_mac_addr(port_id, (void *)new_mac_addr) == 0) {
+				printf(", and it's being re-assigned to %s\n", mac_addr_str(new_mac_addr));
+				new_mac_addr[MAC_ADDR_SIZE-1]++;
+			} else {
+				printf("\n");
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1, &param2_size, param2);
+		if (req_type != (req_t)ipc_begin) {
+			proc_invalid(req_id);
+		} else {
+			break;
+		}
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1, &param2_size, param2);
+		port_id = param1[0];
+
+		switch((req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id, first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0) {
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			}
+			if (reg_count) {
+				status = proc_ethtool_get_regs(port_id, req_id, first_param, reply1);
+			}
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0) {
+				eeprom_size = rte_ethtool_get_eeprom_len(port_id);
+			}
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id, first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id, first_param, param2);
+			break;
+
+		case get_ringparam:
+			{
+				struct ethtool_ringparam *ring_param = (void *)reply1;
+				status = proc_ethtool_get_ringparam(port_id, req_id, ring_param);
+
+				if (status != 0) {
+					printf("get_ringparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case set_ringparam:
+			{
+				struct ethtool_ringparam *ring_param = (void *)reply1;
+				status = proc_ethtool_set_ringparam(port_id, req_id, ring_param);
+
+				if (status != 0) {
+					printf("set_ringparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param = (void *)reply1;
+				status = proc_ethtool_get_pauseparam(port_id, req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param = (void *)reply1;
+				status = proc_ethtool_set_pauseparam(port_id, req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id, req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id, req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id, req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id, req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id, req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id, req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id, req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id, req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type: %d\n",req_type);
+			break;
+		}
+		if ( status < 0)
+			printf("Service request with type (=%d) failed or not supported!!!\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+    init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		}
+		else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+		       lcore_queue_conf[rx_lcore_id].n_rx_port ==
+		       l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n", (unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					     rte_eth_dev_socket_id(portid),
+					     NULL,
+					     l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+    cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+			"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..e57b7c3
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,821 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE								6
+#define quad_aligned_size(x)						(x & 0x7)?((x+7)&0x7): x
+
+#define size16(data_type)							(uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED			-1
+#define NETDEV_INVALID				-1
+#define NETDEV_STATUS(data_size)	(GOOD_RETURN(data_size)?0:NETDEV_INVALID)
+#define UNUSED(x)					(void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id = 0;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY );
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close (fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY );
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close (fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	// block on read if reply is not available
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id) {
+		return -1;
+	}
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return leng;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs), param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size)){
+		return link_status;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return leng;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_ringparam(uint8_t port_id, struct ethtool_ringparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_ringparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return valid;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t* param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY );
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else {
+			*param2_size = 0;
+		}
+	}
+	close (fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(struct ethtool_drvinfo);
+	}
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	if ((reg_len = rte_ethtool_get_regs_len(port_id)) == 0) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(int);
+	}
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	}
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	if ((eeprom_leng = rte_ethtool_get_eeprom_len(port_id)) == 0) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(int);
+	}
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_ringparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_ringparam(port_id,
+		(struct ethtool_ringparam *)reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_ringparam));
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_ringparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_ringparam(port_id,
+		(struct ethtool_ringparam *)set_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_ringparam));
+	}
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	}
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = MAC_ADDR_SIZE;
+	}
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(struct rte_eth_stats);
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..c854811
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,153 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE			"/tmp/nic_request"
+#define REP_PIPE			"/tmp/nic_reply"
+#define PAGE_SIZE			(4*1024)
+#define STACK_SIZE			(4*PAGE_SIZE)
+#define MAXI_DATA			(1024 *6)
+#define MAXI_PARA			1024
+#define STATUS_MASK			0x8000
+#define MULTIPLE_DATA_MASK	0x4000
+#define MAXI_REQ_TYPE		16
+#define FIRST_DATA_OFFSET	8
+#define to_ptr(new_ptr_type, data, offset)			(new_ptr_type)(&((unsigned char *)(void*)data)[offset])
+#define u8ptr(x)									(uint8_t*)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT						(sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye)	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size)	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes)		(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes)				(data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size)			(data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)						(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)					((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)						((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)				(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)				((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)						(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)				((dword_ptr[0] >> 16)& 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)				(dword_ptr[1])
+
+#define BAD_RETURN(data_size)					(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)					((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)				(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)					(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)						((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)					(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data,ptr_type)	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+typedef enum _REQ_TYPE {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_ringparam,
+	set_ringparam,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+} req_t;
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif // _SHARED_FIFO_H_
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..b3b8c83
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..10ae86a
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,335 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	if ((n = rte_eth_dev_reg_leng(port_id)) > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	if ((n = rte_eth_dev_eeprom_leng(port_id)) > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_leng(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	if ((status = rte_eth_dev_reg_info(port_id, &reg_info))
+		!= 0)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_leng(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	if ((status = rte_eth_dev_get_eeprom(port_id, &eeprom_info)) != 0)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	if ((status = rte_eth_dev_set_eeprom(port_id, &eeprom_info)) != 0)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_ringparam(uint8_t port_id,
+	struct ethtool_ringparam *ring_param)
+{
+	struct rte_dev_ring_info ring_info;
+	int status;
+
+	if ((status = rte_eth_dev_get_ringparam(port_id, &ring_info)) != 0)
+		return status;
+
+	ring_param->rx_pending = ring_info.rx_pending;
+	ring_param->tx_pending = ring_info.tx_pending;
+	ring_param->rx_max_pending = ring_info.rx_max_pending;
+	ring_param->tx_max_pending = ring_info.tx_max_pending;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_ringparam(uint8_t port_id,
+	struct ethtool_ringparam *ring_param)
+{
+	struct rte_dev_ring_info ring_info;
+	int status;
+
+	ring_info.rx_max_pending = ring_param->rx_max_pending;
+	ring_info.tx_max_pending = ring_param->tx_max_pending;
+
+	if ((status = rte_eth_dev_set_ringparam(port_id, &ring_info)) != 0)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	if ((status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf)) != 0)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch(fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	if ((status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf)) != 0)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	if ((status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf)) != 0)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..10deaa1
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,412 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_ringparam:       ethtool_ops::get_ringparam
+ * rte_ethtool_set_ringparam:       ethtool_ops::set_ringparam
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom, void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom, void *words);
+
+/**
+ * Retrieve the Ethernet device ring configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_ringparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_ringparam(uint8_t port_id, struct ethtool_ringparam *ring_param);
+
+/**
+ * Setting the Ethernet device ring configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_ringparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_ringparam(uint8_t port_id, struct ethtool_ringparam *ring_param);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..d49ca98
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..4bb925d
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,417 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES/(after_ts - before_ts)
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES*8/(after_ts - before_ts)
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES*64*8/(after_ts - before_ts)
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
+}
+
+static uint32_t port_mask = 0;
+static uint32_t vf_port_mask = 0;
+static uint8_t num_of_ports = 0;
+
+inline static int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1<< port_id)) > 0;
+}
+
+inline static int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports	= reply_data[0];
+	port_mask		= reply_data2[0];
+	vf_port_mask	= reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0) {
+				printf("setrlimit returned result = %d\n", result);
+			} else {
+				printf("setrlimit succeed!!!\n");
+			}
+		} else {
+			printf("default stack size is 0x%x\n", (int)(rl.rlim_cur));
+		}
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id)) {
+		port_id = rand() & 0x1F;
+	}
+	return port_id;
+}
+
+inline static char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+int
+main(void)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_ringparam ring_param;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0) {
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+	}
+
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0) {
+				netdev_net_set_rx_mode(port_id);
+			} else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id ++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port #%d!!!\n", port_id);
+			} else {
+				printf("\nPort #%d mac addr is %s \n", port_id,
+					mac_addr_str(mac_addr));
+			}
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s fw_version: %s bus_info=%s\n"
+					"reg-size(bytes)=%d eeprom-size=%d\n", drvinfo.driver,
+					drvinfo.version, drvinfo.fw_version, drvinfo.bus_info,
+					drvinfo.regdump_len, drvinfo.eedump_len);
+			}
+
+			if ((count =netdev_ethtool_get_regs_len(port_id)) <= 0) {
+				printf("There are no registers available from device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers for dump\n", count);
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF, sizeof(struct ethtool_regs));
+				if ((count =netdev_ethtool_get_regs(port_id, &regs, reply_data))) {
+					printf("failed to run ethtool_get_regs from port #%d (error-code=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x version=0x%x\n",
+						int_ptr[0], int_ptr[10], regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			if (!is_vf_port(port_id)) {
+				if((count = netdev_ethtool_get_eeprom_len(0)) == 0)
+					printf("fail to retrieve eeprom count from port #%d\n", port_id);
+				else {
+
+					printf("eeprom size is %d bytes\n", count);
+					eeprom.offset = 20;
+					eeprom.len = 80;
+					eeprom.magic = 0;
+					if (netdev_ethtool_get_eeprom(port_id, &eeprom, reply_data)) {
+						printf("Fail to read eeprom from port #%d\n", port_id);
+					} else {
+						int i;
+						uint16_t *word = (uint16_t *)((void*)reply_data);
+
+						printf("eeprom-magic: %x; read-back eeprom data ...\n", eeprom.magic);
+						for(i = 0; i < (int)(eeprom.len >> 1); i++) {
+							if (((i+1) %16) == 0)
+								printf("\n");
+							printf("%4x ", word[i]);
+						}
+						printf("\n");
+					}
+				}
+			}
+		}
+	}
+
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id ++) {
+		if (netdev_net_get_mac_addr(port_id, to_mac_type(mac_addr))) {
+			printf("Fail to get mac addr from port #%d!!!\n", port_id);
+		} else {
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+		}
+
+		strncpy((char *)mac_addr, (char *)mac_base_addr, MAC_ADDR_SIZE);
+		mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+
+		printf("New MAC address:%s is %s unicast mac address\n",
+			mac_addr_str(mac_addr),
+			netdev_net_validate_addr(port_id,
+			to_mac_type(mac_addr))?"a valid":"an invalid");
+		sleep(1);
+
+		if (netdev_net_set_mac_addr(port_id, to_mac_type(mac_addr)) ||
+			netdev_net_get_mac_addr(port_id, to_mac_type(mac_addr))) {
+			printf("Fail to reset mac addr from port #%d!!!\n", port_id);
+		} else {
+			printf("After reset, device mac addr is %s\n",
+				mac_addr_str(mac_addr));
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n", port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n", port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets, last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets, last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes, last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes, last_ts, ts));
+
+		if (!is_vf_port(port_id)
+			|| (netdev_ethtool_get_regs_len(port_id) == 0)
+			) {
+			printf("Getting ringparam from a %s\n", is_vf_port(port_id)?"VF":"PF");
+
+			if (netdev_ethtool_get_ringparam(port_id, &ring_param)) {
+				printf("Fail to retrieve descriptor ring info!!!\n");
+			} else {
+				printf("Rx/Tx descriptor ring info for queue 0!!!\n");
+				printf("Tx-max=%d Tx-pending=%d Rx-max=%d Rx-pend=%d\n",
+					ring_param.tx_max_pending, ring_param.tx_pending,
+					ring_param.rx_max_pending, ring_param.rx_pending);
+			}
+		}
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		if (link_up)
+			netdev_net_stop(port_id);
+	}
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		if (!is_vf_port(port_id)) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (!link_up) {
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				if (netdev_ethtool_get_eeprom(port_id, &eeprom, reply_data)) {
+					printf("failed to read eeprom break from post-run"
+						" testing!!!\n");
+					break;
+				}
+				if (netdev_ethtool_set_eeprom(port_id, &eeprom, reply_data)) {
+					printf("Fail to write read-back data to eeprom!!!\n");
+					break;
+				}
+				/* checking mtu setting */
+				if (netdev_net_change_mtu(port_id, mtu))
+					printf("failed to set mtu to %d\n", mtu);
+
+				/* add/remove vlan to vid */
+				if (netdev_net_vlan_rx_add_vid(port_id, 0) == 0) {
+					if (netdev_net_vlan_rx_kill_vid(port_id, 0)) {
+						printf("fail to kill vid 0 vlan\n");
+						break;
+					}
+				} else {
+					printf("fail to add vid 0 vlan\n");
+					break;
+				}
+
+				/* testing pause parameter get/set functions */
+				if (netdev_ethtool_get_pauseparam(port_id, &pause_param)) {
+					printf("fail to get pause param\n");
+					break;
+				}
+				printf("pause setup: autoneg: %d tx_pause: %d rx_pause: %d\n",
+					pause_param.autoneg, pause_param.tx_pause,
+					pause_param.rx_pause);
+
+				if (netdev_ethtool_set_pauseparam(port_id, &pause_param)) {
+					printf("fail to set pause param\n");
+					break;
+				}
+
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0);
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-10 15:21     ` David Harton (dharton)
  2015-06-11 12:26     ` Ananyev, Konstantin
  1 sibling, 0 replies; 174+ messages in thread
From: David Harton (dharton) @ 2015-06-10 15:21 UTC (permalink / raw)
  To: Liang-Min Larry Wang, dev

Sorry for spam and providing feedback here again.

> -----Original Message-----
> From: Liang-Min Larry Wang [mailto:liang-min.wang@intel.com]
> Sent: Wednesday, June 10, 2015 11:10 AM
> To: dev@dpdk.org
> Cc: Andrew Harvey (agh); Roger Melton (rmelton); David Harton (dharton);
> Liang-Min Larry Wang
> Subject: [PATCH v4 1/4] ethdev: add apis to support access device info
> 
> add new apis:
> - rte_eth_dev_default_mac_addr_set
> - rte_eth_dev_reg_leng
> - rte_eth_dev_reg_info
> - rte_eth_dev_eeprom_leng

<dharton> I know this is a bit of a nit but please consider changing "leng" to "length".
Some places already use "length" in the diffs below so using length would be consistent.

> - rte_eth_dev_get_eeprom
> - rte_eth_dev_set_eeprom
> - rte_eth_dev_get_ringparam
> - rte_eth_dev_set_ringparam
> 
> to enable reading device parameters (mac-addr, register, eeprom, ring)
> based upon ethtool alike data parameter specification.
> 
> Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> ---
>  lib/librte_ether/Makefile              |   1 +
>  lib/librte_ether/rte_eth_dev_info.h    |  80 +++++++++++++++++
>  lib/librte_ether/rte_ethdev.c          | 159
> +++++++++++++++++++++++++++++++++
>  lib/librte_ether/rte_ethdev.h          | 158
> ++++++++++++++++++++++++++++++++
>  lib/librte_ether/rte_ether_version.map |   8 ++
>  5 files changed, 406 insertions(+)
>  create mode 100644 lib/librte_ether/rte_eth_dev_info.h
> 
> diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile index
> c0e5768..05209e9 100644
> --- a/lib/librte_ether/Makefile
> +++ b/lib/librte_ether/Makefile
> @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c  SYMLINK-y-include += rte_ether.h
> SYMLINK-y-include += rte_ethdev.h  SYMLINK-y-include += rte_eth_ctrl.h
> +SYMLINK-y-include += rte_eth_dev_info.h
> 
>  # this lib depends upon:
>  DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring
> lib/librte_mbuf diff --git a/lib/librte_ether/rte_eth_dev_info.h
> b/lib/librte_ether/rte_eth_dev_info.h
> new file mode 100644
> index 0000000..002c4b5
> --- /dev/null
> +++ b/lib/librte_ether/rte_eth_dev_info.h
> @@ -0,0 +1,80 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> + *   All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above
> copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of Intel Corporation nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
> USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#ifndef _RTE_ETH_DEV_INFO_H_
> +#define _RTE_ETH_DEV_INFO_H_
> +
> +
> +/*
> + * Placeholder for accessing device registers  */ struct
> +rte_dev_reg_info {
> +	void *buf; /**< Buffer for register */
> +	uint32_t offset; /**< Offset for 1st register to fetch */
> +	uint32_t leng; /**< Number of registers to fetch */
> +	uint32_t version; /**< Device version */ };
> +
> +/*
> + * Placeholder for accessing device eeprom  */ struct
> +rte_dev_eeprom_info {
> +	void *buf; /**< Buffer for eeprom */
> +	uint32_t offset; /**< Offset for 1st eeprom location to access */
> +	uint32_t leng; /**< Length of eeprom region to access */
> +	uint32_t magic; /**< Device ID */
> +};
> +
> +/*
> + * Placeholder for accessing device ring parameters  */ struct
> +rte_dev_ring_info {
> +	uint32_t rx_pending; /**< Number of outstanding Rx ring */
> +	uint32_t tx_pending; /**< Number of outstanding Tx ring */
> +	uint32_t rx_max_pending; /**< Maximum number of outstanding Rx ring
> */
> +	uint32_t tx_max_pending; /**< Maximum number of outstanding Tx ring
> */
> +};
> +
> +/*
> + * A data structure captures information as defined in struct
> +ifla_vf_info
> + * for user-space api
> + */
> +struct rte_dev_vf_info {
> +	uint32_t vf;
> +	uint8_t mac[ETHER_ADDR_LEN];
> +	uint32_t vlan;
> +	uint32_t tx_rate;
> +	uint32_t spoofchk;
> +};
> +
> +#endif /* _RTE_ETH_DEV_INFO_H_ */
> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
> index 5a94654..186e85c 100644
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -2751,6 +2751,32 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct
> ether_addr *addr)  }
> 
>  int
> +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr
> +*addr) {
> +	struct rte_eth_dev *dev;
> +	const int index = 0;
> +	const uint32_t pool = 0;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	dev = &rte_eth_devices[port_id];
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_remove, -ENOTSUP);
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -ENOTSUP);
> +
> +	/* Update NIC default MAC address*/
> +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> +
> +	/* Update default address in NIC data structure */
> +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> +
> +	return 0;
> +}
> +
> +int
>  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
>  				uint16_t rx_mode, uint8_t on)
>  {
> @@ -3627,3 +3653,136 @@ rte_eth_remove_tx_callback(uint8_t port_id,
> uint16_t queue_id,
>  	/* Callback wasn't found. */
>  	return -EINVAL;
>  }
> +
> +int
> +rte_eth_dev_reg_leng(uint8_t port_id)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
> +	return (*dev->dev_ops->get_reg_length)(dev);
> +}
> +
> +int
> +rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info) {
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
> +	return (*dev->dev_ops->get_reg)(dev, info); }
> +
> +int
> +rte_eth_dev_eeprom_leng(uint8_t port_id) {
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
> +	return (*dev->dev_ops->get_eeprom_length)(dev);
> +}
> +
> +int
> +rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info
> +*info) {
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
> +	return (*dev->dev_ops->get_eeprom)(dev, info); }
> +
> +int
> +rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info
> +*info) {
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
> +	return (*dev->dev_ops->set_eeprom)(dev, info); }
> +
> +int
> +rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info
> +*info) {
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -ENOTSUP);
> +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> +
> +int
> +rte_eth_dev_set_ringparam(uint8_t port_id, struct rte_dev_ring_info
> +*info) {
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_ringparam, -ENOTSUP);
> +	return (*dev->dev_ops->set_ringparam)(dev, info); }
> diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
> index 16dbe00..8f99f0d 100644
> --- a/lib/librte_ether/rte_ethdev.h
> +++ b/lib/librte_ether/rte_ethdev.h
> @@ -182,6 +182,7 @@ extern "C" {
>  #include <rte_devargs.h>
>  #include "rte_ether.h"
>  #include "rte_eth_ctrl.h"
> +#include "rte_eth_dev_info.h"
> 
>  struct rte_mbuf;
> 
> @@ -1228,6 +1229,31 @@ typedef int (*eth_udp_tunnel_del_t)(struct
> rte_eth_dev *dev,
>  				    struct rte_eth_udp_tunnel *tunnel_udp);  /**<
> @internal Delete tunneling UDP info */
> 
> +typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev); /**<
> +@internal Retrieve device register count  */
> +
> +typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_reg_info *info);
> +/**< @internal Retrieve registers  */
> +
> +typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev); /**<
> +@internal Retrieve eeprom size  */
> +
> +typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_eeprom_info *info);
> +/**< @internal Retrieve eeprom data  */
> +
> +typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_eeprom_info *info);
> +/**< @internal Program eeprom data  */
> +
> +typedef int (*eth_get_ringparam_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_ring_info *info);
> +/**< @internal Retrieve device ring descriptor  */
> +
> +typedef int (*eth_set_ringparam_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_ring_info *info);
> +/**< @internal Set device ring descriptor  */
> 
>  #ifdef RTE_NIC_BYPASS
> 
> @@ -1368,6 +1394,21 @@ struct eth_dev_ops {
>  	reta_update_t reta_update;
>  	/** Query redirection table. */
>  	reta_query_t reta_query;
> +
> +	eth_get_reg_length_t get_reg_length;
> +	/**< Get # of registers */
> +	eth_get_reg_t get_reg;
> +	/**< Get registers */
> +	eth_get_eeprom_length_t get_eeprom_length;
> +	/**< Get eeprom length */
> +	eth_get_eeprom_t get_eeprom;
> +	/**< Get eeprom data */
> +	eth_set_eeprom_t set_eeprom;
> +	/**< Set eeprom */
> +	eth_get_ringparam_t get_ringparam;
> +	/**< Get descriptor ring parameters */
> +	eth_set_ringparam_t set_ringparam;
> +	/**< Set descriptor ring parameters */
>    /* bypass control */
>  #ifdef RTE_NIC_BYPASS
>    bypass_init_t bypass_init;
> @@ -2982,6 +3023,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct
> ether_addr *mac_addr,  int rte_eth_dev_mac_addr_remove(uint8_t port,
> struct ether_addr *mac_addr);
> 
>  /**
> + * Set the default MAC address.
> + *
> + * @param port
> + *   The port identifier of the Ethernet device.
> + * @param mac_addr
> + *   New default MAC address.
> + * @return
> + *   - (0) if successful, or *mac_addr* didn't exist.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port* invalid.
> + */
> +int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr
> +*mac_addr);
> +
> +/**
>   * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet
> device.
>   *
>   * @param port
> @@ -3611,6 +3666,109 @@ int rte_eth_remove_rx_callback(uint8_t port_id,
> uint16_t queue_id,  int rte_eth_remove_tx_callback(uint8_t port_id,
> uint16_t queue_id,
>  		struct rte_eth_rxtx_callback *user_cb);
> 
> +/**
> + * Retrieve number of available registers for access
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @return
> + *   - (>=0) number of registers if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_reg_leng(uint8_t port_id);
> +
> +/**
> + * Retrieve device registers and register attributes
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes buffer for register data and attribute to be
> filled.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info
> +*info);
> +
> +/**
> + * Retrieve size of device EEPROM
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @return
> + *   - (>=0) EEPROM size if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_eeprom_leng(uint8_t port_id);
> +
> +/**
> + * Retrieve EEPROM and EEPROM attribute
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes buffer for return EEPROM data and
> + *   EEPROM attributes to be filled.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info
> +*info);
> +
> +/**
> + * Program EEPROM with provided data
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes EEPROM data for programming and
> + *   EEPROM attributes to be filled
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info
> +*info);
> +
> +/**
> + * Retrieve device descriptor ring information
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes device ring descriptor usage information.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info
> +*info);
> +
> +/**
> + * Set device ring descriptor parameters
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes descriptor ring parameters to be set.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_set_ringparam(uint8_t port_id, struct rte_dev_ring_info
> +*info);
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/lib/librte_ether/rte_ether_version.map
> b/lib/librte_ether/rte_ether_version.map
> index a2d25a6..1b1e092 100644
> --- a/lib/librte_ether/rte_ether_version.map
> +++ b/lib/librte_ether/rte_ether_version.map
> @@ -102,6 +102,14 @@ DPDK_2.0 {
>  	rte_eth_tx_queue_setup;
>  	rte_eth_xstats_get;
>  	rte_eth_xstats_reset;
> +	rte_eth_dev_default_mac_addr_set;
> +	rte_eth_dev_reg_leng;
> +	rte_eth_dev_reg_info;
> +	rte_eth_dev_eeprom_leng;
> +	rte_eth_dev_get_eeprom;
> +	rte_eth_dev_set_eeprom;
> +	rte_eth_dev_get_ringparam;
> +	rte_eth_dev_set_ringparam;
> 
>  	local: *;
>  };
> --
> 2.1.4

Thanks for these changes as they will prove useful in the user space.

I have no other comments beyond the one above.

Regards,
Dave

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-06-10 15:21     ` David Harton (dharton)
@ 2015-06-11 12:26     ` Ananyev, Konstantin
  2015-06-11 12:57       ` Wang, Liang-min
  1 sibling, 1 reply; 174+ messages in thread
From: Ananyev, Konstantin @ 2015-06-11 12:26 UTC (permalink / raw)
  To: Wang, Liang-min, dev; +Cc: Wang, Liang-min

Hi Larry,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Liang-Min Larry Wang
> Sent: Wednesday, June 10, 2015 4:10 PM
> To: dev@dpdk.org
> Cc: Wang, Liang-min
> Subject: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
> 
> add new apis:
> - rte_eth_dev_default_mac_addr_set
> - rte_eth_dev_reg_leng
> - rte_eth_dev_reg_info
> - rte_eth_dev_eeprom_leng
> - rte_eth_dev_get_eeprom
> - rte_eth_dev_set_eeprom
> - rte_eth_dev_get_ringparam
> - rte_eth_dev_set_ringparam
> 
> to enable reading device parameters (mac-addr, register,
> eeprom, ring) based upon ethtool alike
> data parameter specification.
> 
> Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> ---
>  lib/librte_ether/Makefile              |   1 +
>  lib/librte_ether/rte_eth_dev_info.h    |  80 +++++++++++++++++
>  lib/librte_ether/rte_ethdev.c          | 159 +++++++++++++++++++++++++++++++++
>  lib/librte_ether/rte_ethdev.h          | 158 ++++++++++++++++++++++++++++++++
>  lib/librte_ether/rte_ether_version.map |   8 ++
>  5 files changed, 406 insertions(+)
>  create mode 100644 lib/librte_ether/rte_eth_dev_info.h
> 
> diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
> index c0e5768..05209e9 100644
> --- a/lib/librte_ether/Makefile
> +++ b/lib/librte_ether/Makefile
> @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
>  SYMLINK-y-include += rte_ether.h
>  SYMLINK-y-include += rte_ethdev.h
>  SYMLINK-y-include += rte_eth_ctrl.h
> +SYMLINK-y-include += rte_eth_dev_info.h
> 
>  # this lib depends upon:
>  DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
> diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
> new file mode 100644
> index 0000000..002c4b5
> --- /dev/null
> +++ b/lib/librte_ether/rte_eth_dev_info.h
> @@ -0,0 +1,80 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> + *   All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of Intel Corporation nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#ifndef _RTE_ETH_DEV_INFO_H_
> +#define _RTE_ETH_DEV_INFO_H_
> +
> +
> +/*
> + * Placeholder for accessing device registers
> + */
> +struct rte_dev_reg_info {
> +	void *buf; /**< Buffer for register */
> +	uint32_t offset; /**< Offset for 1st register to fetch */
> +	uint32_t leng; /**< Number of registers to fetch */
> +	uint32_t version; /**< Device version */
> +};
> +
> +/*
> + * Placeholder for accessing device eeprom
> + */
> +struct rte_dev_eeprom_info {
> +	void *buf; /**< Buffer for eeprom */
> +	uint32_t offset; /**< Offset for 1st eeprom location to access */
> +	uint32_t leng; /**< Length of eeprom region to access */
> +	uint32_t magic; /**< Device ID */
> +};
> +
> +/*
> + * Placeholder for accessing device ring parameters
> + */
> +struct rte_dev_ring_info {
> +	uint32_t rx_pending; /**< Number of outstanding Rx ring */
> +	uint32_t tx_pending; /**< Number of outstanding Tx ring */
> +	uint32_t rx_max_pending; /**< Maximum number of outstanding Rx ring */
> +	uint32_t tx_max_pending; /**< Maximum number of outstanding Tx ring */
> +};
> +
> +/*
> + * A data structure captures information as defined in struct ifla_vf_info
> + * for user-space api
> + */
> +struct rte_dev_vf_info {
> +	uint32_t vf;
> +	uint8_t mac[ETHER_ADDR_LEN];
> +	uint32_t vlan;
> +	uint32_t tx_rate;
> +	uint32_t spoofchk;
> +};


Wonder what that structure is for?
I can't see it used in any function below?

> +
> +#endif /* _RTE_ETH_DEV_INFO_H_ */
> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
> index 5a94654..186e85c 100644
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -2751,6 +2751,32 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
>  }
> 
>  int
> +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
> +{
> +	struct rte_eth_dev *dev;
> +	const int index = 0;
> +	const uint32_t pool = 0;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	dev = &rte_eth_devices[port_id];
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_remove, -ENOTSUP);
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -ENOTSUP);
> +
> +	/* Update NIC default MAC address*/
> +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> +
> +	/* Update default address in NIC data structure */
> +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> +
> +	return 0;
> +}
> +
> +int
>  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
>  				uint16_t rx_mode, uint8_t on)
>  {
> @@ -3627,3 +3653,136 @@ rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
>  	/* Callback wasn't found. */
>  	return -EINVAL;
>  }
> +
> +int
> +rte_eth_dev_reg_leng(uint8_t port_id)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
> +	return (*dev->dev_ops->get_reg_length)(dev);
> +}
> +
> +int
> +rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
> +	return (*dev->dev_ops->get_reg)(dev, info);
> +}

Seems that *get_reg* stuff, will be really good addition for DPDK debugging abilities.
Though, I'd suggest we change it a bit to make more generic and flexible:

Introduce rte_eth_reg_read/rte_eth_reg_write(),
or probably even better rte_pcidev_reg_read /rte_pcidev_reg_write at EAL.
Something similar to what port_pci_reg_read/port_pci_reg_write() are doing now at testpmd.h.

struct rte_pcidev_reg_info {
   const char *name;
   uint32_t endianes, bar, offset, size, count;
};

int rte_pcidev_reg_read(const struct rte_pci_device *, const struct rte_pcidev_reg_info *, uint64_t *reg_val);

Then:
int rte_eth_dev_get_reg_info(port_id, const struct rte_pcidev_reg_info **info);

So each device would store in info a pointer to an array of it's register descriptions
(finished by zero elem?).

Then your ethtool (or any other upper layer) can do the following to read all device regs:

const struct rte_eth_dev_reg_info *reg_info;
struct rte_eth_dev_info dev_info;

rte_eth_dev_info_get(pid, &dev_info);
rte_eth_dev_get_reg_info(port_id, &reg_info);

for (i = 0; reg_info[i].name != NULL; i++) {
   ...
   rte_pcidev_read_reg(dev_info. pci_dev, reg_info[i], &v);
  ..
}

> +
> +int
> +rte_eth_dev_eeprom_leng(uint8_t port_id)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
> +	return (*dev->dev_ops->get_eeprom_length)(dev);
> +}
> +
> +int
> +rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
> +	return (*dev->dev_ops->get_eeprom)(dev, info);
> +}
> +
> +int
> +rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
> +	return (*dev->dev_ops->set_eeprom)(dev, info);
> +}
> +
> +int
> +rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info *info)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -ENOTSUP);
> +	return (*dev->dev_ops->get_ringparam)(dev, info);
> +}

I think it will be a useful addition to the ethdev API  to have an ability to retrieve current RX/TX queue parameters.
Though again, it need to be more generic, so it could be useful for non-ethtool upper layer too.
So I suggest to modify it a bit.
Something like that:

struct rte_eth_tx_queue_info {
    struct rte_eth_txconf txconf;
    uint32_t nb_tx_desc;
    uint32_t nb_max_tx_desc; /*max allowable TXDs for that queue */
    uint32_t nb_tx_free;            /* number of free TXDs at the moment of call. */
    /* other tx queue data. */ 	
};

int rte_etdev_get_tx_queue_info(portid, queue_id, struct rte_eth_tx_queue_info *qinfo)

Then, your upper layer ethtool wrapper, can implement yours ethtool_get_ringparam() by:

 ...
 struct rte_eth_tx_queue_info qinfo;
 rte_ethdev_get_tx_queue_info(port, 0, &qinfo);
ring_param->tx_pending = qinfo.nb_tx_desc -  rte_eth_rx_queue_count(port, 0);

Or probably even:
ring_param->tx_pending = qinfo.nb_tx_desc - qinfo.nb_tx_free;

Same for RX.

> +
> +int
> +rte_eth_dev_set_ringparam(uint8_t port_id, struct rte_dev_ring_info *info)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_ringparam, -ENOTSUP);
> +	return (*dev->dev_ops->set_ringparam)(dev, info);
> +}


I am a bit confused, what particular value of rte_dev_ring_info will be allowed to change?
You can't change number of RXD/TXD at runtime.
You have to stop the device first, and then reconfigure particular queue(s).
Again, you can't reset RXF/TXD without stopping RX/TX first.
So what that function is supposed to do?
As I can see currently, none of the PMD in your patch support it. 

Konstantin

> diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
> index 16dbe00..8f99f0d 100644
> --- a/lib/librte_ether/rte_ethdev.h
> +++ b/lib/librte_ether/rte_ethdev.h
> @@ -182,6 +182,7 @@ extern "C" {
>  #include <rte_devargs.h>
>  #include "rte_ether.h"
>  #include "rte_eth_ctrl.h"
> +#include "rte_eth_dev_info.h"
> 
>  struct rte_mbuf;
> 
> @@ -1228,6 +1229,31 @@ typedef int (*eth_udp_tunnel_del_t)(struct rte_eth_dev *dev,
>  				    struct rte_eth_udp_tunnel *tunnel_udp);
>  /**< @internal Delete tunneling UDP info */
> 
> +typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
> +/**< @internal Retrieve device register count  */
> +
> +typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_reg_info *info);
> +/**< @internal Retrieve registers  */
> +
> +typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
> +/**< @internal Retrieve eeprom size  */
> +
> +typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_eeprom_info *info);
> +/**< @internal Retrieve eeprom data  */
> +
> +typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_eeprom_info *info);
> +/**< @internal Program eeprom data  */
> +
> +typedef int (*eth_get_ringparam_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_ring_info *info);
> +/**< @internal Retrieve device ring descriptor  */
> +
> +typedef int (*eth_set_ringparam_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_ring_info *info);
> +/**< @internal Set device ring descriptor  */
> 
>  #ifdef RTE_NIC_BYPASS
> 
> @@ -1368,6 +1394,21 @@ struct eth_dev_ops {
>  	reta_update_t reta_update;
>  	/** Query redirection table. */
>  	reta_query_t reta_query;
> +
> +	eth_get_reg_length_t get_reg_length;
> +	/**< Get # of registers */
> +	eth_get_reg_t get_reg;
> +	/**< Get registers */
> +	eth_get_eeprom_length_t get_eeprom_length;
> +	/**< Get eeprom length */
> +	eth_get_eeprom_t get_eeprom;
> +	/**< Get eeprom data */
> +	eth_set_eeprom_t set_eeprom;
> +	/**< Set eeprom */
> +	eth_get_ringparam_t get_ringparam;
> +	/**< Get descriptor ring parameters */
> +	eth_set_ringparam_t set_ringparam;
> +	/**< Set descriptor ring parameters */
>    /* bypass control */
>  #ifdef RTE_NIC_BYPASS
>    bypass_init_t bypass_init;
> @@ -2982,6 +3023,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
>  int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
> 
>  /**
> + * Set the default MAC address.
> + *
> + * @param port
> + *   The port identifier of the Ethernet device.
> + * @param mac_addr
> + *   New default MAC address.
> + * @return
> + *   - (0) if successful, or *mac_addr* didn't exist.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port* invalid.
> + */
> +int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
> +
> +/**
>   * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
>   *
>   * @param port
> @@ -3611,6 +3666,109 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
>  int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
>  		struct rte_eth_rxtx_callback *user_cb);
> 
> +/**
> + * Retrieve number of available registers for access
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @return
> + *   - (>=0) number of registers if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_reg_leng(uint8_t port_id);
> +
> +/**
> + * Retrieve device registers and register attributes
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes buffer for register data and attribute to be filled.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
> +
> +/**
> + * Retrieve size of device EEPROM
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @return
> + *   - (>=0) EEPROM size if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_eeprom_leng(uint8_t port_id);
> +
> +/**
> + * Retrieve EEPROM and EEPROM attribute
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes buffer for return EEPROM data and
> + *   EEPROM attributes to be filled.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
> +
> +/**
> + * Program EEPROM with provided data
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes EEPROM data for programming and
> + *   EEPROM attributes to be filled
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
> +
> +/**
> + * Retrieve device descriptor ring information
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes device ring descriptor usage information.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info *info);
> +
> +/**
> + * Set device ring descriptor parameters
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes descriptor ring parameters to be set.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_set_ringparam(uint8_t port_id, struct rte_dev_ring_info *info);
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
> index a2d25a6..1b1e092 100644
> --- a/lib/librte_ether/rte_ether_version.map
> +++ b/lib/librte_ether/rte_ether_version.map
> @@ -102,6 +102,14 @@ DPDK_2.0 {
>  	rte_eth_tx_queue_setup;
>  	rte_eth_xstats_get;
>  	rte_eth_xstats_reset;
> +	rte_eth_dev_default_mac_addr_set;
> +	rte_eth_dev_reg_leng;
> +	rte_eth_dev_reg_info;
> +	rte_eth_dev_eeprom_leng;
> +	rte_eth_dev_get_eeprom;
> +	rte_eth_dev_set_eeprom;
> +	rte_eth_dev_get_ringparam;
> +	rte_eth_dev_set_ringparam;
> 
>  	local: *;
>  };
> --
> 2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-11 12:26     ` Ananyev, Konstantin
@ 2015-06-11 12:57       ` Wang, Liang-min
  2015-06-11 13:07         ` Ananyev, Konstantin
  2015-06-11 13:14         ` Ananyev, Konstantin
  0 siblings, 2 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-11 12:57 UTC (permalink / raw)
  To: Ananyev, Konstantin, dev

Hi Konstantin,

> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Thursday, June 11, 2015 8:26 AM
> To: Wang, Liang-min; dev@dpdk.org
> Cc: Wang, Liang-min
> Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> device info
> 
> Hi Larry,
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Liang-Min Larry
> > Wang
> > Sent: Wednesday, June 10, 2015 4:10 PM
> > To: dev@dpdk.org
> > Cc: Wang, Liang-min
> > Subject: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> > device info
> >
> > add new apis:
> > - rte_eth_dev_default_mac_addr_set
> > - rte_eth_dev_reg_leng
> > - rte_eth_dev_reg_info
> > - rte_eth_dev_eeprom_leng
> > - rte_eth_dev_get_eeprom
> > - rte_eth_dev_set_eeprom
> > - rte_eth_dev_get_ringparam
> > - rte_eth_dev_set_ringparam
> >
> > to enable reading device parameters (mac-addr, register, eeprom, ring)
> > based upon ethtool alike data parameter specification.
> >
> > Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> > ---
> >  lib/librte_ether/Makefile              |   1 +
> >  lib/librte_ether/rte_eth_dev_info.h    |  80 +++++++++++++++++
> >  lib/librte_ether/rte_ethdev.c          | 159
> +++++++++++++++++++++++++++++++++
> >  lib/librte_ether/rte_ethdev.h          | 158
> ++++++++++++++++++++++++++++++++
> >  lib/librte_ether/rte_ether_version.map |   8 ++
> >  5 files changed, 406 insertions(+)
> >  create mode 100644 lib/librte_ether/rte_eth_dev_info.h
> >
> > diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
> > index c0e5768..05209e9 100644
> > --- a/lib/librte_ether/Makefile
> > +++ b/lib/librte_ether/Makefile
> > @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c  SYMLINK-y-include +=
> > rte_ether.h  SYMLINK-y-include += rte_ethdev.h  SYMLINK-y-include +=
> > rte_eth_ctrl.h
> > +SYMLINK-y-include += rte_eth_dev_info.h
> >
> >  # this lib depends upon:
> >  DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring
> > lib/librte_mbuf diff --git a/lib/librte_ether/rte_eth_dev_info.h
> > b/lib/librte_ether/rte_eth_dev_info.h
> > new file mode 100644
> > index 0000000..002c4b5
> > --- /dev/null
> > +++ b/lib/librte_ether/rte_eth_dev_info.h
> > @@ -0,0 +1,80 @@
> > +/*-
> > + *   BSD LICENSE
> > + *
> > + *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> > + *   All rights reserved.
> > + *
> > + *   Redistribution and use in source and binary forms, with or without
> > + *   modification, are permitted provided that the following conditions
> > + *   are met:
> > + *
> > + *     * Redistributions of source code must retain the above copyright
> > + *       notice, this list of conditions and the following disclaimer.
> > + *     * Redistributions in binary form must reproduce the above copyright
> > + *       notice, this list of conditions and the following disclaimer in
> > + *       the documentation and/or other materials provided with the
> > + *       distribution.
> > + *     * Neither the name of Intel Corporation nor the names of its
> > + *       contributors may be used to endorse or promote products derived
> > + *       from this software without specific prior written permission.
> > + *
> > + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> > + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> NOT
> > + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> FITNESS FOR
> > + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> > + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> > + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> BUT NOT
> > + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> LOSS OF USE,
> > + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> AND ON ANY
> > + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> > + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> OF THE USE
> > + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> > + */
> > +
> > +#ifndef _RTE_ETH_DEV_INFO_H_
> > +#define _RTE_ETH_DEV_INFO_H_
> > +
> > +
> > +/*
> > + * Placeholder for accessing device registers  */ struct
> > +rte_dev_reg_info {
> > +	void *buf; /**< Buffer for register */
> > +	uint32_t offset; /**< Offset for 1st register to fetch */
> > +	uint32_t leng; /**< Number of registers to fetch */
> > +	uint32_t version; /**< Device version */ };
> > +
> > +/*
> > + * Placeholder for accessing device eeprom  */ struct
> > +rte_dev_eeprom_info {
> > +	void *buf; /**< Buffer for eeprom */
> > +	uint32_t offset; /**< Offset for 1st eeprom location to access */
> > +	uint32_t leng; /**< Length of eeprom region to access */
> > +	uint32_t magic; /**< Device ID */
> > +};
> > +
> > +/*
> > + * Placeholder for accessing device ring parameters  */ struct
> > +rte_dev_ring_info {
> > +	uint32_t rx_pending; /**< Number of outstanding Rx ring */
> > +	uint32_t tx_pending; /**< Number of outstanding Tx ring */
> > +	uint32_t rx_max_pending; /**< Maximum number of outstanding Rx
> ring */
> > +	uint32_t tx_max_pending; /**< Maximum number of outstanding Tx
> ring
> > +*/ };
> > +
> > +/*
> > + * A data structure captures information as defined in struct
> > +ifla_vf_info
> > + * for user-space api
> > + */
> > +struct rte_dev_vf_info {
> > +	uint32_t vf;
> > +	uint8_t mac[ETHER_ADDR_LEN];
> > +	uint32_t vlan;
> > +	uint32_t tx_rate;
> > +	uint32_t spoofchk;
> > +};
> 
> 
> Wonder what that structure is for?
> I can't see it used in any function below?
> 

Good catch, this is designed for other ethtool ops that I did not include in this release, I will remove this from next fix.

> > +
> > +#endif /* _RTE_ETH_DEV_INFO_H_ */
> > diff --git a/lib/librte_ether/rte_ethdev.c
> > b/lib/librte_ether/rte_ethdev.c index 5a94654..186e85c 100644
> > --- a/lib/librte_ether/rte_ethdev.c
> > +++ b/lib/librte_ether/rte_ethdev.c
> > @@ -2751,6 +2751,32 @@ rte_eth_dev_mac_addr_remove(uint8_t
> port_id,
> > struct ether_addr *addr)  }
> >
> >  int
> > +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr
> > +*addr) {
> > +	struct rte_eth_dev *dev;
> > +	const int index = 0;
> > +	const uint32_t pool = 0;
> > +
> > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > +		return -ENODEV;
> > +	}
> > +
> > +	dev = &rte_eth_devices[port_id];
> > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_remove, -
> ENOTSUP);
> > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -
> ENOTSUP);
> > +
> > +	/* Update NIC default MAC address*/
> > +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> > +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> > +
> > +	/* Update default address in NIC data structure */
> > +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> > +
> > +	return 0;
> > +}
> > +
> > +int
> >  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
> >  				uint16_t rx_mode, uint8_t on)
> >  {
> > @@ -3627,3 +3653,136 @@ rte_eth_remove_tx_callback(uint8_t port_id,
> uint16_t queue_id,
> >  	/* Callback wasn't found. */
> >  	return -EINVAL;
> >  }
> > +
> > +int
> > +rte_eth_dev_reg_leng(uint8_t port_id) {
> > +	struct rte_eth_dev *dev;
> > +
> > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > +		return -ENODEV;
> > +	}
> > +
> > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -
> ENOTSUP);
> > +	return (*dev->dev_ops->get_reg_length)(dev);
> > +}
> > +
> > +int
> > +rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
> > +{
> > +	struct rte_eth_dev *dev;
> > +
> > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > +		return -ENODEV;
> > +	}
> > +
> > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
> > +	return (*dev->dev_ops->get_reg)(dev, info); }
> 
> Seems that *get_reg* stuff, will be really good addition for DPDK debugging
> abilities.
> Though, I'd suggest we change it a bit to make more generic and flexible:
> 
> Introduce rte_eth_reg_read/rte_eth_reg_write(),
> or probably even better rte_pcidev_reg_read /rte_pcidev_reg_write at EAL.
> Something similar to what port_pci_reg_read/port_pci_reg_write() are
> doing now at testpmd.h.
> 
> struct rte_pcidev_reg_info {
>    const char *name;
>    uint32_t endianes, bar, offset, size, count; };
> 
> int rte_pcidev_reg_read(const struct rte_pci_device *, const struct
> rte_pcidev_reg_info *, uint64_t *reg_val);
> 
> Then:
> int rte_eth_dev_get_reg_info(port_id, const struct rte_pcidev_reg_info
> **info);
> 
> So each device would store in info a pointer to an array of it's register
> descriptions (finished by zero elem?).
> 
> Then your ethtool (or any other upper layer) can do the following to read all
> device regs:
> 

The proposed reg info structure allows future improvement to support individual register read/write.
Also, because each NIC device has a very distinguish register definition.
So, the plan is to have more comprehensive interface to support query operation (for example, register name) before introduce individual/group register access.
Points taken, the support will be in future release.

> const struct rte_eth_dev_reg_info *reg_info; struct rte_eth_dev_info
> dev_info;
> 
> rte_eth_dev_info_get(pid, &dev_info);
> rte_eth_dev_get_reg_info(port_id, &reg_info);
> 
> for (i = 0; reg_info[i].name != NULL; i++) {
>    ...
>    rte_pcidev_read_reg(dev_info. pci_dev, reg_info[i], &v);
>   ..
> }
> 
> > +
> > +int
> > +rte_eth_dev_eeprom_leng(uint8_t port_id) {
> > +	struct rte_eth_dev *dev;
> > +
> > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > +		return -ENODEV;
> > +	}
> > +
> > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -
> ENOTSUP);
> > +	return (*dev->dev_ops->get_eeprom_length)(dev);
> > +}
> > +
> > +int
> > +rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info
> > +*info) {
> > +	struct rte_eth_dev *dev;
> > +
> > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > +		return -ENODEV;
> > +	}
> > +
> > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -
> ENOTSUP);
> > +	return (*dev->dev_ops->get_eeprom)(dev, info); }
> > +
> > +int
> > +rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info
> > +*info) {
> > +	struct rte_eth_dev *dev;
> > +
> > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > +		return -ENODEV;
> > +	}
> > +
> > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -
> ENOTSUP);
> > +	return (*dev->dev_ops->set_eeprom)(dev, info); }
> > +
> > +int
> > +rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info
> > +*info) {
> > +	struct rte_eth_dev *dev;
> > +
> > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > +		return -ENODEV;
> > +	}
> > +
> > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> ENOTSUP);
> > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> 
> I think it will be a useful addition to the ethdev API  to have an ability to
> retrieve current RX/TX queue parameters.
> Though again, it need to be more generic, so it could be useful for non-
> ethtool upper layer too.
> So I suggest to modify it a bit.
> Something like that:
> 
> struct rte_eth_tx_queue_info {
>     struct rte_eth_txconf txconf;
>     uint32_t nb_tx_desc;
>     uint32_t nb_max_tx_desc; /*max allowable TXDs for that queue */
>     uint32_t nb_tx_free;            /* number of free TXDs at the moment of call.
> */
>     /* other tx queue data. */
> };
> 
> int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> rte_eth_tx_queue_info *qinfo)
> 
> Then, your upper layer ethtool wrapper, can implement yours
> ethtool_get_ringparam() by:
> 
>  ...
>  struct rte_eth_tx_queue_info qinfo;
>  rte_ethdev_get_tx_queue_info(port, 0, &qinfo); ring_param->tx_pending
> = qinfo.nb_tx_desc -  rte_eth_rx_queue_count(port, 0);
> 
> Or probably even:
> ring_param->tx_pending = qinfo.nb_tx_desc - qinfo.nb_tx_free;
> 
> Same for RX.
> 
For now, this descriptor ring information is used by the ethtool op. 
To make this interface simple, i.e. caller doesn't need to access other queue information.
The plan it so keep this information as it is. 
For the expansion, the ethdev can invoke the same dev op to add this information.
> > +
> > +int
> > +rte_eth_dev_set_ringparam(uint8_t port_id, struct rte_dev_ring_info
> > +*info) {
> > +	struct rte_eth_dev *dev;
> > +
> > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > +		return -ENODEV;
> > +	}
> > +
> > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_ringparam, -
> ENOTSUP);
> > +	return (*dev->dev_ops->set_ringparam)(dev, info); }
> 
> 
> I am a bit confused, what particular value of rte_dev_ring_info will be
> allowed to change?
> You can't change number of RXD/TXD at runtime.
> You have to stop the device first, and then reconfigure particular queue(s).
> Again, you can't reset RXF/TXD without stopping RX/TX first.
> So what that function is supposed to do?
> As I can see currently, none of the PMD in your patch support it.
> 

Exactly, setting RXD/TXD will require some change on kernel (RX/TX burst) function.
As you already observe that there is no dev_op registered for set_ring.
The API is created as a placeholder for future implementation.
There are a couple of idea thrown around (such as mono- increase/decrease to avoid buffer overrun).
Any suggestion is welcome. 

> Konstantin
> 
> > diff --git a/lib/librte_ether/rte_ethdev.h
> > b/lib/librte_ether/rte_ethdev.h index 16dbe00..8f99f0d 100644
> > --- a/lib/librte_ether/rte_ethdev.h
> > +++ b/lib/librte_ether/rte_ethdev.h
> > @@ -182,6 +182,7 @@ extern "C" {
> >  #include <rte_devargs.h>
> >  #include "rte_ether.h"
> >  #include "rte_eth_ctrl.h"
> > +#include "rte_eth_dev_info.h"
> >
> >  struct rte_mbuf;
> >
> > @@ -1228,6 +1229,31 @@ typedef int (*eth_udp_tunnel_del_t)(struct
> rte_eth_dev *dev,
> >  				    struct rte_eth_udp_tunnel *tunnel_udp);
> /**< @internal
> > Delete tunneling UDP info */
> >
> > +typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev); /**<
> > +@internal Retrieve device register count  */
> > +
> > +typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
> > +				struct rte_dev_reg_info *info);
> > +/**< @internal Retrieve registers  */
> > +
> > +typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
> /**<
> > +@internal Retrieve eeprom size  */
> > +
> > +typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
> > +				struct rte_dev_eeprom_info *info); /**<
> @internal Retrieve eeprom
> > +data  */
> > +
> > +typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
> > +				struct rte_dev_eeprom_info *info); /**<
> @internal Program eeprom
> > +data  */
> > +
> > +typedef int (*eth_get_ringparam_t)(struct rte_eth_dev *dev,
> > +				struct rte_dev_ring_info *info);
> > +/**< @internal Retrieve device ring descriptor  */
> > +
> > +typedef int (*eth_set_ringparam_t)(struct rte_eth_dev *dev,
> > +				struct rte_dev_ring_info *info);
> > +/**< @internal Set device ring descriptor  */
> >
> >  #ifdef RTE_NIC_BYPASS
> >
> > @@ -1368,6 +1394,21 @@ struct eth_dev_ops {
> >  	reta_update_t reta_update;
> >  	/** Query redirection table. */
> >  	reta_query_t reta_query;
> > +
> > +	eth_get_reg_length_t get_reg_length;
> > +	/**< Get # of registers */
> > +	eth_get_reg_t get_reg;
> > +	/**< Get registers */
> > +	eth_get_eeprom_length_t get_eeprom_length;
> > +	/**< Get eeprom length */
> > +	eth_get_eeprom_t get_eeprom;
> > +	/**< Get eeprom data */
> > +	eth_set_eeprom_t set_eeprom;
> > +	/**< Set eeprom */
> > +	eth_get_ringparam_t get_ringparam;
> > +	/**< Get descriptor ring parameters */
> > +	eth_set_ringparam_t set_ringparam;
> > +	/**< Set descriptor ring parameters */
> >    /* bypass control */
> >  #ifdef RTE_NIC_BYPASS
> >    bypass_init_t bypass_init;
> > @@ -2982,6 +3023,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port,
> > struct ether_addr *mac_addr,  int
> rte_eth_dev_mac_addr_remove(uint8_t
> > port, struct ether_addr *mac_addr);
> >
> >  /**
> > + * Set the default MAC address.
> > + *
> > + * @param port
> > + *   The port identifier of the Ethernet device.
> > + * @param mac_addr
> > + *   New default MAC address.
> > + * @return
> > + *   - (0) if successful, or *mac_addr* didn't exist.
> > + *   - (-ENOTSUP) if hardware doesn't support.
> > + *   - (-ENODEV) if *port* invalid.
> > + */
> > +int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr
> > +*mac_addr);
> > +
> > +/**
> >   * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet
> device.
> >   *
> >   * @param port
> > @@ -3611,6 +3666,109 @@ int rte_eth_remove_rx_callback(uint8_t
> > port_id, uint16_t queue_id,  int rte_eth_remove_tx_callback(uint8_t
> port_id, uint16_t queue_id,
> >  		struct rte_eth_rxtx_callback *user_cb);
> >
> > +/**
> > + * Retrieve number of available registers for access
> > + *
> > + * @param port_id
> > + *   The port identifier of the Ethernet device.
> > + * @return
> > + *   - (>=0) number of registers if successful.
> > + *   - (-ENOTSUP) if hardware doesn't support.
> > + *   - (-ENODEV) if *port_id* invalid.
> > + *   - others depends on the specific operations implementation.
> > + */
> > +int rte_eth_dev_reg_leng(uint8_t port_id);
> > +
> > +/**
> > + * Retrieve device registers and register attributes
> > + *
> > + * @param port_id
> > + *   The port identifier of the Ethernet device.
> > + * @param info
> > + *   The template includes buffer for register data and attribute to be
> filled.
> > + * @return
> > + *   - (0) if successful.
> > + *   - (-ENOTSUP) if hardware doesn't support.
> > + *   - (-ENODEV) if *port_id* invalid.
> > + *   - others depends on the specific operations implementation.
> > + */
> > +int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info
> > +*info);
> > +
> > +/**
> > + * Retrieve size of device EEPROM
> > + *
> > + * @param port_id
> > + *   The port identifier of the Ethernet device.
> > + * @return
> > + *   - (>=0) EEPROM size if successful.
> > + *   - (-ENOTSUP) if hardware doesn't support.
> > + *   - (-ENODEV) if *port_id* invalid.
> > + *   - others depends on the specific operations implementation.
> > + */
> > +int rte_eth_dev_eeprom_leng(uint8_t port_id);
> > +
> > +/**
> > + * Retrieve EEPROM and EEPROM attribute
> > + *
> > + * @param port_id
> > + *   The port identifier of the Ethernet device.
> > + * @param info
> > + *   The template includes buffer for return EEPROM data and
> > + *   EEPROM attributes to be filled.
> > + * @return
> > + *   - (0) if successful.
> > + *   - (-ENOTSUP) if hardware doesn't support.
> > + *   - (-ENODEV) if *port_id* invalid.
> > + *   - others depends on the specific operations implementation.
> > + */
> > +int rte_eth_dev_get_eeprom(uint8_t port_id, struct
> > +rte_dev_eeprom_info *info);
> > +
> > +/**
> > + * Program EEPROM with provided data
> > + *
> > + * @param port_id
> > + *   The port identifier of the Ethernet device.
> > + * @param info
> > + *   The template includes EEPROM data for programming and
> > + *   EEPROM attributes to be filled
> > + * @return
> > + *   - (0) if successful.
> > + *   - (-ENOTSUP) if hardware doesn't support.
> > + *   - (-ENODEV) if *port_id* invalid.
> > + *   - others depends on the specific operations implementation.
> > + */
> > +int rte_eth_dev_set_eeprom(uint8_t port_id, struct
> > +rte_dev_eeprom_info *info);
> > +
> > +/**
> > + * Retrieve device descriptor ring information
> > + *
> > + * @param port_id
> > + *   The port identifier of the Ethernet device.
> > + * @param info
> > + *   The template includes device ring descriptor usage information.
> > + * @return
> > + *   - (0) if successful.
> > + *   - (-ENOTSUP) if hardware doesn't support.
> > + *   - (-ENODEV) if *port_id* invalid.
> > + *   - others depends on the specific operations implementation.
> > + */
> > +int rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > +rte_dev_ring_info *info);
> > +
> > +/**
> > + * Set device ring descriptor parameters
> > + *
> > + * @param port_id
> > + *   The port identifier of the Ethernet device.
> > + * @param info
> > + *   The template includes descriptor ring parameters to be set.
> > + * @return
> > + *   - (0) if successful.
> > + *   - (-ENOTSUP) if hardware doesn't support.
> > + *   - (-ENODEV) if *port_id* invalid.
> > + *   - others depends on the specific operations implementation.
> > + */
> > +int rte_eth_dev_set_ringparam(uint8_t port_id, struct
> > +rte_dev_ring_info *info);
> > +
> >  #ifdef __cplusplus
> >  }
> >  #endif
> > diff --git a/lib/librte_ether/rte_ether_version.map
> > b/lib/librte_ether/rte_ether_version.map
> > index a2d25a6..1b1e092 100644
> > --- a/lib/librte_ether/rte_ether_version.map
> > +++ b/lib/librte_ether/rte_ether_version.map
> > @@ -102,6 +102,14 @@ DPDK_2.0 {
> >  	rte_eth_tx_queue_setup;
> >  	rte_eth_xstats_get;
> >  	rte_eth_xstats_reset;
> > +	rte_eth_dev_default_mac_addr_set;
> > +	rte_eth_dev_reg_leng;
> > +	rte_eth_dev_reg_info;
> > +	rte_eth_dev_eeprom_leng;
> > +	rte_eth_dev_get_eeprom;
> > +	rte_eth_dev_set_eeprom;
> > +	rte_eth_dev_get_ringparam;
> > +	rte_eth_dev_set_ringparam;
> >
> >  	local: *;
> >  };
> > --
> > 2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-11 12:57       ` Wang, Liang-min
@ 2015-06-11 13:07         ` Ananyev, Konstantin
  2015-06-11 21:51           ` Wang, Liang-min
  2015-06-11 13:14         ` Ananyev, Konstantin
  1 sibling, 1 reply; 174+ messages in thread
From: Ananyev, Konstantin @ 2015-06-11 13:07 UTC (permalink / raw)
  To: Wang, Liang-min, dev



> -----Original Message-----
> From: Wang, Liang-min
> Sent: Thursday, June 11, 2015 1:58 PM
> To: Ananyev, Konstantin; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
> 
> Hi Konstantin,
> 
> > -----Original Message-----
> > From: Ananyev, Konstantin
> > Sent: Thursday, June 11, 2015 8:26 AM
> > To: Wang, Liang-min; dev@dpdk.org
> > Cc: Wang, Liang-min
> > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> > device info
> >
> > Hi Larry,
> >
> > > -----Original Message-----
> > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Liang-Min Larry
> > > Wang
> > > Sent: Wednesday, June 10, 2015 4:10 PM
> > > To: dev@dpdk.org
> > > Cc: Wang, Liang-min
> > > Subject: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> > > device info
> > >
> > > add new apis:
> > > - rte_eth_dev_default_mac_addr_set
> > > - rte_eth_dev_reg_leng
> > > - rte_eth_dev_reg_info
> > > - rte_eth_dev_eeprom_leng
> > > - rte_eth_dev_get_eeprom
> > > - rte_eth_dev_set_eeprom
> > > - rte_eth_dev_get_ringparam
> > > - rte_eth_dev_set_ringparam
> > >
> > > to enable reading device parameters (mac-addr, register, eeprom, ring)
> > > based upon ethtool alike data parameter specification.
> > >
> > > Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> > > ---
> > >  lib/librte_ether/Makefile              |   1 +
> > >  lib/librte_ether/rte_eth_dev_info.h    |  80 +++++++++++++++++
> > >  lib/librte_ether/rte_ethdev.c          | 159
> > +++++++++++++++++++++++++++++++++
> > >  lib/librte_ether/rte_ethdev.h          | 158
> > ++++++++++++++++++++++++++++++++
> > >  lib/librte_ether/rte_ether_version.map |   8 ++
> > >  5 files changed, 406 insertions(+)
> > >  create mode 100644 lib/librte_ether/rte_eth_dev_info.h
> > >
> > > diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
> > > index c0e5768..05209e9 100644
> > > --- a/lib/librte_ether/Makefile
> > > +++ b/lib/librte_ether/Makefile
> > > @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c  SYMLINK-y-include +=
> > > rte_ether.h  SYMLINK-y-include += rte_ethdev.h  SYMLINK-y-include +=
> > > rte_eth_ctrl.h
> > > +SYMLINK-y-include += rte_eth_dev_info.h
> > >
> > >  # this lib depends upon:
> > >  DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring
> > > lib/librte_mbuf diff --git a/lib/librte_ether/rte_eth_dev_info.h
> > > b/lib/librte_ether/rte_eth_dev_info.h
> > > new file mode 100644
> > > index 0000000..002c4b5
> > > --- /dev/null
> > > +++ b/lib/librte_ether/rte_eth_dev_info.h
> > > @@ -0,0 +1,80 @@
> > > +/*-
> > > + *   BSD LICENSE
> > > + *
> > > + *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> > > + *   All rights reserved.
> > > + *
> > > + *   Redistribution and use in source and binary forms, with or without
> > > + *   modification, are permitted provided that the following conditions
> > > + *   are met:
> > > + *
> > > + *     * Redistributions of source code must retain the above copyright
> > > + *       notice, this list of conditions and the following disclaimer.
> > > + *     * Redistributions in binary form must reproduce the above copyright
> > > + *       notice, this list of conditions and the following disclaimer in
> > > + *       the documentation and/or other materials provided with the
> > > + *       distribution.
> > > + *     * Neither the name of Intel Corporation nor the names of its
> > > + *       contributors may be used to endorse or promote products derived
> > > + *       from this software without specific prior written permission.
> > > + *
> > > + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > CONTRIBUTORS
> > > + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> > NOT
> > > + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> > FITNESS FOR
> > > + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> > COPYRIGHT
> > > + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> > INCIDENTAL,
> > > + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> > BUT NOT
> > > + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> > LOSS OF USE,
> > > + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> > AND ON ANY
> > > + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> > TORT
> > > + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> > OF THE USE
> > > + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > DAMAGE.
> > > + */
> > > +
> > > +#ifndef _RTE_ETH_DEV_INFO_H_
> > > +#define _RTE_ETH_DEV_INFO_H_
> > > +
> > > +
> > > +/*
> > > + * Placeholder for accessing device registers  */ struct
> > > +rte_dev_reg_info {
> > > +	void *buf; /**< Buffer for register */
> > > +	uint32_t offset; /**< Offset for 1st register to fetch */
> > > +	uint32_t leng; /**< Number of registers to fetch */
> > > +	uint32_t version; /**< Device version */ };
> > > +
> > > +/*
> > > + * Placeholder for accessing device eeprom  */ struct
> > > +rte_dev_eeprom_info {
> > > +	void *buf; /**< Buffer for eeprom */
> > > +	uint32_t offset; /**< Offset for 1st eeprom location to access */
> > > +	uint32_t leng; /**< Length of eeprom region to access */
> > > +	uint32_t magic; /**< Device ID */
> > > +};
> > > +
> > > +/*
> > > + * Placeholder for accessing device ring parameters  */ struct
> > > +rte_dev_ring_info {
> > > +	uint32_t rx_pending; /**< Number of outstanding Rx ring */
> > > +	uint32_t tx_pending; /**< Number of outstanding Tx ring */
> > > +	uint32_t rx_max_pending; /**< Maximum number of outstanding Rx
> > ring */
> > > +	uint32_t tx_max_pending; /**< Maximum number of outstanding Tx
> > ring
> > > +*/ };
> > > +
> > > +/*
> > > + * A data structure captures information as defined in struct
> > > +ifla_vf_info
> > > + * for user-space api
> > > + */
> > > +struct rte_dev_vf_info {
> > > +	uint32_t vf;
> > > +	uint8_t mac[ETHER_ADDR_LEN];
> > > +	uint32_t vlan;
> > > +	uint32_t tx_rate;
> > > +	uint32_t spoofchk;
> > > +};
> >
> >
> > Wonder what that structure is for?
> > I can't see it used in any function below?
> >
> 
> Good catch, this is designed for other ethtool ops that I did not include in this release, I will remove this from next fix.
> 
> > > +
> > > +#endif /* _RTE_ETH_DEV_INFO_H_ */
> > > diff --git a/lib/librte_ether/rte_ethdev.c
> > > b/lib/librte_ether/rte_ethdev.c index 5a94654..186e85c 100644
> > > --- a/lib/librte_ether/rte_ethdev.c
> > > +++ b/lib/librte_ether/rte_ethdev.c
> > > @@ -2751,6 +2751,32 @@ rte_eth_dev_mac_addr_remove(uint8_t
> > port_id,
> > > struct ether_addr *addr)  }
> > >
> > >  int
> > > +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr
> > > +*addr) {
> > > +	struct rte_eth_dev *dev;
> > > +	const int index = 0;
> > > +	const uint32_t pool = 0;
> > > +
> > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	dev = &rte_eth_devices[port_id];
> > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_remove, -
> > ENOTSUP);
> > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -
> > ENOTSUP);
> > > +
> > > +	/* Update NIC default MAC address*/
> > > +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> > > +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> > > +
> > > +	/* Update default address in NIC data structure */
> > > +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +int
> > >  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
> > >  				uint16_t rx_mode, uint8_t on)
> > >  {
> > > @@ -3627,3 +3653,136 @@ rte_eth_remove_tx_callback(uint8_t port_id,
> > uint16_t queue_id,
> > >  	/* Callback wasn't found. */
> > >  	return -EINVAL;
> > >  }
> > > +
> > > +int
> > > +rte_eth_dev_reg_leng(uint8_t port_id) {
> > > +	struct rte_eth_dev *dev;
> > > +
> > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -
> > ENOTSUP);
> > > +	return (*dev->dev_ops->get_reg_length)(dev);
> > > +}
> > > +
> > > +int
> > > +rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
> > > +{
> > > +	struct rte_eth_dev *dev;
> > > +
> > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
> > > +	return (*dev->dev_ops->get_reg)(dev, info); }
> >
> > Seems that *get_reg* stuff, will be really good addition for DPDK debugging
> > abilities.
> > Though, I'd suggest we change it a bit to make more generic and flexible:
> >
> > Introduce rte_eth_reg_read/rte_eth_reg_write(),
> > or probably even better rte_pcidev_reg_read /rte_pcidev_reg_write at EAL.
> > Something similar to what port_pci_reg_read/port_pci_reg_write() are
> > doing now at testpmd.h.
> >
> > struct rte_pcidev_reg_info {
> >    const char *name;
> >    uint32_t endianes, bar, offset, size, count; };
> >
> > int rte_pcidev_reg_read(const struct rte_pci_device *, const struct
> > rte_pcidev_reg_info *, uint64_t *reg_val);
> >
> > Then:
> > int rte_eth_dev_get_reg_info(port_id, const struct rte_pcidev_reg_info
> > **info);
> >
> > So each device would store in info a pointer to an array of it's register
> > descriptions (finished by zero elem?).
> >
> > Then your ethtool (or any other upper layer) can do the following to read all
> > device regs:
> >
> 
> The proposed reg info structure allows future improvement to support individual register read/write.
> Also, because each NIC device has a very distinguish register definition.
> So, the plan is to have more comprehensive interface to support query operation (for example, register name) before introduce
> individual/group register access.
> Points taken, the support will be in future release.

Sorry, didn't get you.
So you are ok to make these changes in next patch version?

> 
> > const struct rte_eth_dev_reg_info *reg_info; struct rte_eth_dev_info
> > dev_info;
> >
> > rte_eth_dev_info_get(pid, &dev_info);
> > rte_eth_dev_get_reg_info(port_id, &reg_info);
> >
> > for (i = 0; reg_info[i].name != NULL; i++) {
> >    ...
> >    rte_pcidev_read_reg(dev_info. pci_dev, reg_info[i], &v);
> >   ..
> > }
> >
> > > +
> > > +int
> > > +rte_eth_dev_eeprom_leng(uint8_t port_id) {
> > > +	struct rte_eth_dev *dev;
> > > +
> > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -
> > ENOTSUP);
> > > +	return (*dev->dev_ops->get_eeprom_length)(dev);
> > > +}
> > > +
> > > +int
> > > +rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info
> > > +*info) {
> > > +	struct rte_eth_dev *dev;
> > > +
> > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -
> > ENOTSUP);
> > > +	return (*dev->dev_ops->get_eeprom)(dev, info); }
> > > +
> > > +int
> > > +rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info
> > > +*info) {
> > > +	struct rte_eth_dev *dev;
> > > +
> > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -
> > ENOTSUP);
> > > +	return (*dev->dev_ops->set_eeprom)(dev, info); }
> > > +
> > > +int
> > > +rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info
> > > +*info) {
> > > +	struct rte_eth_dev *dev;
> > > +
> > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> > ENOTSUP);
> > > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> >
> > I think it will be a useful addition to the ethdev API  to have an ability to
> > retrieve current RX/TX queue parameters.
> > Though again, it need to be more generic, so it could be useful for non-
> > ethtool upper layer too.
> > So I suggest to modify it a bit.
> > Something like that:
> >
> > struct rte_eth_tx_queue_info {
> >     struct rte_eth_txconf txconf;
> >     uint32_t nb_tx_desc;
> >     uint32_t nb_max_tx_desc; /*max allowable TXDs for that queue */
> >     uint32_t nb_tx_free;            /* number of free TXDs at the moment of call.
> > */
> >     /* other tx queue data. */
> > };
> >
> > int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> > rte_eth_tx_queue_info *qinfo)
> >
> > Then, your upper layer ethtool wrapper, can implement yours
> > ethtool_get_ringparam() by:
> >
> >  ...
> >  struct rte_eth_tx_queue_info qinfo;
> >  rte_ethdev_get_tx_queue_info(port, 0, &qinfo); ring_param->tx_pending
> > = qinfo.nb_tx_desc -  rte_eth_rx_queue_count(port, 0);
> >
> > Or probably even:
> > ring_param->tx_pending = qinfo.nb_tx_desc - qinfo.nb_tx_free;
> >
> > Same for RX.
> >
> For now, this descriptor ring information is used by the ethtool op.
> To make this interface simple, i.e. caller doesn't need to access other queue information.

I just repeat what I said to you in off-line conversation:
ethdev API is not equal ethtool API.
It is ok to add  a new function/structure to ethdev if it really needed, but we should do mechanical one to one copy.
It is much better to add  a function/structure that would be more generic, and suit other users, not only ethtool.
There is no point to have dozen functions in rte_ethdev API providing similar information.
BTW, I don't see how API I proposed is much more  complex, then yours one.

Konstantin


> The plan it so keep this information as it is.
> For the expansion, the ethdev can invoke the same dev op to add this information.
> > > +
> > > +int
> > > +rte_eth_dev_set_ringparam(uint8_t port_id, struct rte_dev_ring_info
> > > +*info) {
> > > +	struct rte_eth_dev *dev;
> > > +
> > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_ringparam, -
> > ENOTSUP);
> > > +	return (*dev->dev_ops->set_ringparam)(dev, info); }
> >
> >
> > I am a bit confused, what particular value of rte_dev_ring_info will be
> > allowed to change?
> > You can't change number of RXD/TXD at runtime.
> > You have to stop the device first, and then reconfigure particular queue(s).
> > Again, you can't reset RXF/TXD without stopping RX/TX first.
> > So what that function is supposed to do?
> > As I can see currently, none of the PMD in your patch support it.
> >
> 
> Exactly, setting RXD/TXD will require some change on kernel (RX/TX burst) function.
> As you already observe that there is no dev_op registered for set_ring.
> The API is created as a placeholder for future implementation.
> There are a couple of idea thrown around (such as mono- increase/decrease to avoid buffer overrun).
> Any suggestion is welcome.
> 
> > Konstantin
> >
> > > diff --git a/lib/librte_ether/rte_ethdev.h
> > > b/lib/librte_ether/rte_ethdev.h index 16dbe00..8f99f0d 100644
> > > --- a/lib/librte_ether/rte_ethdev.h
> > > +++ b/lib/librte_ether/rte_ethdev.h
> > > @@ -182,6 +182,7 @@ extern "C" {
> > >  #include <rte_devargs.h>
> > >  #include "rte_ether.h"
> > >  #include "rte_eth_ctrl.h"
> > > +#include "rte_eth_dev_info.h"
> > >
> > >  struct rte_mbuf;
> > >
> > > @@ -1228,6 +1229,31 @@ typedef int (*eth_udp_tunnel_del_t)(struct
> > rte_eth_dev *dev,
> > >  				    struct rte_eth_udp_tunnel *tunnel_udp);
> > /**< @internal
> > > Delete tunneling UDP info */
> > >
> > > +typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev); /**<
> > > +@internal Retrieve device register count  */
> > > +
> > > +typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
> > > +				struct rte_dev_reg_info *info);
> > > +/**< @internal Retrieve registers  */
> > > +
> > > +typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
> > /**<
> > > +@internal Retrieve eeprom size  */
> > > +
> > > +typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
> > > +				struct rte_dev_eeprom_info *info); /**<
> > @internal Retrieve eeprom
> > > +data  */
> > > +
> > > +typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
> > > +				struct rte_dev_eeprom_info *info); /**<
> > @internal Program eeprom
> > > +data  */
> > > +
> > > +typedef int (*eth_get_ringparam_t)(struct rte_eth_dev *dev,
> > > +				struct rte_dev_ring_info *info);
> > > +/**< @internal Retrieve device ring descriptor  */
> > > +
> > > +typedef int (*eth_set_ringparam_t)(struct rte_eth_dev *dev,
> > > +				struct rte_dev_ring_info *info);
> > > +/**< @internal Set device ring descriptor  */
> > >
> > >  #ifdef RTE_NIC_BYPASS
> > >
> > > @@ -1368,6 +1394,21 @@ struct eth_dev_ops {
> > >  	reta_update_t reta_update;
> > >  	/** Query redirection table. */
> > >  	reta_query_t reta_query;
> > > +
> > > +	eth_get_reg_length_t get_reg_length;
> > > +	/**< Get # of registers */
> > > +	eth_get_reg_t get_reg;
> > > +	/**< Get registers */
> > > +	eth_get_eeprom_length_t get_eeprom_length;
> > > +	/**< Get eeprom length */
> > > +	eth_get_eeprom_t get_eeprom;
> > > +	/**< Get eeprom data */
> > > +	eth_set_eeprom_t set_eeprom;
> > > +	/**< Set eeprom */
> > > +	eth_get_ringparam_t get_ringparam;
> > > +	/**< Get descriptor ring parameters */
> > > +	eth_set_ringparam_t set_ringparam;
> > > +	/**< Set descriptor ring parameters */
> > >    /* bypass control */
> > >  #ifdef RTE_NIC_BYPASS
> > >    bypass_init_t bypass_init;
> > > @@ -2982,6 +3023,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port,
> > > struct ether_addr *mac_addr,  int
> > rte_eth_dev_mac_addr_remove(uint8_t
> > > port, struct ether_addr *mac_addr);
> > >
> > >  /**
> > > + * Set the default MAC address.
> > > + *
> > > + * @param port
> > > + *   The port identifier of the Ethernet device.
> > > + * @param mac_addr
> > > + *   New default MAC address.
> > > + * @return
> > > + *   - (0) if successful, or *mac_addr* didn't exist.
> > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > + *   - (-ENODEV) if *port* invalid.
> > > + */
> > > +int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr
> > > +*mac_addr);
> > > +
> > > +/**
> > >   * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet
> > device.
> > >   *
> > >   * @param port
> > > @@ -3611,6 +3666,109 @@ int rte_eth_remove_rx_callback(uint8_t
> > > port_id, uint16_t queue_id,  int rte_eth_remove_tx_callback(uint8_t
> > port_id, uint16_t queue_id,
> > >  		struct rte_eth_rxtx_callback *user_cb);
> > >
> > > +/**
> > > + * Retrieve number of available registers for access
> > > + *
> > > + * @param port_id
> > > + *   The port identifier of the Ethernet device.
> > > + * @return
> > > + *   - (>=0) number of registers if successful.
> > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > + *   - (-ENODEV) if *port_id* invalid.
> > > + *   - others depends on the specific operations implementation.
> > > + */
> > > +int rte_eth_dev_reg_leng(uint8_t port_id);
> > > +
> > > +/**
> > > + * Retrieve device registers and register attributes
> > > + *
> > > + * @param port_id
> > > + *   The port identifier of the Ethernet device.
> > > + * @param info
> > > + *   The template includes buffer for register data and attribute to be
> > filled.
> > > + * @return
> > > + *   - (0) if successful.
> > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > + *   - (-ENODEV) if *port_id* invalid.
> > > + *   - others depends on the specific operations implementation.
> > > + */
> > > +int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info
> > > +*info);
> > > +
> > > +/**
> > > + * Retrieve size of device EEPROM
> > > + *
> > > + * @param port_id
> > > + *   The port identifier of the Ethernet device.
> > > + * @return
> > > + *   - (>=0) EEPROM size if successful.
> > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > + *   - (-ENODEV) if *port_id* invalid.
> > > + *   - others depends on the specific operations implementation.
> > > + */
> > > +int rte_eth_dev_eeprom_leng(uint8_t port_id);
> > > +
> > > +/**
> > > + * Retrieve EEPROM and EEPROM attribute
> > > + *
> > > + * @param port_id
> > > + *   The port identifier of the Ethernet device.
> > > + * @param info
> > > + *   The template includes buffer for return EEPROM data and
> > > + *   EEPROM attributes to be filled.
> > > + * @return
> > > + *   - (0) if successful.
> > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > + *   - (-ENODEV) if *port_id* invalid.
> > > + *   - others depends on the specific operations implementation.
> > > + */
> > > +int rte_eth_dev_get_eeprom(uint8_t port_id, struct
> > > +rte_dev_eeprom_info *info);
> > > +
> > > +/**
> > > + * Program EEPROM with provided data
> > > + *
> > > + * @param port_id
> > > + *   The port identifier of the Ethernet device.
> > > + * @param info
> > > + *   The template includes EEPROM data for programming and
> > > + *   EEPROM attributes to be filled
> > > + * @return
> > > + *   - (0) if successful.
> > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > + *   - (-ENODEV) if *port_id* invalid.
> > > + *   - others depends on the specific operations implementation.
> > > + */
> > > +int rte_eth_dev_set_eeprom(uint8_t port_id, struct
> > > +rte_dev_eeprom_info *info);
> > > +
> > > +/**
> > > + * Retrieve device descriptor ring information
> > > + *
> > > + * @param port_id
> > > + *   The port identifier of the Ethernet device.
> > > + * @param info
> > > + *   The template includes device ring descriptor usage information.
> > > + * @return
> > > + *   - (0) if successful.
> > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > + *   - (-ENODEV) if *port_id* invalid.
> > > + *   - others depends on the specific operations implementation.
> > > + */
> > > +int rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > +rte_dev_ring_info *info);
> > > +
> > > +/**
> > > + * Set device ring descriptor parameters
> > > + *
> > > + * @param port_id
> > > + *   The port identifier of the Ethernet device.
> > > + * @param info
> > > + *   The template includes descriptor ring parameters to be set.
> > > + * @return
> > > + *   - (0) if successful.
> > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > + *   - (-ENODEV) if *port_id* invalid.
> > > + *   - others depends on the specific operations implementation.
> > > + */
> > > +int rte_eth_dev_set_ringparam(uint8_t port_id, struct
> > > +rte_dev_ring_info *info);
> > > +
> > >  #ifdef __cplusplus
> > >  }
> > >  #endif
> > > diff --git a/lib/librte_ether/rte_ether_version.map
> > > b/lib/librte_ether/rte_ether_version.map
> > > index a2d25a6..1b1e092 100644
> > > --- a/lib/librte_ether/rte_ether_version.map
> > > +++ b/lib/librte_ether/rte_ether_version.map
> > > @@ -102,6 +102,14 @@ DPDK_2.0 {
> > >  	rte_eth_tx_queue_setup;
> > >  	rte_eth_xstats_get;
> > >  	rte_eth_xstats_reset;
> > > +	rte_eth_dev_default_mac_addr_set;
> > > +	rte_eth_dev_reg_leng;
> > > +	rte_eth_dev_reg_info;
> > > +	rte_eth_dev_eeprom_leng;
> > > +	rte_eth_dev_get_eeprom;
> > > +	rte_eth_dev_set_eeprom;
> > > +	rte_eth_dev_get_ringparam;
> > > +	rte_eth_dev_set_ringparam;
> > >
> > >  	local: *;
> > >  };
> > > --
> > > 2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-11 12:57       ` Wang, Liang-min
  2015-06-11 13:07         ` Ananyev, Konstantin
@ 2015-06-11 13:14         ` Ananyev, Konstantin
  2015-06-11 13:25           ` Wang, Liang-min
  1 sibling, 1 reply; 174+ messages in thread
From: Ananyev, Konstantin @ 2015-06-11 13:14 UTC (permalink / raw)
  To: Wang, Liang-min, dev


> > > +
> > > +int
> > > +rte_eth_dev_set_ringparam(uint8_t port_id, struct rte_dev_ring_info
> > > +*info) {
> > > +	struct rte_eth_dev *dev;
> > > +
> > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_ringparam, -
> > ENOTSUP);
> > > +	return (*dev->dev_ops->set_ringparam)(dev, info); }
> >
> >
> > I am a bit confused, what particular value of rte_dev_ring_info will be
> > allowed to change?
> > You can't change number of RXD/TXD at runtime.
> > You have to stop the device first, and then reconfigure particular queue(s).
> > Again, you can't reset RXF/TXD without stopping RX/TX first.
> > So what that function is supposed to do?
> > As I can see currently, none of the PMD in your patch support it.
> >
> 
> Exactly, setting RXD/TXD will require some change on kernel (RX/TX burst) function.
> As you already observe that there is no dev_op registered for set_ring.
> The API is created as a placeholder for future implementation.
> There are a couple of idea thrown around (such as mono- increase/decrease to avoid buffer overrun).
> Any suggestion is welcome.

If you don't plan to implement it in current patch-set, then it is better to remove it for now.
About suggestions - as I said, I don't think it is doable without stopping (and reconfiguring) the queue.
Again not sure, why do you want to do that run-tme.
Konstantin

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-11 13:14         ` Ananyev, Konstantin
@ 2015-06-11 13:25           ` Wang, Liang-min
  0 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-11 13:25 UTC (permalink / raw)
  To: Ananyev, Konstantin, dev



> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Thursday, June 11, 2015 9:14 AM
> To: Wang, Liang-min; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> device info
> 
> 
> > > > +
> > > > +int
> > > > +rte_eth_dev_set_ringparam(uint8_t port_id, struct
> > > > +rte_dev_ring_info
> > > > +*info) {
> > > > +	struct rte_eth_dev *dev;
> > > > +
> > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_ringparam, -
> > > ENOTSUP);
> > > > +	return (*dev->dev_ops->set_ringparam)(dev, info); }
> > >
> > >
> > > I am a bit confused, what particular value of rte_dev_ring_info will
> > > be allowed to change?
> > > You can't change number of RXD/TXD at runtime.
> > > You have to stop the device first, and then reconfigure particular
> queue(s).
> > > Again, you can't reset RXF/TXD without stopping RX/TX first.
> > > So what that function is supposed to do?
> > > As I can see currently, none of the PMD in your patch support it.
> > >
> >
> > Exactly, setting RXD/TXD will require some change on kernel (RX/TX burst)
> function.
> > As you already observe that there is no dev_op registered for set_ring.
> > The API is created as a placeholder for future implementation.
> > There are a couple of idea thrown around (such as mono-
> increase/decrease to avoid buffer overrun).
> > Any suggestion is welcome.
> 
> If you don't plan to implement it in current patch-set, then it is better to
> remove it for now.
> About suggestions - as I said, I don't think it is doable without stopping (and
> reconfiguring) the queue.
> Again not sure, why do you want to do that run-tme.
> Konstantin

That's a very valid point. To support run-time ring descriptor size adjustment, we need to stop traffic in some way.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v5 0/4] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (2 preceding siblings ...)
  2015-06-10 15:09 ` [dpdk-dev] [PATCH v4 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-06-11 21:43 ` Liang-Min Larry Wang
  2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (3 more replies)
  2015-06-12 22:03 ` [dpdk-dev] [PATCH v6 0/4] User-space Ethtool Liang-Min Larry Wang
                   ` (11 subsequent siblings)
  15 siblings, 4 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-11 21:43 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (4):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  186 ++++
 drivers/net/e1000/igb_regs.h                     |  217 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  203 +++++
 drivers/net/ixgbe/ixgbe_regs.h                   |  357 ++++++++
 drivers/net/ixgbe/ixgbe_rxtx.c                   |   16 +
 drivers/net/ixgbe/ixgbe_rxtx.h                   |    1 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1052 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  821 +++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  153 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  326 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  412 +++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  427 +++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   67 ++
 lib/librte_ether/rte_ethdev.c                    |  138 +++
 lib/librte_ether/rte_ethdev.h                    |  143 +++
 lib/librte_ether/rte_ether_version.map           |    7 +
 21 files changed, 4750 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v5 1/4] ethdev: add apis to support access device info
  2015-06-11 21:43 ` [dpdk-dev] [PATCH v5 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-06-11 21:43   ` Liang-Min Larry Wang
  2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-11 21:43 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add new apis:
- rte_eth_dev_default_mac_addr_set
- rte_eth_dev_reg_length
- rte_eth_dev_reg_info
- rte_eth_dev_eeprom_length
- rte_eth_dev_get_eeprom
- rte_eth_dev_set_eeprom
- rte_eth_dev_get_ringparam

to enable reading device parameters (mac-addr, register,
eeprom, ring) based upon ethtool alike
data parameter specification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  67 +++++++++++++++
 lib/librte_ether/rte_ethdev.c          | 138 +++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 143 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   7 ++
 5 files changed, 356 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..1cf2c23
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,67 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+/*
+ * Placeholder for accessing device ring parameters
+ */
+struct rte_dev_ring_info {
+	uint32_t rx_pending; /**< Number of outstanding Rx ring */
+	uint32_t tx_pending; /**< Number of outstanding Tx ring */
+	uint32_t rx_max_pending; /**< Maximum number of outstanding Rx ring */
+	uint32_t tx_max_pending; /**< Maximum number of outstanding Tx ring */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 5a94654..52bcb5e 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2751,6 +2751,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3627,3 +3651,117 @@ rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 	/* Callback wasn't found. */
 	return -EINVAL;
 }
+
+int
+rte_eth_dev_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -ENOTSUP);
+	return (*dev->dev_ops->get_ringparam)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 16dbe00..e313cbb 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1228,6 +1229,31 @@ typedef int (*eth_udp_tunnel_del_t)(struct rte_eth_dev *dev,
 				    struct rte_eth_udp_tunnel *tunnel_udp);
 /**< @internal Delete tunneling UDP info */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
+typedef int (*eth_get_ringparam_t)(struct rte_eth_dev *dev,
+				struct rte_dev_ring_info *info);
+/**< @internal Retrieve device ring descriptor  */
+
+typedef int (*eth_set_ringparam_t)(struct rte_eth_dev *dev,
+				struct rte_dev_ring_info *info);
+/**< @internal Set device ring descriptor  */
 
 #ifdef RTE_NIC_BYPASS
 
@@ -1368,6 +1394,21 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
+	eth_get_ringparam_t get_ringparam;
+	/**< Get descriptor ring parameters */
+	eth_set_ringparam_t set_ringparam;
+	/**< Set descriptor ring parameters */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -2982,6 +3023,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3611,6 +3666,94 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Retrieve device descriptor ring information
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes device ring descriptor usage information.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index a2d25a6..9df15b2 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,13 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
+	rte_eth_dev_get_ringparam;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v5 2/4] ixgbe: add ops to support ethtool ops
  2015-06-11 21:43 ` [dpdk-dev] [PATCH v5 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-11 21:43   ` Liang-Min Larry Wang
  2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 3/4] igb: " Liang-Min Larry Wang
  2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-11 21:43 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_pauseparam
- get_ringparam
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 203 ++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_regs.h   | 357 +++++++++++++++++++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.c   |  16 ++
 drivers/net/ixgbe/ixgbe_rxtx.h   |   1 +
 4 files changed, 577 insertions(+)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 0d9f9b2..55a05c0 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -179,6 +183,7 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -223,6 +228,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+		struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -257,6 +264,17 @@ static int ixgbe_dev_filter_ctrl(struct rte_eth_dev *dev,
 		     void *arg);
 static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 
+/* Ethtool op support */
+static int ixgbe_get_ringparam(struct rte_eth_dev *dev, struct rte_dev_ring_info *param);
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
+
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
  */
@@ -355,6 +373,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -381,6 +400,12 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.rss_hash_update      = ixgbe_dev_rss_hash_update,
 	.rss_hash_conf_get    = ixgbe_dev_rss_hash_conf_get,
 	.filter_ctrl          = ixgbe_dev_filter_ctrl,
+	.get_ringparam        = ixgbe_get_ringparam,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -406,6 +431,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.tx_queue_release     = ixgbe_dev_tx_queue_release,
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2883,6 +2911,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3713,6 +3749,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4439,6 +4483,165 @@ ixgbe_dev_filter_ctrl(struct rte_eth_dev *dev,
 	return ret;
 }
 
+static int
+ixgbe_get_ringparam(struct rte_eth_dev *dev,
+	struct rte_dev_ring_info *ring_param)
+{
+	/* Pending rx/tx descriptors in queue #0 */
+	struct ixgbe_tx_queue *txq = dev->data->tx_queues[0];
+	struct ixgbe_rx_queue *rxq = dev->data->rx_queues[0];
+
+	ring_param->rx_pending = rxq->nb_rx_desc - ixgbe_dev_rx_queue_count(dev, 0);
+	ring_param->tx_pending = txq->nb_tx_desc - ixgbe_dev_tx_queue_count(dev, 0);
+	/* The ixgbe descriptor ring is multiple of 8 descriptor, i.e. module by 8*16 bytes */
+	ring_param->rx_max_pending = IXGBE_MAX_RING_DESC;
+	ring_param->tx_max_pending = IXGBE_MAX_RING_DESC;
+
+	return 0;
+}
+
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+	reg_info **reg_set =
+		(hw->mac.type == ixgbe_mac_82598EB)?ixgbe_regs_mac_82598EB:ixgbe_regs_others;
+
+	reg_group = reg_set[g_ind++];
+	while(reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = reg_set[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = ixgbevf_regs[g_ind++];
+	while(reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = ixgbevf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+	reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB)?
+					ixgbe_regs_mac_82598EB:ixgbe_regs_others;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = reg_set[g_ind++];
+		while(reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = reg_set[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = ixgbevf_regs[g_ind++];
+		while(reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = ixgbevf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size*2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+		((first+leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+		((first+leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..7025ed8
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,357 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+typedef struct _reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_nvm [] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_interrupt [] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_interrupt [] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_rx [] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_tx [] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_tx [] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_wakeup [] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_dcb [] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_mac [] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_diagnostic [] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static reg_info* ixgbe_regs_others[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+                                ixgbe_regs_fctl_others, ixgbe_regs_rxdma, ixgbe_regs_rx,
+                                ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
+                                ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
+
+static reg_info* ixgbe_regs_mac_82598EB[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+                                ixgbe_regs_fctl_mac_82598EB, ixgbe_regs_rxdma, ixgbe_regs_rx,
+                                ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
+                                ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
+
+/* VF registers */
+static reg_info* ixgbevf_regs[] = { ixgbevf_regs_general, ixgbevf_regs_interrupt,
+                                ixgbevf_regs_rxdma, ixgbevf_regs_tx, NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for(i = 0; i < reg->count; i++) {
+		reg_buf[i] = IXGBE_READ_REG(hw, reg->base_addr + i*reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += ixgbe_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif // _IXGBE_REGS_H_
diff --git a/drivers/net/ixgbe/ixgbe_rxtx.c b/drivers/net/ixgbe/ixgbe_rxtx.c
index 4f9ab22..762d303 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx.c
+++ b/drivers/net/ixgbe/ixgbe_rxtx.c
@@ -2448,6 +2448,22 @@ ixgbe_dev_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)
 	return desc;
 }
 
+uint32_t
+ixgbe_dev_tx_queue_count(struct rte_eth_dev *dev, uint16_t tx_queue_id)
+{
+	struct ixgbe_tx_queue *txq;
+
+	if (tx_queue_id >= dev->data->nb_tx_queues) {
+		PMD_TX_LOG(ERR, "Invalid TX queue id=%d", tx_queue_id);
+		return 0;
+	}
+
+	txq = dev->data->tx_queues[tx_queue_id];
+	if (txq->tx_ring[txq->tx_next_dd].wb.status & IXGBE_ADVTXD_STAT_DD)
+		return (txq->nb_tx_free + txq->tx_rs_thresh);
+	return txq->nb_tx_free;
+}
+
 int
 ixgbe_dev_rx_descriptor_done(void *rx_queue, uint16_t offset)
 {
diff --git a/drivers/net/ixgbe/ixgbe_rxtx.h b/drivers/net/ixgbe/ixgbe_rxtx.h
index af36438..3b3163c 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx.h
+++ b/drivers/net/ixgbe/ixgbe_rxtx.h
@@ -282,6 +282,7 @@ uint16_t ixgbe_recv_scattered_pkts_vec(void *rx_queue,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 int ixgbe_rx_vec_dev_conf_condition_check(struct rte_eth_dev *dev);
 int ixgbe_rxq_vec_setup(struct ixgbe_rx_queue *rxq);
+uint32_t ixgbe_dev_tx_queue_count(struct rte_eth_dev *dev, uint16_t tx_queue_id);
 
 #ifdef RTE_IXGBE_INC_VECTOR
 
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v5 3/4] igb: add ops to support ethtool ops
  2015-06-11 21:43 ` [dpdk-dev] [PATCH v5 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-06-11 21:43   ` Liang-Min Larry Wang
  2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-11 21:43 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_pauseparam
- set_pauseparam
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 186 +++++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 217 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 403 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index e4b370d..9fc3f00 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -129,6 +130,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -142,6 +145,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -193,6 +202,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -264,11 +281,17 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
 	.rss_hash_conf_get    = eth_igb_rss_hash_conf_get,
 	.filter_ctrl          = eth_igb_filter_ctrl,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -289,6 +312,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.rx_queue_release     = eth_igb_rx_queue_release,
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2107,6 +2133,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+	                     struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2341,6 +2375,16 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.rar_set(hw, (void *)addr, 0); /* index is not used by rar_set() */
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3642,6 +3686,148 @@ eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 	return ret;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = igb_regs[g_ind++];
+	while(reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igb_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = igbvf_regs[g_ind++];
+	while(reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igbvf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igb_regs[g_ind++];
+		while(reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = igb_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igbvf_regs[g_ind++];
+		while(reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = igbvf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size*2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) || ((first+leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) || ((first+leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..14602e8
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,217 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+typedef struct _reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_nvm [] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_interrupt [] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_rx [] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_tx [] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_wakeup [] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_mac [] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info* igb_regs[] = { igb_regs_general, igb_regs_nvm,
+                                igb_regs_interrupt, igb_regs_fctl,
+                                igb_regs_rxdma, igb_regs_rx,
+                                igb_regs_tx, igb_regs_wakeup, igb_regs_mac,
+                                NULL};
+
+static reg_info* igbvf_regs[] = { igb_regs_general,
+	/*
+	 * FIXME: reading igb_regs_interrupt results side-effect which doesn't work with VFIO
+	 *
+	 * igb_regs_interrupt,
+	 */
+                                  igb_regs_rxdma, igb_regs_tx, NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for(i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw, reg->base_addr + i*reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += igb_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif // _IGB_REGS_H_
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v5 4/4] examples: new example: l2fwd-ethtool
  2015-06-11 21:43 ` [dpdk-dev] [PATCH v5 0/4] User-space Ethtool Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 3/4] igb: " Liang-Min Larry Wang
@ 2015-06-11 21:43   ` Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-11 21:43 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1052 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  821 +++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  153 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  326 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  412 +++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  427 +++++++++
 10 files changed, 3414 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..a753c33
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..3d31cb1
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -lrte_ethtool
+LDFLAGS += -L$(SRCDIR)/../lib/build
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..04c7ec1
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1052 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id)            ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id)     ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask = 0;
+
+/* virtio setup enable */
+static int virtio_setup = 0;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+    return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done (void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ------------------------------"
+			   "\nPackets sent: %24"PRIu64
+			   "\nPackets received: %20"PRIu64
+			   "\nPackets dropped: %21"PRIu64,
+			   portid,
+			   port_statistics[portid].tx,
+			   port_statistics[portid].rx,
+			   port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ==============================="
+		   "\nTotal packets sent: %18"PRIu64
+		   "\nTotal packets received: %14"PRIu64
+		   "\nTotal packets dropped: %15"PRIu64,
+		   total_packets_tx,
+		   total_packets_rx,
+		   total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid =0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+    if(virtio_setup) {
+        while (is_ipc_done() == 0) usleep(50);
+    }
+	while (1) {
+
+		cur_tsc = rte_rdtsc();
+
+		/*
+		 * TX burst queue drain
+		 */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >= (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id == rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+	       "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+	       "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+           "  -V : setting rx/tx mode to enable virtio\n"
+		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
+	       prgname);
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+            virtio_setup = l2fwd_parse_virtio_setup(optarg);
+            if (virtio_setup) {
+			    port_conf.rxmode.hw_vlan_strip = 0;
+			    port_conf.rxmode.hw_vlan_extend = 0;
+            }
+            break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status)
+					printf("Port %d Link Up - speed %u "
+						"Mbps - %s\n", (uint8_t)portid,
+						(unsigned)link.link_speed,
+				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+					("full-duplex") : ("half-duplex\n"));
+				else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+inline static char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+    static char addr_string[MAC_STR_SIZE];
+
+    snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+        mac_addr[0], mac_addr[1], mac_addr[2],
+        mac_addr[3], mac_addr[4], mac_addr[5]);
+    return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+    uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for(port_id = 0; port_id < num_of_ports; port_id++){
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of rte_eth_promiscuous_enable */
+		/* to test rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data = (struct rte_eth_dev_data*)dev->data;
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is %s", port_id, mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))) {
+				if (rte_ethtool_net_set_mac_addr(port_id, (void *)new_mac_addr) == 0) {
+					printf(", and it's being re-assigned to %s\n", mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1, &param2_size, param2);
+		if (req_type != (req_t)ipc_begin) {
+			proc_invalid(req_id);
+		} else {
+			break;
+		}
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1, &param2_size, param2);
+		port_id = param1[0];
+
+		switch((req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id, first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0) {
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			}
+			if (reg_count) {
+				status = proc_ethtool_get_regs(port_id, req_id, first_param, reply1);
+			}
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0) {
+				eeprom_size = rte_ethtool_get_eeprom_len(port_id);
+			}
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id, first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id, first_param, param2);
+			break;
+
+		case get_ringparam:
+			{
+				struct ethtool_ringparam *ring_param = (void *)reply1;
+				status = proc_ethtool_get_ringparam(port_id, req_id, ring_param);
+
+				if (status != 0) {
+					printf("get_ringparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case set_ringparam:
+			{
+				struct ethtool_ringparam *ring_param = (void *)reply1;
+				status = proc_ethtool_set_ringparam(port_id, req_id, ring_param);
+
+				if (status != 0) {
+					printf("set_ringparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param = (void *)reply1;
+				status = proc_ethtool_get_pauseparam(port_id, req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param = (void *)reply1;
+				status = proc_ethtool_set_pauseparam(port_id, req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id, req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id, req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id, req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id, req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id, req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id, req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id, req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id, req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type: %d\n",req_type);
+			break;
+		}
+		if ( status < 0)
+			printf("Service request with type (=%d) failed or not supported!!!\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+    init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		}
+		else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+		       lcore_queue_conf[rx_lcore_id].n_rx_port ==
+		       l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n", (unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					     rte_eth_dev_socket_id(portid),
+					     NULL,
+					     l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+    cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+			"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..e57b7c3
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,821 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE								6
+#define quad_aligned_size(x)						(x & 0x7)?((x+7)&0x7): x
+
+#define size16(data_type)							(uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED			-1
+#define NETDEV_INVALID				-1
+#define NETDEV_STATUS(data_size)	(GOOD_RETURN(data_size)?0:NETDEV_INVALID)
+#define UNUSED(x)					(void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id = 0;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY );
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close (fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY );
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close (fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	// block on read if reply is not available
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id) {
+		return -1;
+	}
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return leng;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs), param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size)){
+		return link_status;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return leng;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_ringparam(uint8_t port_id, struct ethtool_ringparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_ringparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return valid;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t* param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY );
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else {
+			*param2_size = 0;
+		}
+	}
+	close (fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(struct ethtool_drvinfo);
+	}
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	if ((reg_len = rte_ethtool_get_regs_len(port_id)) == 0) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(int);
+	}
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	}
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	if ((eeprom_leng = rte_ethtool_get_eeprom_len(port_id)) == 0) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(int);
+	}
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_ringparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_ringparam(port_id,
+		(struct ethtool_ringparam *)reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_ringparam));
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_ringparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_ringparam(port_id,
+		(struct ethtool_ringparam *)set_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_ringparam));
+	}
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	}
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = MAC_ADDR_SIZE;
+	}
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(struct rte_eth_stats);
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..c854811
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,153 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE			"/tmp/nic_request"
+#define REP_PIPE			"/tmp/nic_reply"
+#define PAGE_SIZE			(4*1024)
+#define STACK_SIZE			(4*PAGE_SIZE)
+#define MAXI_DATA			(1024 *6)
+#define MAXI_PARA			1024
+#define STATUS_MASK			0x8000
+#define MULTIPLE_DATA_MASK	0x4000
+#define MAXI_REQ_TYPE		16
+#define FIRST_DATA_OFFSET	8
+#define to_ptr(new_ptr_type, data, offset)			(new_ptr_type)(&((unsigned char *)(void*)data)[offset])
+#define u8ptr(x)									(uint8_t*)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT						(sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye)	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size)	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes)		(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes)				(data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size)			(data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)						(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)					((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)						((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)				(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)				((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)						(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)				((dword_ptr[0] >> 16)& 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)				(dword_ptr[1])
+
+#define BAD_RETURN(data_size)					(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)					((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)				(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)					(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)						((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)					(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data,ptr_type)	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+typedef enum _REQ_TYPE {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_ringparam,
+	set_ringparam,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+} req_t;
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif // _SHARED_FIFO_H_
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..b3b8c83
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..83c5a62
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,326 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	if ((n = rte_eth_dev_reg_length(port_id)) > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	if ((n = rte_eth_dev_eeprom_length(port_id)) > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	if ((status = rte_eth_dev_reg_info(port_id, &reg_info))
+		!= 0)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	if ((status = rte_eth_dev_get_eeprom(port_id, &eeprom_info)) != 0)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	if ((status = rte_eth_dev_set_eeprom(port_id, &eeprom_info)) != 0)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_ringparam(uint8_t port_id,
+	struct ethtool_ringparam *ring_param)
+{
+	struct rte_dev_ring_info ring_info;
+	int status;
+
+	if ((status = rte_eth_dev_get_ringparam(port_id, &ring_info)) != 0)
+		return status;
+
+	ring_param->rx_pending = ring_info.rx_pending;
+	ring_param->tx_pending = ring_info.tx_pending;
+	ring_param->rx_max_pending = ring_info.rx_max_pending;
+	ring_param->tx_max_pending = ring_info.tx_max_pending;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_ringparam(uint8_t port_id __rte_unused,
+	struct ethtool_ringparam *ring_param __rte_unused)
+{
+	return -ENOTSUP;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	if ((status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf)) != 0)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch(fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	if ((status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf)) != 0)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	if ((status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf)) != 0)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..10deaa1
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,412 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_ringparam:       ethtool_ops::get_ringparam
+ * rte_ethtool_set_ringparam:       ethtool_ops::set_ringparam
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom, void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom, void *words);
+
+/**
+ * Retrieve the Ethernet device ring configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_ringparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_ringparam(uint8_t port_id, struct ethtool_ringparam *ring_param);
+
+/**
+ * Setting the Ethernet device ring configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_ringparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_ringparam(uint8_t port_id, struct ethtool_ringparam *ring_param);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..d49ca98
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..4ca6ee1
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,427 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES/(after_ts - before_ts)
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES*8/(after_ts - before_ts)
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES*64*8/(after_ts - before_ts)
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
+}
+
+static uint32_t port_mask = 0;
+static uint32_t vf_port_mask = 0;
+static uint8_t num_of_ports = 0;
+static int keep_traffic = 1;
+
+inline static int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1<< port_id)) > 0;
+}
+
+inline static int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports	= reply_data[0];
+	port_mask		= reply_data2[0];
+	vf_port_mask	= reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0) {
+				printf("setrlimit returned result = %d\n", result);
+			} else {
+				printf("setrlimit succeed!!!\n");
+			}
+		} else {
+			printf("default stack size is 0x%x\n", (int)(rl.rlim_cur));
+		}
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id)) {
+		port_id = rand() & 0x1F;
+	}
+	return port_id;
+}
+
+inline static char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_ringparam ring_param;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1) {
+		keep_traffic = atoi(argv[1]);
+	}
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0) {
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+	}
+
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0) {
+				netdev_net_set_rx_mode(port_id);
+			} else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id ++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port #%d!!!\n", port_id);
+			} else {
+				printf("\nPort #%d mac addr is %s \n", port_id,
+					mac_addr_str(mac_addr));
+			}
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s fw_version: %s bus_info=%s\n"
+					"reg-size(bytes)=%d eeprom-size=%d\n", drvinfo.driver,
+					drvinfo.version, drvinfo.fw_version, drvinfo.bus_info,
+					drvinfo.regdump_len, drvinfo.eedump_len);
+			}
+
+			if ((count =netdev_ethtool_get_regs_len(port_id)) <= 0) {
+				printf("There are no registers available from device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers for dump\n", count);
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF, sizeof(struct ethtool_regs));
+				if ((count =netdev_ethtool_get_regs(port_id, &regs, reply_data))) {
+					printf("failed to run ethtool_get_regs from port #%d (error-code=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x version=0x%x\n",
+						int_ptr[0], int_ptr[10], regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			if (!is_vf_port(port_id)) {
+				if((count = netdev_ethtool_get_eeprom_len(0)) == 0)
+					printf("fail to retrieve eeprom count from port #%d\n", port_id);
+				else {
+
+					printf("eeprom size is %d bytes\n", count);
+					eeprom.offset = 20;
+					eeprom.len = 80;
+					eeprom.magic = 0;
+					if (netdev_ethtool_get_eeprom(port_id, &eeprom, reply_data)) {
+						printf("Fail to read eeprom from port #%d\n", port_id);
+					} else {
+						int i;
+						uint16_t *word = (uint16_t *)((void*)reply_data);
+
+						printf("eeprom-magic: %x; read-back eeprom data ...\n", eeprom.magic);
+						for(i = 0; i < (int)(eeprom.len >> 1); i++) {
+							if (((i+1) %16) == 0)
+								printf("\n");
+							printf("%4x ", word[i]);
+						}
+						printf("\n");
+					}
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id ++) {
+		if (netdev_net_get_mac_addr(port_id, to_mac_type(mac_addr))) {
+			printf("Fail to get mac addr from port #%d!!!\n", port_id);
+		} else {
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+		}
+
+		if (!netdev_net_validate_addr(port_id, to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr, MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n", mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id, to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id, to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign, device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n", port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n", port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets, last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets, last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes, last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes, last_ts, ts));
+
+		if (!is_vf_port(port_id)
+			|| (netdev_ethtool_get_regs_len(port_id) == 0)
+			) {
+			printf("Getting ringparam from a %s\n", is_vf_port(port_id)?"VF":"PF");
+
+			if (netdev_ethtool_get_ringparam(port_id, &ring_param)) {
+				printf("Fail to retrieve descriptor ring info!!!\n");
+			} else {
+				printf("Rx/Tx descriptor ring info for queue 0!!!\n");
+				printf("Tx-max=%d Tx-pending=%d Rx-max=%d Rx-pend=%d\n",
+					ring_param.tx_max_pending, ring_param.tx_pending,
+					ring_param.rx_max_pending, ring_param.rx_pending);
+			}
+		}
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		for(port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for(port_id = 0; port_id < num_of_ports; port_id++) {
+			if (!is_vf_port(port_id)) {
+				link_up = netdev_ethtool_get_link(port_id);
+				if (!link_up) {
+					eeprom.offset = 20;
+					eeprom.len = 80;
+					if (netdev_ethtool_get_eeprom(port_id, &eeprom,
+						reply_data)) {
+						printf("failed to read eeprom break from post-run"
+							" testing!!!\n");
+						break;
+					}
+					if (netdev_ethtool_set_eeprom(port_id, &eeprom,
+						reply_data)) {
+						printf("Fail to write read-back data to eeprom!!!\n");
+						break;
+					}
+					/* checking mtu setting */
+					if (netdev_net_change_mtu(port_id, mtu))
+						printf("failed to set mtu to %d\n", mtu);
+
+					/* add/remove vlan to vid */
+					if (netdev_net_vlan_rx_add_vid(port_id, 0) == 0) {
+						if (netdev_net_vlan_rx_kill_vid(port_id, 0)) {
+							printf("fail to kill vid 0 vlan\n");
+							break;
+						}
+					} else {
+						printf("fail to add vid 0 vlan\n");
+						break;
+					}
+
+					/* testing pause parameter get/set functions */
+					if (netdev_ethtool_get_pauseparam(port_id, &pause_param)) {
+						printf("fail to get pause param\n");
+						break;
+					}
+					printf("pause setup: autoneg: %d tx_pause: "
+						"%d rx_pause: %d\n",
+						pause_param.autoneg, pause_param.tx_pause,
+						pause_param.rx_pause);
+
+					if (netdev_ethtool_set_pauseparam(port_id, &pause_param)) {
+						printf("fail to set pause param\n");
+						break;
+					}
+
+				}
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0);
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-11 13:07         ` Ananyev, Konstantin
@ 2015-06-11 21:51           ` Wang, Liang-min
  2015-06-12 12:30             ` Ananyev, Konstantin
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-11 21:51 UTC (permalink / raw)
  To: Ananyev, Konstantin, dev



> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Thursday, June 11, 2015 9:07 AM
> To: Wang, Liang-min; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> device info
> 
> 
> 
> > -----Original Message-----
> > From: Wang, Liang-min
> > Sent: Thursday, June 11, 2015 1:58 PM
> > To: Ananyev, Konstantin; dev@dpdk.org
> > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > access device info
> >
> > Hi Konstantin,
> >
> > > -----Original Message-----
> > > From: Ananyev, Konstantin
> > > Sent: Thursday, June 11, 2015 8:26 AM
> > > To: Wang, Liang-min; dev@dpdk.org
> > > Cc: Wang, Liang-min
> > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > access device info
> > >
> > > Hi Larry,
> > >
> > > > -----Original Message-----
> > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Liang-Min
> > > > Larry Wang
> > > > Sent: Wednesday, June 10, 2015 4:10 PM
> > > > To: dev@dpdk.org
> > > > Cc: Wang, Liang-min
> > > > Subject: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > access device info
> > > >
> > > > add new apis:
> > > > - rte_eth_dev_default_mac_addr_set
> > > > - rte_eth_dev_reg_leng
> > > > - rte_eth_dev_reg_info
> > > > - rte_eth_dev_eeprom_leng
> > > > - rte_eth_dev_get_eeprom
> > > > - rte_eth_dev_set_eeprom
> > > > - rte_eth_dev_get_ringparam
> > > > - rte_eth_dev_set_ringparam
> > > >
> > > > to enable reading device parameters (mac-addr, register, eeprom,
> > > > ring) based upon ethtool alike data parameter specification.
> > > >
> > > > Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> > > > ---
> > > >  lib/librte_ether/Makefile              |   1 +
> > > >  lib/librte_ether/rte_eth_dev_info.h    |  80 +++++++++++++++++
> > > >  lib/librte_ether/rte_ethdev.c          | 159
> > > +++++++++++++++++++++++++++++++++
> > > >  lib/librte_ether/rte_ethdev.h          | 158
> > > ++++++++++++++++++++++++++++++++
> > > >  lib/librte_ether/rte_ether_version.map |   8 ++
> > > >  5 files changed, 406 insertions(+)  create mode 100644
> > > > lib/librte_ether/rte_eth_dev_info.h
> > > >
> > > > diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
> > > > index c0e5768..05209e9 100644
> > > > --- a/lib/librte_ether/Makefile
> > > > +++ b/lib/librte_ether/Makefile
> > > > @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c  SYMLINK-y-include +=
> > > > rte_ether.h  SYMLINK-y-include += rte_ethdev.h  SYMLINK-y-include
> > > > += rte_eth_ctrl.h
> > > > +SYMLINK-y-include += rte_eth_dev_info.h
> > > >
> > > >  # this lib depends upon:
> > > >  DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring
> > > > lib/librte_mbuf diff --git a/lib/librte_ether/rte_eth_dev_info.h
> > > > b/lib/librte_ether/rte_eth_dev_info.h
> > > > new file mode 100644
> > > > index 0000000..002c4b5
> > > > --- /dev/null
> > > > +++ b/lib/librte_ether/rte_eth_dev_info.h
> > > > @@ -0,0 +1,80 @@
> > > > +/*-
> > > > + *   BSD LICENSE
> > > > + *
> > > > + *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> > > > + *   All rights reserved.
> > > > + *
> > > > + *   Redistribution and use in source and binary forms, with or without
> > > > + *   modification, are permitted provided that the following conditions
> > > > + *   are met:
> > > > + *
> > > > + *     * Redistributions of source code must retain the above copyright
> > > > + *       notice, this list of conditions and the following disclaimer.
> > > > + *     * Redistributions in binary form must reproduce the above
> copyright
> > > > + *       notice, this list of conditions and the following disclaimer in
> > > > + *       the documentation and/or other materials provided with the
> > > > + *       distribution.
> > > > + *     * Neither the name of Intel Corporation nor the names of its
> > > > + *       contributors may be used to endorse or promote products
> derived
> > > > + *       from this software without specific prior written permission.
> > > > + *
> > > > + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > > CONTRIBUTORS
> > > > + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
> BUT
> > > NOT
> > > > + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> > > FITNESS FOR
> > > > + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> > > COPYRIGHT
> > > > + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> > > INCIDENTAL,
> > > > + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> (INCLUDING,
> > > BUT NOT
> > > > + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> > > LOSS OF USE,
> > > > + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED
> > > AND ON ANY
> > > > + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> OR
> > > TORT
> > > > + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> OUT
> > > OF THE USE
> > > > + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > > DAMAGE.
> > > > + */
> > > > +
> > > > +#ifndef _RTE_ETH_DEV_INFO_H_
> > > > +#define _RTE_ETH_DEV_INFO_H_
> > > > +
> > > > +
> > > > +/*
> > > > + * Placeholder for accessing device registers  */ struct
> > > > +rte_dev_reg_info {
> > > > +	void *buf; /**< Buffer for register */
> > > > +	uint32_t offset; /**< Offset for 1st register to fetch */
> > > > +	uint32_t leng; /**< Number of registers to fetch */
> > > > +	uint32_t version; /**< Device version */ };
> > > > +
> > > > +/*
> > > > + * Placeholder for accessing device eeprom  */ struct
> > > > +rte_dev_eeprom_info {
> > > > +	void *buf; /**< Buffer for eeprom */
> > > > +	uint32_t offset; /**< Offset for 1st eeprom location to access */
> > > > +	uint32_t leng; /**< Length of eeprom region to access */
> > > > +	uint32_t magic; /**< Device ID */ };
> > > > +
> > > > +/*
> > > > + * Placeholder for accessing device ring parameters  */ struct
> > > > +rte_dev_ring_info {
> > > > +	uint32_t rx_pending; /**< Number of outstanding Rx ring */
> > > > +	uint32_t tx_pending; /**< Number of outstanding Tx ring */
> > > > +	uint32_t rx_max_pending; /**< Maximum number of outstanding Rx
> > > ring */
> > > > +	uint32_t tx_max_pending; /**< Maximum number of outstanding Tx
> > > ring
> > > > +*/ };
> > > > +
> > > > +/*
> > > > + * A data structure captures information as defined in struct
> > > > +ifla_vf_info
> > > > + * for user-space api
> > > > + */
> > > > +struct rte_dev_vf_info {
> > > > +	uint32_t vf;
> > > > +	uint8_t mac[ETHER_ADDR_LEN];
> > > > +	uint32_t vlan;
> > > > +	uint32_t tx_rate;
> > > > +	uint32_t spoofchk;
> > > > +};
> > >
> > >
> > > Wonder what that structure is for?
> > > I can't see it used in any function below?
> > >
> >
> > Good catch, this is designed for other ethtool ops that I did not include in
> this release, I will remove this from next fix.
> >
> > > > +
> > > > +#endif /* _RTE_ETH_DEV_INFO_H_ */
> > > > diff --git a/lib/librte_ether/rte_ethdev.c
> > > > b/lib/librte_ether/rte_ethdev.c index 5a94654..186e85c 100644
> > > > --- a/lib/librte_ether/rte_ethdev.c
> > > > +++ b/lib/librte_ether/rte_ethdev.c
> > > > @@ -2751,6 +2751,32 @@ rte_eth_dev_mac_addr_remove(uint8_t
> > > port_id,
> > > > struct ether_addr *addr)  }
> > > >
> > > >  int
> > > > +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct
> > > > +ether_addr
> > > > +*addr) {
> > > > +	struct rte_eth_dev *dev;
> > > > +	const int index = 0;
> > > > +	const uint32_t pool = 0;
> > > > +
> > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	dev = &rte_eth_devices[port_id];
> > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_remove, -
> > > ENOTSUP);
> > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -
> > > ENOTSUP);
> > > > +
> > > > +	/* Update NIC default MAC address*/
> > > > +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> > > > +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> > > > +
> > > > +	/* Update default address in NIC data structure */
> > > > +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +int
> > > >  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
> > > >  				uint16_t rx_mode, uint8_t on)  { @@ -3627,3
> +3653,136 @@
> > > > rte_eth_remove_tx_callback(uint8_t port_id,
> > > uint16_t queue_id,
> > > >  	/* Callback wasn't found. */
> > > >  	return -EINVAL;
> > > >  }
> > > > +
> > > > +int
> > > > +rte_eth_dev_reg_leng(uint8_t port_id) {
> > > > +	struct rte_eth_dev *dev;
> > > > +
> > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -
> > > ENOTSUP);
> > > > +	return (*dev->dev_ops->get_reg_length)(dev);
> > > > +}
> > > > +
> > > > +int
> > > > +rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info
> > > > +*info) {
> > > > +	struct rte_eth_dev *dev;
> > > > +
> > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
> > > > +	return (*dev->dev_ops->get_reg)(dev, info); }
> > >
> > > Seems that *get_reg* stuff, will be really good addition for DPDK
> > > debugging abilities.
> > > Though, I'd suggest we change it a bit to make more generic and flexible:
> > >
> > > Introduce rte_eth_reg_read/rte_eth_reg_write(),
> > > or probably even better rte_pcidev_reg_read /rte_pcidev_reg_write at
> EAL.
> > > Something similar to what port_pci_reg_read/port_pci_reg_write() are
> > > doing now at testpmd.h.
> > >
> > > struct rte_pcidev_reg_info {
> > >    const char *name;
> > >    uint32_t endianes, bar, offset, size, count; };
> > >
> > > int rte_pcidev_reg_read(const struct rte_pci_device *, const struct
> > > rte_pcidev_reg_info *, uint64_t *reg_val);
> > >
> > > Then:
> > > int rte_eth_dev_get_reg_info(port_id, const struct
> > > rte_pcidev_reg_info **info);
> > >
> > > So each device would store in info a pointer to an array of it's
> > > register descriptions (finished by zero elem?).
> > >
> > > Then your ethtool (or any other upper layer) can do the following to
> > > read all device regs:
> > >
> >
> > The proposed reg info structure allows future improvement to support
> individual register read/write.
> > Also, because each NIC device has a very distinguish register definition.
> > So, the plan is to have more comprehensive interface to support query
> > operation (for example, register name) before introduce individual/group
> register access.
> > Points taken, the support will be in future release.
> 
> Sorry, didn't get you.
> So you are ok to make these changes in next patch version?
> 
I would like to get a consensus from dpdk community on how to provide register information.
Currently, it's designed for debug dumping. The register information is very hardware dependent.
Need to consider current supported NIC device and future devices for DPDK, so we won't make it a bulky interface.
> >
> > > const struct rte_eth_dev_reg_info *reg_info; struct rte_eth_dev_info
> > > dev_info;
> > >
> > > rte_eth_dev_info_get(pid, &dev_info);
> > > rte_eth_dev_get_reg_info(port_id, &reg_info);
> > >
> > > for (i = 0; reg_info[i].name != NULL; i++) {
> > >    ...
> > >    rte_pcidev_read_reg(dev_info. pci_dev, reg_info[i], &v);
> > >   ..
> > > }
> > >
> > > > +
> > > > +int
> > > > +rte_eth_dev_eeprom_leng(uint8_t port_id) {
> > > > +	struct rte_eth_dev *dev;
> > > > +
> > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -
> > > ENOTSUP);
> > > > +	return (*dev->dev_ops->get_eeprom_length)(dev);
> > > > +}
> > > > +
> > > > +int
> > > > +rte_eth_dev_get_eeprom(uint8_t port_id, struct
> > > > +rte_dev_eeprom_info
> > > > +*info) {
> > > > +	struct rte_eth_dev *dev;
> > > > +
> > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -
> > > ENOTSUP);
> > > > +	return (*dev->dev_ops->get_eeprom)(dev, info); }
> > > > +
> > > > +int
> > > > +rte_eth_dev_set_eeprom(uint8_t port_id, struct
> > > > +rte_dev_eeprom_info
> > > > +*info) {
> > > > +	struct rte_eth_dev *dev;
> > > > +
> > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -
> > > ENOTSUP);
> > > > +	return (*dev->dev_ops->set_eeprom)(dev, info); }
> > > > +
> > > > +int
> > > > +rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > > +rte_dev_ring_info
> > > > +*info) {
> > > > +	struct rte_eth_dev *dev;
> > > > +
> > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> > > ENOTSUP);
> > > > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> > >
> > > I think it will be a useful addition to the ethdev API  to have an
> > > ability to retrieve current RX/TX queue parameters.
> > > Though again, it need to be more generic, so it could be useful for
> > > non- ethtool upper layer too.
> > > So I suggest to modify it a bit.
> > > Something like that:
> > >
> > > struct rte_eth_tx_queue_info {
> > >     struct rte_eth_txconf txconf;
> > >     uint32_t nb_tx_desc;
> > >     uint32_t nb_max_tx_desc; /*max allowable TXDs for that queue */
> > >     uint32_t nb_tx_free;            /* number of free TXDs at the moment of
> call.
> > > */
> > >     /* other tx queue data. */
> > > };
> > >
> > > int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> > > rte_eth_tx_queue_info *qinfo)
> > >
> > > Then, your upper layer ethtool wrapper, can implement yours
> > > ethtool_get_ringparam() by:
> > >
> > >  ...
> > >  struct rte_eth_tx_queue_info qinfo;
> > > rte_ethdev_get_tx_queue_info(port, 0, &qinfo);
> > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > rte_eth_rx_queue_count(port, 0);
> > >
> > > Or probably even:
> > > ring_param->tx_pending = qinfo.nb_tx_desc - qinfo.nb_tx_free;
> > >
> > > Same for RX.
> > >
> > For now, this descriptor ring information is used by the ethtool op.
> > To make this interface simple, i.e. caller doesn't need to access other
> queue information.
> 
> I just repeat what I said to you in off-line conversation:
> ethdev API is not equal ethtool API.
> It is ok to add  a new function/structure to ethdev if it really needed, but we
> should do mechanical one to one copy.
> It is much better to add  a function/structure that would be more generic,
> and suit other users, not only ethtool.
> There is no point to have dozen functions in rte_ethdev API providing similar
> information.
> BTW, I don't see how API I proposed is much more  complex, then yours one.
The ring parameter is a run-time information which is different than data structure described in this discussion.
It's the desire of this patch to separate each data structure to avoid cross dependency.

> 
> Konstantin
> 
> 
> > The plan it so keep this information as it is.
> > For the expansion, the ethdev can invoke the same dev op to add this
> information.
> > > > +
> > > > +int
> > > > +rte_eth_dev_set_ringparam(uint8_t port_id, struct
> > > > +rte_dev_ring_info
> > > > +*info) {
> > > > +	struct rte_eth_dev *dev;
> > > > +
> > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > +		return -ENODEV;
> > > > +	}
> > > > +
> > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_ringparam, -
> > > ENOTSUP);
> > > > +	return (*dev->dev_ops->set_ringparam)(dev, info); }
> > >
> > >
> > > I am a bit confused, what particular value of rte_dev_ring_info will
> > > be allowed to change?
> > > You can't change number of RXD/TXD at runtime.
> > > You have to stop the device first, and then reconfigure particular
> queue(s).
> > > Again, you can't reset RXF/TXD without stopping RX/TX first.
> > > So what that function is supposed to do?
> > > As I can see currently, none of the PMD in your patch support it.
> > >
> >
> > Exactly, setting RXD/TXD will require some change on kernel (RX/TX burst)
> function.
> > As you already observe that there is no dev_op registered for set_ring.
> > The API is created as a placeholder for future implementation.
> > There are a couple of idea thrown around (such as mono-
> increase/decrease to avoid buffer overrun).
> > Any suggestion is welcome.
> >
> > > Konstantin
> > >
> > > > diff --git a/lib/librte_ether/rte_ethdev.h
> > > > b/lib/librte_ether/rte_ethdev.h index 16dbe00..8f99f0d 100644
> > > > --- a/lib/librte_ether/rte_ethdev.h
> > > > +++ b/lib/librte_ether/rte_ethdev.h
> > > > @@ -182,6 +182,7 @@ extern "C" {
> > > >  #include <rte_devargs.h>
> > > >  #include "rte_ether.h"
> > > >  #include "rte_eth_ctrl.h"
> > > > +#include "rte_eth_dev_info.h"
> > > >
> > > >  struct rte_mbuf;
> > > >
> > > > @@ -1228,6 +1229,31 @@ typedef int (*eth_udp_tunnel_del_t)(struct
> > > rte_eth_dev *dev,
> > > >  				    struct rte_eth_udp_tunnel *tunnel_udp);
> > > /**< @internal
> > > > Delete tunneling UDP info */
> > > >
> > > > +typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
> > > > +/**< @internal Retrieve device register count  */
> > > > +
> > > > +typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
> > > > +				struct rte_dev_reg_info *info); /**<
> @internal Retrieve
> > > > +registers  */
> > > > +
> > > > +typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
> > > /**<
> > > > +@internal Retrieve eeprom size  */
> > > > +
> > > > +typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
> > > > +				struct rte_dev_eeprom_info *info); /**<
> > > @internal Retrieve eeprom
> > > > +data  */
> > > > +
> > > > +typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
> > > > +				struct rte_dev_eeprom_info *info); /**<
> > > @internal Program eeprom
> > > > +data  */
> > > > +
> > > > +typedef int (*eth_get_ringparam_t)(struct rte_eth_dev *dev,
> > > > +				struct rte_dev_ring_info *info); /**<
> @internal Retrieve
> > > > +device ring descriptor  */
> > > > +
> > > > +typedef int (*eth_set_ringparam_t)(struct rte_eth_dev *dev,
> > > > +				struct rte_dev_ring_info *info); /**<
> @internal Set device
> > > > +ring descriptor  */
> > > >
> > > >  #ifdef RTE_NIC_BYPASS
> > > >
> > > > @@ -1368,6 +1394,21 @@ struct eth_dev_ops {
> > > >  	reta_update_t reta_update;
> > > >  	/** Query redirection table. */
> > > >  	reta_query_t reta_query;
> > > > +
> > > > +	eth_get_reg_length_t get_reg_length;
> > > > +	/**< Get # of registers */
> > > > +	eth_get_reg_t get_reg;
> > > > +	/**< Get registers */
> > > > +	eth_get_eeprom_length_t get_eeprom_length;
> > > > +	/**< Get eeprom length */
> > > > +	eth_get_eeprom_t get_eeprom;
> > > > +	/**< Get eeprom data */
> > > > +	eth_set_eeprom_t set_eeprom;
> > > > +	/**< Set eeprom */
> > > > +	eth_get_ringparam_t get_ringparam;
> > > > +	/**< Get descriptor ring parameters */
> > > > +	eth_set_ringparam_t set_ringparam;
> > > > +	/**< Set descriptor ring parameters */
> > > >    /* bypass control */
> > > >  #ifdef RTE_NIC_BYPASS
> > > >    bypass_init_t bypass_init;
> > > > @@ -2982,6 +3023,20 @@ int rte_eth_dev_mac_addr_add(uint8_t
> port,
> > > > struct ether_addr *mac_addr,  int
> > > rte_eth_dev_mac_addr_remove(uint8_t
> > > > port, struct ether_addr *mac_addr);
> > > >
> > > >  /**
> > > > + * Set the default MAC address.
> > > > + *
> > > > + * @param port
> > > > + *   The port identifier of the Ethernet device.
> > > > + * @param mac_addr
> > > > + *   New default MAC address.
> > > > + * @return
> > > > + *   - (0) if successful, or *mac_addr* didn't exist.
> > > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > > + *   - (-ENODEV) if *port* invalid.
> > > > + */
> > > > +int rte_eth_dev_default_mac_addr_set(uint8_t port, struct
> > > > +ether_addr *mac_addr);
> > > > +
> > > > +/**
> > > >   * Update Redirection Table(RETA) of Receive Side Scaling of
> > > > Ethernet
> > > device.
> > > >   *
> > > >   * @param port
> > > > @@ -3611,6 +3666,109 @@ int rte_eth_remove_rx_callback(uint8_t
> > > > port_id, uint16_t queue_id,  int
> > > > rte_eth_remove_tx_callback(uint8_t
> > > port_id, uint16_t queue_id,
> > > >  		struct rte_eth_rxtx_callback *user_cb);
> > > >
> > > > +/**
> > > > + * Retrieve number of available registers for access
> > > > + *
> > > > + * @param port_id
> > > > + *   The port identifier of the Ethernet device.
> > > > + * @return
> > > > + *   - (>=0) number of registers if successful.
> > > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > > + *   - (-ENODEV) if *port_id* invalid.
> > > > + *   - others depends on the specific operations implementation.
> > > > + */
> > > > +int rte_eth_dev_reg_leng(uint8_t port_id);
> > > > +
> > > > +/**
> > > > + * Retrieve device registers and register attributes
> > > > + *
> > > > + * @param port_id
> > > > + *   The port identifier of the Ethernet device.
> > > > + * @param info
> > > > + *   The template includes buffer for register data and attribute to be
> > > filled.
> > > > + * @return
> > > > + *   - (0) if successful.
> > > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > > + *   - (-ENODEV) if *port_id* invalid.
> > > > + *   - others depends on the specific operations implementation.
> > > > + */
> > > > +int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info
> > > > +*info);
> > > > +
> > > > +/**
> > > > + * Retrieve size of device EEPROM
> > > > + *
> > > > + * @param port_id
> > > > + *   The port identifier of the Ethernet device.
> > > > + * @return
> > > > + *   - (>=0) EEPROM size if successful.
> > > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > > + *   - (-ENODEV) if *port_id* invalid.
> > > > + *   - others depends on the specific operations implementation.
> > > > + */
> > > > +int rte_eth_dev_eeprom_leng(uint8_t port_id);
> > > > +
> > > > +/**
> > > > + * Retrieve EEPROM and EEPROM attribute
> > > > + *
> > > > + * @param port_id
> > > > + *   The port identifier of the Ethernet device.
> > > > + * @param info
> > > > + *   The template includes buffer for return EEPROM data and
> > > > + *   EEPROM attributes to be filled.
> > > > + * @return
> > > > + *   - (0) if successful.
> > > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > > + *   - (-ENODEV) if *port_id* invalid.
> > > > + *   - others depends on the specific operations implementation.
> > > > + */
> > > > +int rte_eth_dev_get_eeprom(uint8_t port_id, struct
> > > > +rte_dev_eeprom_info *info);
> > > > +
> > > > +/**
> > > > + * Program EEPROM with provided data
> > > > + *
> > > > + * @param port_id
> > > > + *   The port identifier of the Ethernet device.
> > > > + * @param info
> > > > + *   The template includes EEPROM data for programming and
> > > > + *   EEPROM attributes to be filled
> > > > + * @return
> > > > + *   - (0) if successful.
> > > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > > + *   - (-ENODEV) if *port_id* invalid.
> > > > + *   - others depends on the specific operations implementation.
> > > > + */
> > > > +int rte_eth_dev_set_eeprom(uint8_t port_id, struct
> > > > +rte_dev_eeprom_info *info);
> > > > +
> > > > +/**
> > > > + * Retrieve device descriptor ring information
> > > > + *
> > > > + * @param port_id
> > > > + *   The port identifier of the Ethernet device.
> > > > + * @param info
> > > > + *   The template includes device ring descriptor usage information.
> > > > + * @return
> > > > + *   - (0) if successful.
> > > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > > + *   - (-ENODEV) if *port_id* invalid.
> > > > + *   - others depends on the specific operations implementation.
> > > > + */
> > > > +int rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > > +rte_dev_ring_info *info);
> > > > +
> > > > +/**
> > > > + * Set device ring descriptor parameters
> > > > + *
> > > > + * @param port_id
> > > > + *   The port identifier of the Ethernet device.
> > > > + * @param info
> > > > + *   The template includes descriptor ring parameters to be set.
> > > > + * @return
> > > > + *   - (0) if successful.
> > > > + *   - (-ENOTSUP) if hardware doesn't support.
> > > > + *   - (-ENODEV) if *port_id* invalid.
> > > > + *   - others depends on the specific operations implementation.
> > > > + */
> > > > +int rte_eth_dev_set_ringparam(uint8_t port_id, struct
> > > > +rte_dev_ring_info *info);
> > > > +
> > > >  #ifdef __cplusplus
> > > >  }
> > > >  #endif
> > > > diff --git a/lib/librte_ether/rte_ether_version.map
> > > > b/lib/librte_ether/rte_ether_version.map
> > > > index a2d25a6..1b1e092 100644
> > > > --- a/lib/librte_ether/rte_ether_version.map
> > > > +++ b/lib/librte_ether/rte_ether_version.map
> > > > @@ -102,6 +102,14 @@ DPDK_2.0 {
> > > >  	rte_eth_tx_queue_setup;
> > > >  	rte_eth_xstats_get;
> > > >  	rte_eth_xstats_reset;
> > > > +	rte_eth_dev_default_mac_addr_set;
> > > > +	rte_eth_dev_reg_leng;
> > > > +	rte_eth_dev_reg_info;
> > > > +	rte_eth_dev_eeprom_leng;
> > > > +	rte_eth_dev_get_eeprom;
> > > > +	rte_eth_dev_set_eeprom;
> > > > +	rte_eth_dev_get_ringparam;
> > > > +	rte_eth_dev_set_ringparam;
> > > >
> > > >  	local: *;
> > > >  };
> > > > --
> > > > 2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-11 21:51           ` Wang, Liang-min
@ 2015-06-12 12:30             ` Ananyev, Konstantin
  2015-06-15 13:26               ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Ananyev, Konstantin @ 2015-06-12 12:30 UTC (permalink / raw)
  To: Wang, Liang-min, dev



> -----Original Message-----
> From: Wang, Liang-min
> Sent: Thursday, June 11, 2015 10:51 PM
> To: Ananyev, Konstantin; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
> 
> 
> 
> > -----Original Message-----
> > From: Ananyev, Konstantin
> > Sent: Thursday, June 11, 2015 9:07 AM
> > To: Wang, Liang-min; dev@dpdk.org
> > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> > device info
> >
> >
> >
> > > -----Original Message-----
> > > From: Wang, Liang-min
> > > Sent: Thursday, June 11, 2015 1:58 PM
> > > To: Ananyev, Konstantin; dev@dpdk.org
> > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > access device info
> > >
> > > Hi Konstantin,
> > >
> > > > -----Original Message-----
> > > > From: Ananyev, Konstantin
> > > > Sent: Thursday, June 11, 2015 8:26 AM
> > > > To: Wang, Liang-min; dev@dpdk.org
> > > > Cc: Wang, Liang-min
> > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > access device info
> > > >
> > > > Hi Larry,
> > > >
> > > > > -----Original Message-----
> > > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Liang-Min
> > > > > Larry Wang
> > > > > Sent: Wednesday, June 10, 2015 4:10 PM
> > > > > To: dev@dpdk.org
> > > > > Cc: Wang, Liang-min
> > > > > Subject: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > > access device info
> > > > >
> > > > > add new apis:
> > > > > - rte_eth_dev_default_mac_addr_set
> > > > > - rte_eth_dev_reg_leng
> > > > > - rte_eth_dev_reg_info
> > > > > - rte_eth_dev_eeprom_leng
> > > > > - rte_eth_dev_get_eeprom
> > > > > - rte_eth_dev_set_eeprom
> > > > > - rte_eth_dev_get_ringparam
> > > > > - rte_eth_dev_set_ringparam
> > > > >
> > > > > to enable reading device parameters (mac-addr, register, eeprom,
> > > > > ring) based upon ethtool alike data parameter specification.
> > > > >
> > > > > Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> > > > > ---
> > > > >  lib/librte_ether/Makefile              |   1 +
> > > > >  lib/librte_ether/rte_eth_dev_info.h    |  80 +++++++++++++++++
> > > > >  lib/librte_ether/rte_ethdev.c          | 159
> > > > +++++++++++++++++++++++++++++++++
> > > > >  lib/librte_ether/rte_ethdev.h          | 158
> > > > ++++++++++++++++++++++++++++++++
> > > > >  lib/librte_ether/rte_ether_version.map |   8 ++
> > > > >  5 files changed, 406 insertions(+)  create mode 100644
> > > > > lib/librte_ether/rte_eth_dev_info.h
> > > > >
> > > > > diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
> > > > > index c0e5768..05209e9 100644
> > > > > --- a/lib/librte_ether/Makefile
> > > > > +++ b/lib/librte_ether/Makefile
> > > > > @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c  SYMLINK-y-include +=
> > > > > rte_ether.h  SYMLINK-y-include += rte_ethdev.h  SYMLINK-y-include
> > > > > += rte_eth_ctrl.h
> > > > > +SYMLINK-y-include += rte_eth_dev_info.h
> > > > >
> > > > >  # this lib depends upon:
> > > > >  DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring
> > > > > lib/librte_mbuf diff --git a/lib/librte_ether/rte_eth_dev_info.h
> > > > > b/lib/librte_ether/rte_eth_dev_info.h
> > > > > new file mode 100644
> > > > > index 0000000..002c4b5
> > > > > --- /dev/null
> > > > > +++ b/lib/librte_ether/rte_eth_dev_info.h
> > > > > @@ -0,0 +1,80 @@
> > > > > +/*-
> > > > > + *   BSD LICENSE
> > > > > + *
> > > > > + *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> > > > > + *   All rights reserved.
> > > > > + *
> > > > > + *   Redistribution and use in source and binary forms, with or without
> > > > > + *   modification, are permitted provided that the following conditions
> > > > > + *   are met:
> > > > > + *
> > > > > + *     * Redistributions of source code must retain the above copyright
> > > > > + *       notice, this list of conditions and the following disclaimer.
> > > > > + *     * Redistributions in binary form must reproduce the above
> > copyright
> > > > > + *       notice, this list of conditions and the following disclaimer in
> > > > > + *       the documentation and/or other materials provided with the
> > > > > + *       distribution.
> > > > > + *     * Neither the name of Intel Corporation nor the names of its
> > > > > + *       contributors may be used to endorse or promote products
> > derived
> > > > > + *       from this software without specific prior written permission.
> > > > > + *
> > > > > + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > > > CONTRIBUTORS
> > > > > + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
> > BUT
> > > > NOT
> > > > > + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> > > > FITNESS FOR
> > > > > + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> > > > COPYRIGHT
> > > > > + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> > > > INCIDENTAL,
> > > > > + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> > (INCLUDING,
> > > > BUT NOT
> > > > > + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> > > > LOSS OF USE,
> > > > > + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> > CAUSED
> > > > AND ON ANY
> > > > > + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> > OR
> > > > TORT
> > > > > + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> > OUT
> > > > OF THE USE
> > > > > + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > > > DAMAGE.
> > > > > + */
> > > > > +
> > > > > +#ifndef _RTE_ETH_DEV_INFO_H_
> > > > > +#define _RTE_ETH_DEV_INFO_H_
> > > > > +
> > > > > +
> > > > > +/*
> > > > > + * Placeholder for accessing device registers  */ struct
> > > > > +rte_dev_reg_info {
> > > > > +	void *buf; /**< Buffer for register */
> > > > > +	uint32_t offset; /**< Offset for 1st register to fetch */
> > > > > +	uint32_t leng; /**< Number of registers to fetch */
> > > > > +	uint32_t version; /**< Device version */ };
> > > > > +
> > > > > +/*
> > > > > + * Placeholder for accessing device eeprom  */ struct
> > > > > +rte_dev_eeprom_info {
> > > > > +	void *buf; /**< Buffer for eeprom */
> > > > > +	uint32_t offset; /**< Offset for 1st eeprom location to access */
> > > > > +	uint32_t leng; /**< Length of eeprom region to access */
> > > > > +	uint32_t magic; /**< Device ID */ };
> > > > > +
> > > > > +/*
> > > > > + * Placeholder for accessing device ring parameters  */ struct
> > > > > +rte_dev_ring_info {
> > > > > +	uint32_t rx_pending; /**< Number of outstanding Rx ring */
> > > > > +	uint32_t tx_pending; /**< Number of outstanding Tx ring */
> > > > > +	uint32_t rx_max_pending; /**< Maximum number of outstanding Rx
> > > > ring */
> > > > > +	uint32_t tx_max_pending; /**< Maximum number of outstanding Tx
> > > > ring
> > > > > +*/ };
> > > > > +
> > > > > +/*
> > > > > + * A data structure captures information as defined in struct
> > > > > +ifla_vf_info
> > > > > + * for user-space api
> > > > > + */
> > > > > +struct rte_dev_vf_info {
> > > > > +	uint32_t vf;
> > > > > +	uint8_t mac[ETHER_ADDR_LEN];
> > > > > +	uint32_t vlan;
> > > > > +	uint32_t tx_rate;
> > > > > +	uint32_t spoofchk;
> > > > > +};
> > > >
> > > >
> > > > Wonder what that structure is for?
> > > > I can't see it used in any function below?
> > > >
> > >
> > > Good catch, this is designed for other ethtool ops that I did not include in
> > this release, I will remove this from next fix.
> > >
> > > > > +
> > > > > +#endif /* _RTE_ETH_DEV_INFO_H_ */
> > > > > diff --git a/lib/librte_ether/rte_ethdev.c
> > > > > b/lib/librte_ether/rte_ethdev.c index 5a94654..186e85c 100644
> > > > > --- a/lib/librte_ether/rte_ethdev.c
> > > > > +++ b/lib/librte_ether/rte_ethdev.c
> > > > > @@ -2751,6 +2751,32 @@ rte_eth_dev_mac_addr_remove(uint8_t
> > > > port_id,
> > > > > struct ether_addr *addr)  }
> > > > >
> > > > >  int
> > > > > +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct
> > > > > +ether_addr
> > > > > +*addr) {
> > > > > +	struct rte_eth_dev *dev;
> > > > > +	const int index = 0;
> > > > > +	const uint32_t pool = 0;
> > > > > +
> > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	dev = &rte_eth_devices[port_id];
> > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_remove, -
> > > > ENOTSUP);
> > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -
> > > > ENOTSUP);
> > > > > +
> > > > > +	/* Update NIC default MAC address*/
> > > > > +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> > > > > +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> > > > > +
> > > > > +	/* Update default address in NIC data structure */
> > > > > +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +int
> > > > >  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
> > > > >  				uint16_t rx_mode, uint8_t on)  { @@ -3627,3
> > +3653,136 @@
> > > > > rte_eth_remove_tx_callback(uint8_t port_id,
> > > > uint16_t queue_id,
> > > > >  	/* Callback wasn't found. */
> > > > >  	return -EINVAL;
> > > > >  }
> > > > > +
> > > > > +int
> > > > > +rte_eth_dev_reg_leng(uint8_t port_id) {
> > > > > +	struct rte_eth_dev *dev;
> > > > > +
> > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -
> > > > ENOTSUP);
> > > > > +	return (*dev->dev_ops->get_reg_length)(dev);
> > > > > +}
> > > > > +
> > > > > +int
> > > > > +rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info
> > > > > +*info) {
> > > > > +	struct rte_eth_dev *dev;
> > > > > +
> > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
> > > > > +	return (*dev->dev_ops->get_reg)(dev, info); }
> > > >
> > > > Seems that *get_reg* stuff, will be really good addition for DPDK
> > > > debugging abilities.
> > > > Though, I'd suggest we change it a bit to make more generic and flexible:
> > > >
> > > > Introduce rte_eth_reg_read/rte_eth_reg_write(),
> > > > or probably even better rte_pcidev_reg_read /rte_pcidev_reg_write at
> > EAL.
> > > > Something similar to what port_pci_reg_read/port_pci_reg_write() are
> > > > doing now at testpmd.h.
> > > >
> > > > struct rte_pcidev_reg_info {
> > > >    const char *name;
> > > >    uint32_t endianes, bar, offset, size, count; };
> > > >
> > > > int rte_pcidev_reg_read(const struct rte_pci_device *, const struct
> > > > rte_pcidev_reg_info *, uint64_t *reg_val);
> > > >
> > > > Then:
> > > > int rte_eth_dev_get_reg_info(port_id, const struct
> > > > rte_pcidev_reg_info **info);
> > > >
> > > > So each device would store in info a pointer to an array of it's
> > > > register descriptions (finished by zero elem?).
> > > >
> > > > Then your ethtool (or any other upper layer) can do the following to
> > > > read all device regs:
> > > >
> > >
> > > The proposed reg info structure allows future improvement to support
> > individual register read/write.
> > > Also, because each NIC device has a very distinguish register definition.
> > > So, the plan is to have more comprehensive interface to support query
> > > operation (for example, register name) before introduce individual/group
> > register access.
> > > Points taken, the support will be in future release.
> >
> > Sorry, didn't get you.
> > So you are ok to make these changes in next patch version?
> >
> I would like to get a consensus from dpdk community on how to provide register information.

Well, that' ok, but if it is just a trial patch that is not intended to be applied, then you should mark it as RFC.

> Currently, it's designed for debug dumping. The register information is very hardware dependent.
> Need to consider current supported NIC device and future devices for DPDK, so we won't make it a bulky interface.

Ok, could you explain what exactly  concerns you in the approach described above?
What part you feel is bulky?

> > >
> > > > const struct rte_eth_dev_reg_info *reg_info; struct rte_eth_dev_info
> > > > dev_info;
> > > >
> > > > rte_eth_dev_info_get(pid, &dev_info);
> > > > rte_eth_dev_get_reg_info(port_id, &reg_info);
> > > >
> > > > for (i = 0; reg_info[i].name != NULL; i++) {
> > > >    ...
> > > >    rte_pcidev_read_reg(dev_info. pci_dev, reg_info[i], &v);
> > > >   ..
> > > > }
> > > >
> > > > > +
> > > > > +int
> > > > > +rte_eth_dev_eeprom_leng(uint8_t port_id) {
> > > > > +	struct rte_eth_dev *dev;
> > > > > +
> > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -
> > > > ENOTSUP);
> > > > > +	return (*dev->dev_ops->get_eeprom_length)(dev);
> > > > > +}
> > > > > +
> > > > > +int
> > > > > +rte_eth_dev_get_eeprom(uint8_t port_id, struct
> > > > > +rte_dev_eeprom_info
> > > > > +*info) {
> > > > > +	struct rte_eth_dev *dev;
> > > > > +
> > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -
> > > > ENOTSUP);
> > > > > +	return (*dev->dev_ops->get_eeprom)(dev, info); }
> > > > > +
> > > > > +int
> > > > > +rte_eth_dev_set_eeprom(uint8_t port_id, struct
> > > > > +rte_dev_eeprom_info
> > > > > +*info) {
> > > > > +	struct rte_eth_dev *dev;
> > > > > +
> > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -
> > > > ENOTSUP);
> > > > > +	return (*dev->dev_ops->set_eeprom)(dev, info); }
> > > > > +
> > > > > +int
> > > > > +rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > > > +rte_dev_ring_info
> > > > > +*info) {
> > > > > +	struct rte_eth_dev *dev;
> > > > > +
> > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > +		return -ENODEV;
> > > > > +	}
> > > > > +
> > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> > > > ENOTSUP);
> > > > > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> > > >
> > > > I think it will be a useful addition to the ethdev API  to have an
> > > > ability to retrieve current RX/TX queue parameters.
> > > > Though again, it need to be more generic, so it could be useful for
> > > > non- ethtool upper layer too.
> > > > So I suggest to modify it a bit.
> > > > Something like that:
> > > >
> > > > struct rte_eth_tx_queue_info {
> > > >     struct rte_eth_txconf txconf;
> > > >     uint32_t nb_tx_desc;
> > > >     uint32_t nb_max_tx_desc; /*max allowable TXDs for that queue */
> > > >     uint32_t nb_tx_free;            /* number of free TXDs at the moment of
> > call.
> > > > */
> > > >     /* other tx queue data. */
> > > > };
> > > >
> > > > int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> > > > rte_eth_tx_queue_info *qinfo)
> > > >
> > > > Then, your upper layer ethtool wrapper, can implement yours
> > > > ethtool_get_ringparam() by:
> > > >
> > > >  ...
> > > >  struct rte_eth_tx_queue_info qinfo;
> > > > rte_ethdev_get_tx_queue_info(port, 0, &qinfo);
> > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > rte_eth_rx_queue_count(port, 0);
> > > >
> > > > Or probably even:
> > > > ring_param->tx_pending = qinfo.nb_tx_desc - qinfo.nb_tx_free;
> > > >
> > > > Same for RX.
> > > >
> > > For now, this descriptor ring information is used by the ethtool op.
> > > To make this interface simple, i.e. caller doesn't need to access other
> > queue information.
> >
> > I just repeat what I said to you in off-line conversation:
> > ethdev API is not equal ethtool API.
> > It is ok to add  a new function/structure to ethdev if it really needed, but we
> > should do mechanical one to one copy.
> > It is much better to add  a function/structure that would be more generic,
> > and suit other users, not only ethtool.
> > There is no point to have dozen functions in rte_ethdev API providing similar
> > information.
> > BTW, I don't see how API I proposed is much more  complex, then yours one.
> The ring parameter is a run-time information which is different than data structure described in this discussion.

I don't see how they are different.
Looking at ixgbe_get_ringparam(), it returns:
rx_max_pending - that's a static IXGBE PMD value (max possible number of RXDs per one queue).
rx_pending - number of RXD currently in use by the HW for queue 0 (that information can be changed at each call).

With the approach I suggesting - you can get same information for each RX queue by
calling rte_ethdev_get_rx_queue_info() and rte_eth_rx_queue_count(). 
Plus you are getting other RX queue data.

Another thing - what is practical usage of the information you retrieving now by get_ringparam()?
Let say it returned to you: rx_max_pending=4096; rx_pending=128;
How that information would help to understand what is going on with the device?
Without knowing  value of nb_tx_desc for the queue, you can't say is you queue full or not.
Again, it could be that all your traffic going through some other queue (not 0).
So from my point rte_eth_dev_get_ringparam()  usage is very limited, and doesn't
provide enough information about current queue state.

Same thing applies for TX. 

> It's the desire of this patch to separate each data structure to avoid cross dependency.

That's too cryptic to me.
Could you explain what cross dependency you are talking about?

Konstantin

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v6 0/4] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (3 preceding siblings ...)
  2015-06-11 21:43 ` [dpdk-dev] [PATCH v5 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-06-12 22:03 ` Liang-Min Larry Wang
  2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (4 more replies)
  2015-06-17 22:22 ` [dpdk-dev] [PATCH v7 " Liang-Min Larry Wang
                   ` (10 subsequent siblings)
  15 siblings, 5 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-12 22:03 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v6 change:
- Rebase to match new changes over dpdk repository (librte_ether)
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (4):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  186 ++++
 drivers/net/e1000/igb_regs.h                     |  217 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  202 +++++
 drivers/net/ixgbe/ixgbe_regs.h                   |  357 ++++++++
 drivers/net/ixgbe/ixgbe_rxtx.c                   |   16 +
 drivers/net/ixgbe/ixgbe_rxtx.h                   |    1 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1052 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  821 +++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  153 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  326 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  412 +++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  427 +++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   67 ++
 lib/librte_ether/rte_ethdev.c                    |  134 +++
 lib/librte_ether/rte_ethdev.h                    |  144 +++
 lib/librte_ether/rte_ether_version.map           |    7 +
 21 files changed, 4746 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v6 1/4] ethdev: add apis to support access device info
  2015-06-12 22:03 ` [dpdk-dev] [PATCH v6 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-06-12 22:03   ` Liang-Min Larry Wang
  2015-06-13 23:25     ` David Harton (dharton)
  2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-12 22:03 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add new apis:
- rte_eth_dev_default_mac_addr_set
- rte_eth_dev_reg_length
- rte_eth_dev_reg_info
- rte_eth_dev_eeprom_length
- rte_eth_dev_get_eeprom
- rte_eth_dev_set_eeprom
- rte_eth_dev_get_ringparam

to enable reading device parameters (mac-addr, register,
eeprom, ring) based upon ethtool alike
data parameter specification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  67 +++++++++++++++
 lib/librte_ether/rte_ethdev.c          | 134 ++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 144 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   7 ++
 5 files changed, 353 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..1cf2c23
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,67 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+/*
+ * Placeholder for accessing device ring parameters
+ */
+struct rte_dev_ring_info {
+	uint32_t rx_pending; /**< Number of outstanding Rx ring */
+	uint32_t tx_pending; /**< Number of outstanding Tx ring */
+	uint32_t rx_max_pending; /**< Maximum number of outstanding Rx ring */
+	uint32_t tx_max_pending; /**< Maximum number of outstanding Tx ring */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index e13fde5..27c9215 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2751,6 +2751,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3644,3 +3668,113 @@ rte_eth_dev_set_mc_addr_list(uint8_t port_id,
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_mc_addr_list, -ENOTSUP);
 	return dev->dev_ops->set_mc_addr_list(dev, mc_addr_set, nb_mc_addr);
 }
+
+int
+rte_eth_dev_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -ENOTSUP);
+	return (*dev->dev_ops->get_ringparam)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 04c192d..c9e629d 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1233,6 +1234,32 @@ typedef int (*eth_set_mc_addr_list_t)(struct rte_eth_dev *dev,
 				      uint32_t nb_mc_addr);
 /**< @internal set the list of multicast addresses on an Ethernet device */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
+typedef int (*eth_get_ringparam_t)(struct rte_eth_dev *dev,
+				struct rte_dev_ring_info *info);
+/**< @internal Retrieve device ring descriptor  */
+
+typedef int (*eth_set_ringparam_t)(struct rte_eth_dev *dev,
+				struct rte_dev_ring_info *info);
+/**< @internal Set device ring descriptor  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1372,6 +1399,21 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
+	eth_get_ringparam_t get_ringparam;
+	/**< Get descriptor ring parameters */
+	eth_set_ringparam_t set_ringparam;
+	/**< Set descriptor ring parameters */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -2987,6 +3029,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3616,6 +3672,94 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Retrieve device descriptor ring information
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes device ring descriptor usage information.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 012a82e..f75f3d1 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,13 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
+	rte_eth_dev_get_ringparam;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v6 2/4] ixgbe: add ops to support ethtool ops
  2015-06-12 22:03 ` [dpdk-dev] [PATCH v6 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-12 22:03   ` Liang-Min Larry Wang
  2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 3/4] igb: " Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-12 22:03 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_ringparam
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 202 ++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_regs.h   | 357 +++++++++++++++++++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.c   |  16 ++
 drivers/net/ixgbe/ixgbe_rxtx.h   |   1 +
 4 files changed, 576 insertions(+)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 7414a2e..7418753 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -179,6 +183,7 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -223,6 +228,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+		struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -260,6 +267,16 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_ringparam(struct rte_eth_dev *dev, struct rte_dev_ring_info *param);
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -359,6 +376,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -386,6 +404,12 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.rss_hash_conf_get    = ixgbe_dev_rss_hash_conf_get,
 	.filter_ctrl          = ixgbe_dev_filter_ctrl,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.get_ringparam        = ixgbe_get_ringparam,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -412,6 +436,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2889,6 +2916,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3719,6 +3754,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4471,6 +4514,165 @@ ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 					 ixgbe_dev_addr_list_itr, TRUE);
 }
 
+static int
+ixgbe_get_ringparam(struct rte_eth_dev *dev,
+	struct rte_dev_ring_info *ring_param)
+{
+	/* Pending rx/tx descriptors in queue #0 */
+	struct ixgbe_tx_queue *txq = dev->data->tx_queues[0];
+	struct ixgbe_rx_queue *rxq = dev->data->rx_queues[0];
+
+	ring_param->rx_pending = rxq->nb_rx_desc - ixgbe_dev_rx_queue_count(dev, 0);
+	ring_param->tx_pending = txq->nb_tx_desc - ixgbe_dev_tx_queue_count(dev, 0);
+	/* The ixgbe descriptor ring is multiple of 8 descriptor, i.e. module by 8*16 bytes */
+	ring_param->rx_max_pending = IXGBE_MAX_RING_DESC;
+	ring_param->tx_max_pending = IXGBE_MAX_RING_DESC;
+
+	return 0;
+}
+
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+	reg_info **reg_set =
+		(hw->mac.type == ixgbe_mac_82598EB)?ixgbe_regs_mac_82598EB:ixgbe_regs_others;
+
+	reg_group = reg_set[g_ind++];
+	while(reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = reg_set[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = ixgbevf_regs[g_ind++];
+	while(reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = ixgbevf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+	reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB)?
+					ixgbe_regs_mac_82598EB:ixgbe_regs_others;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = reg_set[g_ind++];
+		while(reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = reg_set[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = ixgbevf_regs[g_ind++];
+		while(reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = ixgbevf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size*2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+		((first+leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+		((first+leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..7025ed8
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,357 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+typedef struct _reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_nvm [] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_interrupt [] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_interrupt [] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_rx [] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_tx [] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_tx [] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_wakeup [] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_dcb [] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_mac [] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_diagnostic [] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static reg_info* ixgbe_regs_others[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+                                ixgbe_regs_fctl_others, ixgbe_regs_rxdma, ixgbe_regs_rx,
+                                ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
+                                ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
+
+static reg_info* ixgbe_regs_mac_82598EB[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+                                ixgbe_regs_fctl_mac_82598EB, ixgbe_regs_rxdma, ixgbe_regs_rx,
+                                ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
+                                ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
+
+/* VF registers */
+static reg_info* ixgbevf_regs[] = { ixgbevf_regs_general, ixgbevf_regs_interrupt,
+                                ixgbevf_regs_rxdma, ixgbevf_regs_tx, NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for(i = 0; i < reg->count; i++) {
+		reg_buf[i] = IXGBE_READ_REG(hw, reg->base_addr + i*reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += ixgbe_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif // _IXGBE_REGS_H_
diff --git a/drivers/net/ixgbe/ixgbe_rxtx.c b/drivers/net/ixgbe/ixgbe_rxtx.c
index 4f9ab22..762d303 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx.c
+++ b/drivers/net/ixgbe/ixgbe_rxtx.c
@@ -2448,6 +2448,22 @@ ixgbe_dev_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)
 	return desc;
 }
 
+uint32_t
+ixgbe_dev_tx_queue_count(struct rte_eth_dev *dev, uint16_t tx_queue_id)
+{
+	struct ixgbe_tx_queue *txq;
+
+	if (tx_queue_id >= dev->data->nb_tx_queues) {
+		PMD_TX_LOG(ERR, "Invalid TX queue id=%d", tx_queue_id);
+		return 0;
+	}
+
+	txq = dev->data->tx_queues[tx_queue_id];
+	if (txq->tx_ring[txq->tx_next_dd].wb.status & IXGBE_ADVTXD_STAT_DD)
+		return (txq->nb_tx_free + txq->tx_rs_thresh);
+	return txq->nb_tx_free;
+}
+
 int
 ixgbe_dev_rx_descriptor_done(void *rx_queue, uint16_t offset)
 {
diff --git a/drivers/net/ixgbe/ixgbe_rxtx.h b/drivers/net/ixgbe/ixgbe_rxtx.h
index af36438..3b3163c 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx.h
+++ b/drivers/net/ixgbe/ixgbe_rxtx.h
@@ -282,6 +282,7 @@ uint16_t ixgbe_recv_scattered_pkts_vec(void *rx_queue,
 		struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 int ixgbe_rx_vec_dev_conf_condition_check(struct rte_eth_dev *dev);
 int ixgbe_rxq_vec_setup(struct ixgbe_rx_queue *rxq);
+uint32_t ixgbe_dev_tx_queue_count(struct rte_eth_dev *dev, uint16_t tx_queue_id);
 
 #ifdef RTE_IXGBE_INC_VECTOR
 
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v6 3/4] igb: add ops to support ethtool ops
  2015-06-12 22:03 ` [dpdk-dev] [PATCH v6 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-06-12 22:03   ` Liang-Min Larry Wang
  2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  2015-06-13  0:21   ` [dpdk-dev] [PATCH v6 0/4] User-space Ethtool Andrew Harvey (agh)
  4 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-12 22:03 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 186 +++++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 217 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 403 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 24c7510..cde6840 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -129,6 +130,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -142,6 +145,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -193,6 +202,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -268,12 +285,18 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
 	.rss_hash_conf_get    = eth_igb_rss_hash_conf_get,
 	.filter_ctrl          = eth_igb_filter_ctrl,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -295,6 +318,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2113,6 +2139,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+	                     struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2347,6 +2381,16 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.rar_set(hw, (void *)addr, 0); /* index is not used by rar_set() */
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3660,6 +3704,148 @@ eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = igb_regs[g_ind++];
+	while(reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igb_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = igbvf_regs[g_ind++];
+	while(reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igbvf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igb_regs[g_ind++];
+		while(reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = igb_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igbvf_regs[g_ind++];
+		while(reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = igbvf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size*2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) || ((first+leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) || ((first+leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..14602e8
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,217 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+typedef struct _reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_nvm [] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_interrupt [] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_rx [] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_tx [] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_wakeup [] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_mac [] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info* igb_regs[] = { igb_regs_general, igb_regs_nvm,
+                                igb_regs_interrupt, igb_regs_fctl,
+                                igb_regs_rxdma, igb_regs_rx,
+                                igb_regs_tx, igb_regs_wakeup, igb_regs_mac,
+                                NULL};
+
+static reg_info* igbvf_regs[] = { igb_regs_general,
+	/*
+	 * FIXME: reading igb_regs_interrupt results side-effect which doesn't work with VFIO
+	 *
+	 * igb_regs_interrupt,
+	 */
+                                  igb_regs_rxdma, igb_regs_tx, NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for(i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw, reg->base_addr + i*reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += igb_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif // _IGB_REGS_H_
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v6 4/4] examples: new example: l2fwd-ethtool
  2015-06-12 22:03 ` [dpdk-dev] [PATCH v6 0/4] User-space Ethtool Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 3/4] igb: " Liang-Min Larry Wang
@ 2015-06-12 22:03   ` Liang-Min Larry Wang
  2015-06-13  0:21   ` [dpdk-dev] [PATCH v6 0/4] User-space Ethtool Andrew Harvey (agh)
  4 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-12 22:03 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1052 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  821 +++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  153 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  326 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  412 +++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  427 +++++++++
 10 files changed, 3414 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..a753c33
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..3d31cb1
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -lrte_ethtool
+LDFLAGS += -L$(SRCDIR)/../lib/build
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..04c7ec1
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1052 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id)            ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id)     ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask = 0;
+
+/* virtio setup enable */
+static int virtio_setup = 0;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+    return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done (void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ------------------------------"
+			   "\nPackets sent: %24"PRIu64
+			   "\nPackets received: %20"PRIu64
+			   "\nPackets dropped: %21"PRIu64,
+			   portid,
+			   port_statistics[portid].tx,
+			   port_statistics[portid].rx,
+			   port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ==============================="
+		   "\nTotal packets sent: %18"PRIu64
+		   "\nTotal packets received: %14"PRIu64
+		   "\nTotal packets dropped: %15"PRIu64,
+		   total_packets_tx,
+		   total_packets_rx,
+		   total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid =0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+    if(virtio_setup) {
+        while (is_ipc_done() == 0) usleep(50);
+    }
+	while (1) {
+
+		cur_tsc = rte_rdtsc();
+
+		/*
+		 * TX burst queue drain
+		 */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >= (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id == rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+	       "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+	       "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+           "  -V : setting rx/tx mode to enable virtio\n"
+		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
+	       prgname);
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+            virtio_setup = l2fwd_parse_virtio_setup(optarg);
+            if (virtio_setup) {
+			    port_conf.rxmode.hw_vlan_strip = 0;
+			    port_conf.rxmode.hw_vlan_extend = 0;
+            }
+            break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status)
+					printf("Port %d Link Up - speed %u "
+						"Mbps - %s\n", (uint8_t)portid,
+						(unsigned)link.link_speed,
+				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+					("full-duplex") : ("half-duplex\n"));
+				else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+inline static char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+    static char addr_string[MAC_STR_SIZE];
+
+    snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+        mac_addr[0], mac_addr[1], mac_addr[2],
+        mac_addr[3], mac_addr[4], mac_addr[5]);
+    return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+    uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for(port_id = 0; port_id < num_of_ports; port_id++){
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of rte_eth_promiscuous_enable */
+		/* to test rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data = (struct rte_eth_dev_data*)dev->data;
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is %s", port_id, mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))) {
+				if (rte_ethtool_net_set_mac_addr(port_id, (void *)new_mac_addr) == 0) {
+					printf(", and it's being re-assigned to %s\n", mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1, &param2_size, param2);
+		if (req_type != (req_t)ipc_begin) {
+			proc_invalid(req_id);
+		} else {
+			break;
+		}
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1, &param2_size, param2);
+		port_id = param1[0];
+
+		switch((req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id, first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0) {
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			}
+			if (reg_count) {
+				status = proc_ethtool_get_regs(port_id, req_id, first_param, reply1);
+			}
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0) {
+				eeprom_size = rte_ethtool_get_eeprom_len(port_id);
+			}
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id, first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id, first_param, param2);
+			break;
+
+		case get_ringparam:
+			{
+				struct ethtool_ringparam *ring_param = (void *)reply1;
+				status = proc_ethtool_get_ringparam(port_id, req_id, ring_param);
+
+				if (status != 0) {
+					printf("get_ringparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case set_ringparam:
+			{
+				struct ethtool_ringparam *ring_param = (void *)reply1;
+				status = proc_ethtool_set_ringparam(port_id, req_id, ring_param);
+
+				if (status != 0) {
+					printf("set_ringparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param = (void *)reply1;
+				status = proc_ethtool_get_pauseparam(port_id, req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param = (void *)reply1;
+				status = proc_ethtool_set_pauseparam(port_id, req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id, req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id, req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id, req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id, req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id, req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id, req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id, req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id, req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type: %d\n",req_type);
+			break;
+		}
+		if ( status < 0)
+			printf("Service request with type (=%d) failed or not supported!!!\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+    init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		}
+		else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+		       lcore_queue_conf[rx_lcore_id].n_rx_port ==
+		       l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n", (unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					     rte_eth_dev_socket_id(portid),
+					     NULL,
+					     l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+    cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+			"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..e57b7c3
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,821 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE								6
+#define quad_aligned_size(x)						(x & 0x7)?((x+7)&0x7): x
+
+#define size16(data_type)							(uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED			-1
+#define NETDEV_INVALID				-1
+#define NETDEV_STATUS(data_size)	(GOOD_RETURN(data_size)?0:NETDEV_INVALID)
+#define UNUSED(x)					(void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id = 0;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY );
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close (fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY );
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close (fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	// block on read if reply is not available
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id) {
+		return -1;
+	}
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return leng;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs), param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size)){
+		return link_status;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return leng;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_ringparam(uint8_t port_id, struct ethtool_ringparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_ringparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return valid;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t* param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY );
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else {
+			*param2_size = 0;
+		}
+	}
+	close (fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(struct ethtool_drvinfo);
+	}
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	if ((reg_len = rte_ethtool_get_regs_len(port_id)) == 0) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(int);
+	}
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	}
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	if ((eeprom_leng = rte_ethtool_get_eeprom_len(port_id)) == 0) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(int);
+	}
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_ringparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_ringparam(port_id,
+		(struct ethtool_ringparam *)reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_ringparam));
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_ringparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_ringparam(port_id,
+		(struct ethtool_ringparam *)set_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_ringparam));
+	}
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	}
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = MAC_ADDR_SIZE;
+	}
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(struct rte_eth_stats);
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..c854811
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,153 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE			"/tmp/nic_request"
+#define REP_PIPE			"/tmp/nic_reply"
+#define PAGE_SIZE			(4*1024)
+#define STACK_SIZE			(4*PAGE_SIZE)
+#define MAXI_DATA			(1024 *6)
+#define MAXI_PARA			1024
+#define STATUS_MASK			0x8000
+#define MULTIPLE_DATA_MASK	0x4000
+#define MAXI_REQ_TYPE		16
+#define FIRST_DATA_OFFSET	8
+#define to_ptr(new_ptr_type, data, offset)			(new_ptr_type)(&((unsigned char *)(void*)data)[offset])
+#define u8ptr(x)									(uint8_t*)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT						(sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye)	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size)	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes)		(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes)				(data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size)			(data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)						(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)					((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)						((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)				(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)				((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)						(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)				((dword_ptr[0] >> 16)& 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)				(dword_ptr[1])
+
+#define BAD_RETURN(data_size)					(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)					((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)				(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)					(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)						((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)					(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data,ptr_type)	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+typedef enum _REQ_TYPE {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_ringparam,
+	set_ringparam,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+} req_t;
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif // _SHARED_FIFO_H_
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..b3b8c83
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..83c5a62
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,326 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	if ((n = rte_eth_dev_reg_length(port_id)) > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	if ((n = rte_eth_dev_eeprom_length(port_id)) > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	if ((status = rte_eth_dev_reg_info(port_id, &reg_info))
+		!= 0)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	if ((status = rte_eth_dev_get_eeprom(port_id, &eeprom_info)) != 0)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	if ((status = rte_eth_dev_set_eeprom(port_id, &eeprom_info)) != 0)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_ringparam(uint8_t port_id,
+	struct ethtool_ringparam *ring_param)
+{
+	struct rte_dev_ring_info ring_info;
+	int status;
+
+	if ((status = rte_eth_dev_get_ringparam(port_id, &ring_info)) != 0)
+		return status;
+
+	ring_param->rx_pending = ring_info.rx_pending;
+	ring_param->tx_pending = ring_info.tx_pending;
+	ring_param->rx_max_pending = ring_info.rx_max_pending;
+	ring_param->tx_max_pending = ring_info.tx_max_pending;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_ringparam(uint8_t port_id __rte_unused,
+	struct ethtool_ringparam *ring_param __rte_unused)
+{
+	return -ENOTSUP;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	if ((status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf)) != 0)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch(fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	if ((status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf)) != 0)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	if ((status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf)) != 0)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..10deaa1
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,412 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_ringparam:       ethtool_ops::get_ringparam
+ * rte_ethtool_set_ringparam:       ethtool_ops::set_ringparam
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom, void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom, void *words);
+
+/**
+ * Retrieve the Ethernet device ring configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_ringparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_ringparam(uint8_t port_id, struct ethtool_ringparam *ring_param);
+
+/**
+ * Setting the Ethernet device ring configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_ringparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_ringparam(uint8_t port_id, struct ethtool_ringparam *ring_param);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..d49ca98
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..4ca6ee1
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,427 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES/(after_ts - before_ts)
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES*8/(after_ts - before_ts)
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES*64*8/(after_ts - before_ts)
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
+}
+
+static uint32_t port_mask = 0;
+static uint32_t vf_port_mask = 0;
+static uint8_t num_of_ports = 0;
+static int keep_traffic = 1;
+
+inline static int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1<< port_id)) > 0;
+}
+
+inline static int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports	= reply_data[0];
+	port_mask		= reply_data2[0];
+	vf_port_mask	= reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0) {
+				printf("setrlimit returned result = %d\n", result);
+			} else {
+				printf("setrlimit succeed!!!\n");
+			}
+		} else {
+			printf("default stack size is 0x%x\n", (int)(rl.rlim_cur));
+		}
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id)) {
+		port_id = rand() & 0x1F;
+	}
+	return port_id;
+}
+
+inline static char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_ringparam ring_param;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1) {
+		keep_traffic = atoi(argv[1]);
+	}
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0) {
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+	}
+
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0) {
+				netdev_net_set_rx_mode(port_id);
+			} else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id ++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port #%d!!!\n", port_id);
+			} else {
+				printf("\nPort #%d mac addr is %s \n", port_id,
+					mac_addr_str(mac_addr));
+			}
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s fw_version: %s bus_info=%s\n"
+					"reg-size(bytes)=%d eeprom-size=%d\n", drvinfo.driver,
+					drvinfo.version, drvinfo.fw_version, drvinfo.bus_info,
+					drvinfo.regdump_len, drvinfo.eedump_len);
+			}
+
+			if ((count =netdev_ethtool_get_regs_len(port_id)) <= 0) {
+				printf("There are no registers available from device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers for dump\n", count);
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF, sizeof(struct ethtool_regs));
+				if ((count =netdev_ethtool_get_regs(port_id, &regs, reply_data))) {
+					printf("failed to run ethtool_get_regs from port #%d (error-code=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x version=0x%x\n",
+						int_ptr[0], int_ptr[10], regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			if (!is_vf_port(port_id)) {
+				if((count = netdev_ethtool_get_eeprom_len(0)) == 0)
+					printf("fail to retrieve eeprom count from port #%d\n", port_id);
+				else {
+
+					printf("eeprom size is %d bytes\n", count);
+					eeprom.offset = 20;
+					eeprom.len = 80;
+					eeprom.magic = 0;
+					if (netdev_ethtool_get_eeprom(port_id, &eeprom, reply_data)) {
+						printf("Fail to read eeprom from port #%d\n", port_id);
+					} else {
+						int i;
+						uint16_t *word = (uint16_t *)((void*)reply_data);
+
+						printf("eeprom-magic: %x; read-back eeprom data ...\n", eeprom.magic);
+						for(i = 0; i < (int)(eeprom.len >> 1); i++) {
+							if (((i+1) %16) == 0)
+								printf("\n");
+							printf("%4x ", word[i]);
+						}
+						printf("\n");
+					}
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id ++) {
+		if (netdev_net_get_mac_addr(port_id, to_mac_type(mac_addr))) {
+			printf("Fail to get mac addr from port #%d!!!\n", port_id);
+		} else {
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+		}
+
+		if (!netdev_net_validate_addr(port_id, to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr, MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n", mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id, to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id, to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign, device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n", port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n", port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets, last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets, last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes, last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes, last_ts, ts));
+
+		if (!is_vf_port(port_id)
+			|| (netdev_ethtool_get_regs_len(port_id) == 0)
+			) {
+			printf("Getting ringparam from a %s\n", is_vf_port(port_id)?"VF":"PF");
+
+			if (netdev_ethtool_get_ringparam(port_id, &ring_param)) {
+				printf("Fail to retrieve descriptor ring info!!!\n");
+			} else {
+				printf("Rx/Tx descriptor ring info for queue 0!!!\n");
+				printf("Tx-max=%d Tx-pending=%d Rx-max=%d Rx-pend=%d\n",
+					ring_param.tx_max_pending, ring_param.tx_pending,
+					ring_param.rx_max_pending, ring_param.rx_pending);
+			}
+		}
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		for(port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for(port_id = 0; port_id < num_of_ports; port_id++) {
+			if (!is_vf_port(port_id)) {
+				link_up = netdev_ethtool_get_link(port_id);
+				if (!link_up) {
+					eeprom.offset = 20;
+					eeprom.len = 80;
+					if (netdev_ethtool_get_eeprom(port_id, &eeprom,
+						reply_data)) {
+						printf("failed to read eeprom break from post-run"
+							" testing!!!\n");
+						break;
+					}
+					if (netdev_ethtool_set_eeprom(port_id, &eeprom,
+						reply_data)) {
+						printf("Fail to write read-back data to eeprom!!!\n");
+						break;
+					}
+					/* checking mtu setting */
+					if (netdev_net_change_mtu(port_id, mtu))
+						printf("failed to set mtu to %d\n", mtu);
+
+					/* add/remove vlan to vid */
+					if (netdev_net_vlan_rx_add_vid(port_id, 0) == 0) {
+						if (netdev_net_vlan_rx_kill_vid(port_id, 0)) {
+							printf("fail to kill vid 0 vlan\n");
+							break;
+						}
+					} else {
+						printf("fail to add vid 0 vlan\n");
+						break;
+					}
+
+					/* testing pause parameter get/set functions */
+					if (netdev_ethtool_get_pauseparam(port_id, &pause_param)) {
+						printf("fail to get pause param\n");
+						break;
+					}
+					printf("pause setup: autoneg: %d tx_pause: "
+						"%d rx_pause: %d\n",
+						pause_param.autoneg, pause_param.tx_pause,
+						pause_param.rx_pause);
+
+					if (netdev_ethtool_set_pauseparam(port_id, &pause_param)) {
+						printf("fail to set pause param\n");
+						break;
+					}
+
+				}
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0);
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v6 0/4] User-space Ethtool
  2015-06-12 22:03 ` [dpdk-dev] [PATCH v6 0/4] User-space Ethtool Liang-Min Larry Wang
                     ` (3 preceding siblings ...)
  2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
@ 2015-06-13  0:21   ` Andrew Harvey (agh)
  4 siblings, 0 replies; 174+ messages in thread
From: Andrew Harvey (agh) @ 2015-06-13  0:21 UTC (permalink / raw)
  To: Liang-Min Larry Wang, dev

On 6/12/15, 3:03 PM, "Liang-Min Larry Wang" <liang-min.wang@intel.com>
wrote:

>This implementation is designed to provide a familar interface for
>applications that rely on kernel-space driver to support ethtool_op and
>net_device_op for device management. The initial implementation focuses
>on ops that can be implemented through existing netdev APIs. More ops
>will be supported in latter release.
>
>v6 change:
>- Rebase to match new changes over dpdk repository (librte_ether)
>v5 change:
>- Change API name from 'leng' to 'length'
>- Remove unused data structure rte_dev_vf_info
>- Remove placeholder API rte_eth_dev_set_ringparam
>- Clean up set_mac_addr implementation
>v4 change:
>- Add rte_eth_xxx apis and respective ops over igb and ixgbe
>  to support ethtool and net device alike ops
>- Add an example to demonstrate the use of ethtool library
>v3 change:
>- Fix a build issue
>v2 change:
>- Implement rte_eth_dev_default_mac_addr_set through
>dev_ops::mac_addr_set so it would support NIC devices other than ixgbe
>and igb
>
>Liang-Min Larry Wang (4):
>  ethdev: add apis to support access device info
>  ixgbe: add ops to support ethtool ops
>  igb: add ops to support ethtool ops
>  examples: new example: l2fwd-ethtool
>
> drivers/net/e1000/igb_ethdev.c                   |  186 ++++
> drivers/net/e1000/igb_regs.h                     |  217 +++++
> drivers/net/ixgbe/ixgbe_ethdev.c                 |  202 +++++
> drivers/net/ixgbe/ixgbe_regs.h                   |  357 ++++++++
> drivers/net/ixgbe/ixgbe_rxtx.c                   |   16 +
> drivers/net/ixgbe/ixgbe_rxtx.h                   |    1 +
> examples/l2fwd-ethtool/Makefile                  |   55 ++
> examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
> examples/l2fwd-ethtool/l2fwd-app/main.c          | 1052
>++++++++++++++++++++++
> examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  821 +++++++++++++++++
> examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  153 ++++
> examples/l2fwd-ethtool/lib/Makefile              |   55 ++
> examples/l2fwd-ethtool/lib/rte_ethtool.c         |  326 +++++++
> examples/l2fwd-ethtool/lib/rte_ethtool.h         |  412 +++++++++
> examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
> examples/l2fwd-ethtool/nic-control/nic_control.c |  427 +++++++++
> lib/librte_ether/Makefile                        |    1 +
> lib/librte_ether/rte_eth_dev_info.h              |   67 ++
> lib/librte_ether/rte_ethdev.c                    |  134 +++
> lib/librte_ether/rte_ethdev.h                    |  144 +++
> lib/librte_ether/rte_ether_version.map           |    7 +
> 21 files changed, 4746 insertions(+)
> create mode 100644 drivers/net/e1000/igb_regs.h
> create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
> create mode 100644 examples/l2fwd-ethtool/Makefile
> create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
> create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
> create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
> create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
> create mode 100644 examples/l2fwd-ethtool/lib/Makefile
> create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
> create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
> create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
> create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
> create mode 100644 lib/librte_ether/rte_eth_dev_info.h
>
>-- 
>2.1.4

Acked-by: Andrew Harvey (agh) <agh@cisco.com>

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v6 1/4] ethdev: add apis to support access device info
  2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-13 23:25     ` David Harton (dharton)
  0 siblings, 0 replies; 174+ messages in thread
From: David Harton (dharton) @ 2015-06-13 23:25 UTC (permalink / raw)
  To: Liang-Min Larry Wang, dev



> -----Original Message-----
> From: Liang-Min Larry Wang [mailto:liang-min.wang@intel.com]
> Sent: Friday, June 12, 2015 6:03 PM
> To: dev@dpdk.org
> Cc: Andrew Harvey (agh); David Harton (dharton); Roger Melton (rmelton);
> Liang-Min Larry Wang
> Subject: [PATCH v6 1/4] ethdev: add apis to support access device info
> 
> add new apis:
> - rte_eth_dev_default_mac_addr_set
> - rte_eth_dev_reg_length
> - rte_eth_dev_reg_info
> - rte_eth_dev_eeprom_length
> - rte_eth_dev_get_eeprom
> - rte_eth_dev_set_eeprom
> - rte_eth_dev_get_ringparam
> 
> to enable reading device parameters (mac-addr, register,
> eeprom, ring) based upon ethtool alike
> data parameter specification.
> 
> Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> ---
>  lib/librte_ether/Makefile              |   1 +
>  lib/librte_ether/rte_eth_dev_info.h    |  67 +++++++++++++++
>  lib/librte_ether/rte_ethdev.c          | 134
> ++++++++++++++++++++++++++++++
>  lib/librte_ether/rte_ethdev.h          | 144
> +++++++++++++++++++++++++++++++++
>  lib/librte_ether/rte_ether_version.map |   7 ++
>  5 files changed, 353 insertions(+)
>  create mode 100644 lib/librte_ether/rte_eth_dev_info.h
> 
> diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
> index c0e5768..05209e9 100644
> --- a/lib/librte_ether/Makefile
> +++ b/lib/librte_ether/Makefile
> @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
>  SYMLINK-y-include += rte_ether.h
>  SYMLINK-y-include += rte_ethdev.h
>  SYMLINK-y-include += rte_eth_ctrl.h
> +SYMLINK-y-include += rte_eth_dev_info.h
> 
>  # this lib depends upon:
>  DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring
> lib/librte_mbuf
> diff --git a/lib/librte_ether/rte_eth_dev_info.h
> b/lib/librte_ether/rte_eth_dev_info.h
> new file mode 100644
> index 0000000..1cf2c23
> --- /dev/null
> +++ b/lib/librte_ether/rte_eth_dev_info.h
> @@ -0,0 +1,67 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> + *   All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above
> copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of Intel Corporation nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
> USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#ifndef _RTE_ETH_DEV_INFO_H_
> +#define _RTE_ETH_DEV_INFO_H_
> +
> +/*
> + * Placeholder for accessing device registers
> + */
> +struct rte_dev_reg_info {
> +	void *buf; /**< Buffer for register */
> +	uint32_t offset; /**< Offset for 1st register to fetch */
> +	uint32_t leng; /**< Number of registers to fetch */
> +	uint32_t version; /**< Device version */
> +};
> +
> +/*
> + * Placeholder for accessing device eeprom
> + */
> +struct rte_dev_eeprom_info {
> +	void *buf; /**< Buffer for eeprom */
> +	uint32_t offset; /**< Offset for 1st eeprom location to access */
> +	uint32_t leng; /**< Length of eeprom region to access */
> +	uint32_t magic; /**< Device ID */
> +};
> +
> +/*
> + * Placeholder for accessing device ring parameters
> + */
> +struct rte_dev_ring_info {
> +	uint32_t rx_pending; /**< Number of outstanding Rx ring */
> +	uint32_t tx_pending; /**< Number of outstanding Tx ring */
> +	uint32_t rx_max_pending; /**< Maximum number of outstanding Rx ring
> */
> +	uint32_t tx_max_pending; /**< Maximum number of outstanding Tx ring
> */
> +};
> +
> +#endif /* _RTE_ETH_DEV_INFO_H_ */
> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
> index e13fde5..27c9215 100644
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -2751,6 +2751,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct
> ether_addr *addr)
>  }
> 
>  int
> +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr
> *addr)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if (!is_valid_assigned_ether_addr(addr))
> +		return -EINVAL;
> +
> +	dev = &rte_eth_devices[port_id];
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
> +
> +	/* Update default address in NIC data structure */
> +	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
> +
> +	(*dev->dev_ops->mac_addr_set)(dev, addr);
> +
> +	return 0;
> +}
> +
> +int
>  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
>  				uint16_t rx_mode, uint8_t on)
>  {
> @@ -3644,3 +3668,113 @@ rte_eth_dev_set_mc_addr_list(uint8_t port_id,
>  	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_mc_addr_list, -ENOTSUP);
>  	return dev->dev_ops->set_mc_addr_list(dev, mc_addr_set, nb_mc_addr);
>  }
> +
> +int
> +rte_eth_dev_reg_length(uint8_t port_id)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	dev = &rte_eth_devices[port_id];
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
> +	return (*dev->dev_ops->get_reg_length)(dev);
> +}
> +
> +int
> +rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
> +	return (*dev->dev_ops->get_reg)(dev, info);
> +}
> +
> +int
> +rte_eth_dev_eeprom_length(uint8_t port_id)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
> +	return (*dev->dev_ops->get_eeprom_length)(dev);
> +}
> +
> +int
> +rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
> +	return (*dev->dev_ops->get_eeprom)(dev, info);
> +}
> +
> +int
> +rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
> +	return (*dev->dev_ops->set_eeprom)(dev, info);
> +}
> +
> +int
> +rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info
> *info)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}
> +
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -ENOTSUP);
> +	return (*dev->dev_ops->get_ringparam)(dev, info);
> +}
> diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
> index 04c192d..c9e629d 100644
> --- a/lib/librte_ether/rte_ethdev.h
> +++ b/lib/librte_ether/rte_ethdev.h
> @@ -182,6 +182,7 @@ extern "C" {
>  #include <rte_devargs.h>
>  #include "rte_ether.h"
>  #include "rte_eth_ctrl.h"
> +#include "rte_eth_dev_info.h"
> 
>  struct rte_mbuf;
> 
> @@ -1233,6 +1234,32 @@ typedef int (*eth_set_mc_addr_list_t)(struct
> rte_eth_dev *dev,
>  				      uint32_t nb_mc_addr);
>  /**< @internal set the list of multicast addresses on an Ethernet device
> */
> 
> +typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
> +/**< @internal Retrieve device register count  */
> +
> +typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_reg_info *info);
> +/**< @internal Retrieve registers  */
> +
> +typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
> +/**< @internal Retrieve eeprom size  */
> +
> +typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_eeprom_info *info);
> +/**< @internal Retrieve eeprom data  */
> +
> +typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_eeprom_info *info);
> +/**< @internal Program eeprom data  */
> +
> +typedef int (*eth_get_ringparam_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_ring_info *info);
> +/**< @internal Retrieve device ring descriptor  */
> +
> +typedef int (*eth_set_ringparam_t)(struct rte_eth_dev *dev,
> +				struct rte_dev_ring_info *info);
> +/**< @internal Set device ring descriptor  */
> +
>  #ifdef RTE_NIC_BYPASS
> 
>  enum {
> @@ -1372,6 +1399,21 @@ struct eth_dev_ops {
>  	reta_update_t reta_update;
>  	/** Query redirection table. */
>  	reta_query_t reta_query;
> +
> +	eth_get_reg_length_t get_reg_length;
> +	/**< Get # of registers */
> +	eth_get_reg_t get_reg;
> +	/**< Get registers */
> +	eth_get_eeprom_length_t get_eeprom_length;
> +	/**< Get eeprom length */
> +	eth_get_eeprom_t get_eeprom;
> +	/**< Get eeprom data */
> +	eth_set_eeprom_t set_eeprom;
> +	/**< Set eeprom */
> +	eth_get_ringparam_t get_ringparam;
> +	/**< Get descriptor ring parameters */
> +	eth_set_ringparam_t set_ringparam;
> +	/**< Set descriptor ring parameters */
>    /* bypass control */
>  #ifdef RTE_NIC_BYPASS
>    bypass_init_t bypass_init;
> @@ -2987,6 +3029,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct
> ether_addr *mac_addr,
>  int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr
> *mac_addr);
> 
>  /**
> + * Set the default MAC address.
> + *
> + * @param port
> + *   The port identifier of the Ethernet device.
> + * @param mac_addr
> + *   New default MAC address.
> + * @return
> + *   - (0) if successful, or *mac_addr* didn't exist.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port* invalid.
> + */
> +int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr
> *mac_addr);
> +
> +/**
>   * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet
> device.
>   *
>   * @param port
> @@ -3616,6 +3672,94 @@ int rte_eth_remove_rx_callback(uint8_t port_id,
> uint16_t queue_id,
>  int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
>  		struct rte_eth_rxtx_callback *user_cb);
> 
> +/**
> + * Retrieve number of available registers for access
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @return
> + *   - (>=0) number of registers if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_reg_length(uint8_t port_id);
> +
> +/**
> + * Retrieve device registers and register attributes
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes buffer for register data and attribute to be
> filled.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
> +
> +/**
> + * Retrieve size of device EEPROM
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @return
> + *   - (>=0) EEPROM size if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_eeprom_length(uint8_t port_id);
> +
> +/**
> + * Retrieve EEPROM and EEPROM attribute
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes buffer for return EEPROM data and
> + *   EEPROM attributes to be filled.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info
> *info);
> +
> +/**
> + * Program EEPROM with provided data
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes EEPROM data for programming and
> + *   EEPROM attributes to be filled
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info
> *info);
> +
> +/**
> + * Retrieve device descriptor ring information
> + *
> + * @param port_id
> + *   The port identifier of the Ethernet device.
> + * @param info
> + *   The template includes device ring descriptor usage information.
> + * @return
> + *   - (0) if successful.
> + *   - (-ENOTSUP) if hardware doesn't support.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - others depends on the specific operations implementation.
> + */
> +int rte_eth_dev_get_ringparam(uint8_t port_id, struct rte_dev_ring_info
> *info);
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/lib/librte_ether/rte_ether_version.map
> b/lib/librte_ether/rte_ether_version.map
> index 012a82e..f75f3d1 100644
> --- a/lib/librte_ether/rte_ether_version.map
> +++ b/lib/librte_ether/rte_ether_version.map
> @@ -102,6 +102,13 @@ DPDK_2.0 {
>  	rte_eth_tx_queue_setup;
>  	rte_eth_xstats_get;
>  	rte_eth_xstats_reset;
> +	rte_eth_dev_default_mac_addr_set;
> +	rte_eth_dev_reg_length;
> +	rte_eth_dev_reg_info;
> +	rte_eth_dev_eeprom_length;
> +	rte_eth_dev_get_eeprom;
> +	rte_eth_dev_set_eeprom;
> +	rte_eth_dev_get_ringparam;
> 
>  	local: *;
>  };
> --
> 2.1.4

Acked-by: David Harton (dharton) <dharton@cisco.com>

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-12 12:30             ` Ananyev, Konstantin
@ 2015-06-15 13:26               ` Wang, Liang-min
  2015-06-15 13:45                 ` Ananyev, Konstantin
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-15 13:26 UTC (permalink / raw)
  To: Ananyev, Konstantin, dev



> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Friday, June 12, 2015 8:31 AM
> To: Wang, Liang-min; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> device info
> 
> 
> 
> > -----Original Message-----
> > From: Wang, Liang-min
> > Sent: Thursday, June 11, 2015 10:51 PM
> > To: Ananyev, Konstantin; dev@dpdk.org
> > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > access device info
> >
> >
> >
> > > -----Original Message-----
> > > From: Ananyev, Konstantin
> > > Sent: Thursday, June 11, 2015 9:07 AM
> > > To: Wang, Liang-min; dev@dpdk.org
> > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > access device info
> > >
> > >
> > >
> > > > -----Original Message-----
> > > > From: Wang, Liang-min
> > > > Sent: Thursday, June 11, 2015 1:58 PM
> > > > To: Ananyev, Konstantin; dev@dpdk.org
> > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > access device info
> > > >
> > > > Hi Konstantin,
> > > >
> > > > > -----Original Message-----
> > > > > From: Ananyev, Konstantin
> > > > > Sent: Thursday, June 11, 2015 8:26 AM
> > > > > To: Wang, Liang-min; dev@dpdk.org
> > > > > Cc: Wang, Liang-min
> > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > support access device info
> > > > >
> > > > > Hi Larry,
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Liang-Min
> > > > > > Larry Wang
> > > > > > Sent: Wednesday, June 10, 2015 4:10 PM
> > > > > > To: dev@dpdk.org
> > > > > > Cc: Wang, Liang-min
> > > > > > Subject: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > > > access device info
> > > > > >
> > > > > > add new apis:
> > > > > > - rte_eth_dev_default_mac_addr_set
> > > > > > - rte_eth_dev_reg_leng
> > > > > > - rte_eth_dev_reg_info
> > > > > > - rte_eth_dev_eeprom_leng
> > > > > > - rte_eth_dev_get_eeprom
> > > > > > - rte_eth_dev_set_eeprom
> > > > > > - rte_eth_dev_get_ringparam
> > > > > > - rte_eth_dev_set_ringparam
> > > > > >
> > > > > > to enable reading device parameters (mac-addr, register,
> > > > > > eeprom,
> > > > > > ring) based upon ethtool alike data parameter specification.
> > > > > >
> > > > > > Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> > > > > > ---
> > > > > >  lib/librte_ether/Makefile              |   1 +
> > > > > >  lib/librte_ether/rte_eth_dev_info.h    |  80 +++++++++++++++++
> > > > > >  lib/librte_ether/rte_ethdev.c          | 159
> > > > > +++++++++++++++++++++++++++++++++
> > > > > >  lib/librte_ether/rte_ethdev.h          | 158
> > > > > ++++++++++++++++++++++++++++++++
> > > > > >  lib/librte_ether/rte_ether_version.map |   8 ++
> > > > > >  5 files changed, 406 insertions(+)  create mode 100644
> > > > > > lib/librte_ether/rte_eth_dev_info.h
> > > > > >
> > > > > > diff --git a/lib/librte_ether/Makefile
> > > > > > b/lib/librte_ether/Makefile index c0e5768..05209e9 100644
> > > > > > --- a/lib/librte_ether/Makefile
> > > > > > +++ b/lib/librte_ether/Makefile
> > > > > > @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c  SYMLINK-y-include +=
> > > > > > rte_ether.h  SYMLINK-y-include += rte_ethdev.h
> > > > > > SYMLINK-y-include
> > > > > > += rte_eth_ctrl.h
> > > > > > +SYMLINK-y-include += rte_eth_dev_info.h
> > > > > >
> > > > > >  # this lib depends upon:
> > > > > >  DEPDIRS-y += lib/librte_eal lib/librte_mempool
> > > > > > lib/librte_ring lib/librte_mbuf diff --git
> > > > > > a/lib/librte_ether/rte_eth_dev_info.h
> > > > > > b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > new file mode 100644
> > > > > > index 0000000..002c4b5
> > > > > > --- /dev/null
> > > > > > +++ b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > @@ -0,0 +1,80 @@
> > > > > > +/*-
> > > > > > + *   BSD LICENSE
> > > > > > + *
> > > > > > + *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> > > > > > + *   All rights reserved.
> > > > > > + *
> > > > > > + *   Redistribution and use in source and binary forms, with or
> without
> > > > > > + *   modification, are permitted provided that the following
> conditions
> > > > > > + *   are met:
> > > > > > + *
> > > > > > + *     * Redistributions of source code must retain the above
> copyright
> > > > > > + *       notice, this list of conditions and the following disclaimer.
> > > > > > + *     * Redistributions in binary form must reproduce the above
> > > copyright
> > > > > > + *       notice, this list of conditions and the following disclaimer in
> > > > > > + *       the documentation and/or other materials provided with the
> > > > > > + *       distribution.
> > > > > > + *     * Neither the name of Intel Corporation nor the names of its
> > > > > > + *       contributors may be used to endorse or promote products
> > > derived
> > > > > > + *       from this software without specific prior written permission.
> > > > > > + *
> > > > > > + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > > > > CONTRIBUTORS
> > > > > > + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> INCLUDING,
> > > BUT
> > > > > NOT
> > > > > > + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
> AND
> > > > > FITNESS FOR
> > > > > > + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
> THE
> > > > > COPYRIGHT
> > > > > > + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
> INDIRECT,
> > > > > INCIDENTAL,
> > > > > > + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> > > (INCLUDING,
> > > > > BUT NOT
> > > > > > + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> SERVICES;
> > > > > LOSS OF USE,
> > > > > > + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> > > CAUSED
> > > > > AND ON ANY
> > > > > > + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> LIABILITY,
> > > OR
> > > > > TORT
> > > > > > + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> WAY
> > > OUT
> > > > > OF THE USE
> > > > > > + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> SUCH
> > > > > DAMAGE.
> > > > > > + */
> > > > > > +
> > > > > > +#ifndef _RTE_ETH_DEV_INFO_H_
> > > > > > +#define _RTE_ETH_DEV_INFO_H_
> > > > > > +
> > > > > > +
> > > > > > +/*
> > > > > > + * Placeholder for accessing device registers  */ struct
> > > > > > +rte_dev_reg_info {
> > > > > > +	void *buf; /**< Buffer for register */
> > > > > > +	uint32_t offset; /**< Offset for 1st register to fetch */
> > > > > > +	uint32_t leng; /**< Number of registers to fetch */
> > > > > > +	uint32_t version; /**< Device version */ };
> > > > > > +
> > > > > > +/*
> > > > > > + * Placeholder for accessing device eeprom  */ struct
> > > > > > +rte_dev_eeprom_info {
> > > > > > +	void *buf; /**< Buffer for eeprom */
> > > > > > +	uint32_t offset; /**< Offset for 1st eeprom location to access
> */
> > > > > > +	uint32_t leng; /**< Length of eeprom region to access */
> > > > > > +	uint32_t magic; /**< Device ID */ };
> > > > > > +
> > > > > > +/*
> > > > > > + * Placeholder for accessing device ring parameters  */
> > > > > > +struct rte_dev_ring_info {
> > > > > > +	uint32_t rx_pending; /**< Number of outstanding Rx ring */
> > > > > > +	uint32_t tx_pending; /**< Number of outstanding Tx ring */
> > > > > > +	uint32_t rx_max_pending; /**< Maximum number of
> outstanding
> > > > > > +Rx
> > > > > ring */
> > > > > > +	uint32_t tx_max_pending; /**< Maximum number of
> outstanding
> > > > > > +Tx
> > > > > ring
> > > > > > +*/ };
> > > > > > +
> > > > > > +/*
> > > > > > + * A data structure captures information as defined in struct
> > > > > > +ifla_vf_info
> > > > > > + * for user-space api
> > > > > > + */
> > > > > > +struct rte_dev_vf_info {
> > > > > > +	uint32_t vf;
> > > > > > +	uint8_t mac[ETHER_ADDR_LEN];
> > > > > > +	uint32_t vlan;
> > > > > > +	uint32_t tx_rate;
> > > > > > +	uint32_t spoofchk;
> > > > > > +};
> > > > >
> > > > >
> > > > > Wonder what that structure is for?
> > > > > I can't see it used in any function below?
> > > > >
> > > >
> > > > Good catch, this is designed for other ethtool ops that I did not
> > > > include in
> > > this release, I will remove this from next fix.
> > > >
> > > > > > +
> > > > > > +#endif /* _RTE_ETH_DEV_INFO_H_ */
> > > > > > diff --git a/lib/librte_ether/rte_ethdev.c
> > > > > > b/lib/librte_ether/rte_ethdev.c index 5a94654..186e85c 100644
> > > > > > --- a/lib/librte_ether/rte_ethdev.c
> > > > > > +++ b/lib/librte_ether/rte_ethdev.c
> > > > > > @@ -2751,6 +2751,32 @@ rte_eth_dev_mac_addr_remove(uint8_t
> > > > > port_id,
> > > > > > struct ether_addr *addr)  }
> > > > > >
> > > > > >  int
> > > > > > +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct
> > > > > > +ether_addr
> > > > > > +*addr) {
> > > > > > +	struct rte_eth_dev *dev;
> > > > > > +	const int index = 0;
> > > > > > +	const uint32_t pool = 0;
> > > > > > +
> > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> port_id);
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	dev = &rte_eth_devices[port_id];
> > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> >mac_addr_remove, -
> > > > > ENOTSUP);
> > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -
> > > > > ENOTSUP);
> > > > > > +
> > > > > > +	/* Update NIC default MAC address*/
> > > > > > +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> > > > > > +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> > > > > > +
> > > > > > +	/* Update default address in NIC data structure */
> > > > > > +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> > > > > > +
> > > > > > +	return 0;
> > > > > > +}
> > > > > > +
> > > > > > +int
> > > > > >  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
> > > > > >  				uint16_t rx_mode, uint8_t on)  { @@
> -3627,3
> > > +3653,136 @@
> > > > > > rte_eth_remove_tx_callback(uint8_t port_id,
> > > > > uint16_t queue_id,
> > > > > >  	/* Callback wasn't found. */
> > > > > >  	return -EINVAL;
> > > > > >  }
> > > > > > +
> > > > > > +int
> > > > > > +rte_eth_dev_reg_leng(uint8_t port_id) {
> > > > > > +	struct rte_eth_dev *dev;
> > > > > > +
> > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> port_id);
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length,
> -
> > > > > ENOTSUP);
> > > > > > +	return (*dev->dev_ops->get_reg_length)(dev);
> > > > > > +}
> > > > > > +
> > > > > > +int
> > > > > > +rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info
> > > > > > +*info) {
> > > > > > +	struct rte_eth_dev *dev;
> > > > > > +
> > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> port_id);
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -
> ENOTSUP);
> > > > > > +	return (*dev->dev_ops->get_reg)(dev, info); }
> > > > >
> > > > > Seems that *get_reg* stuff, will be really good addition for
> > > > > DPDK debugging abilities.
> > > > > Though, I'd suggest we change it a bit to make more generic and
> flexible:
> > > > >
> > > > > Introduce rte_eth_reg_read/rte_eth_reg_write(),
> > > > > or probably even better rte_pcidev_reg_read
> > > > > /rte_pcidev_reg_write at
> > > EAL.
> > > > > Something similar to what port_pci_reg_read/port_pci_reg_write()
> > > > > are doing now at testpmd.h.
> > > > >
> > > > > struct rte_pcidev_reg_info {
> > > > >    const char *name;
> > > > >    uint32_t endianes, bar, offset, size, count; };
> > > > >
> > > > > int rte_pcidev_reg_read(const struct rte_pci_device *, const
> > > > > struct rte_pcidev_reg_info *, uint64_t *reg_val);
> > > > >
> > > > > Then:
> > > > > int rte_eth_dev_get_reg_info(port_id, const struct
> > > > > rte_pcidev_reg_info **info);
> > > > >
> > > > > So each device would store in info a pointer to an array of it's
> > > > > register descriptions (finished by zero elem?).
> > > > >
> > > > > Then your ethtool (or any other upper layer) can do the
> > > > > following to read all device regs:
> > > > >
> > > >
> > > > The proposed reg info structure allows future improvement to
> > > > support
> > > individual register read/write.
> > > > Also, because each NIC device has a very distinguish register definition.
> > > > So, the plan is to have more comprehensive interface to support
> > > > query operation (for example, register name) before introduce
> > > > individual/group
> > > register access.
> > > > Points taken, the support will be in future release.
> > >
> > > Sorry, didn't get you.
> > > So you are ok to make these changes in next patch version?
> > >
> > I would like to get a consensus from dpdk community on how to provide
> register information.
> 
> Well, that' ok, but if it is just a trial patch that is not intended to be applied,
> then you should mark it as RFC.
> 
> > Currently, it's designed for debug dumping. The register information is very
> hardware dependent.
> > Need to consider current supported NIC device and future devices for
> DPDK, so we won't make it a bulky interface.
> 
> Ok, could you explain what exactly  concerns you in the approach described
> above?
> What part you feel is bulky?
> 
> > > >
> > > > > const struct rte_eth_dev_reg_info *reg_info; struct
> > > > > rte_eth_dev_info dev_info;
> > > > >
> > > > > rte_eth_dev_info_get(pid, &dev_info);
> > > > > rte_eth_dev_get_reg_info(port_id, &reg_info);
> > > > >
> > > > > for (i = 0; reg_info[i].name != NULL; i++) {
> > > > >    ...
> > > > >    rte_pcidev_read_reg(dev_info. pci_dev, reg_info[i], &v);
> > > > >   ..
> > > > > }
> > > > >
> > > > > > +
> > > > > > +int
> > > > > > +rte_eth_dev_eeprom_leng(uint8_t port_id) {
> > > > > > +	struct rte_eth_dev *dev;
> > > > > > +
> > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> port_id);
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> >get_eeprom_length, -
> > > > > ENOTSUP);
> > > > > > +	return (*dev->dev_ops->get_eeprom_length)(dev);
> > > > > > +}
> > > > > > +
> > > > > > +int
> > > > > > +rte_eth_dev_get_eeprom(uint8_t port_id, struct
> > > > > > +rte_dev_eeprom_info
> > > > > > +*info) {
> > > > > > +	struct rte_eth_dev *dev;
> > > > > > +
> > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> port_id);
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -
> > > > > ENOTSUP);
> > > > > > +	return (*dev->dev_ops->get_eeprom)(dev, info); }
> > > > > > +
> > > > > > +int
> > > > > > +rte_eth_dev_set_eeprom(uint8_t port_id, struct
> > > > > > +rte_dev_eeprom_info
> > > > > > +*info) {
> > > > > > +	struct rte_eth_dev *dev;
> > > > > > +
> > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> port_id);
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -
> > > > > ENOTSUP);
> > > > > > +	return (*dev->dev_ops->set_eeprom)(dev, info); }
> > > > > > +
> > > > > > +int
> > > > > > +rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > > > > +rte_dev_ring_info
> > > > > > +*info) {
> > > > > > +	struct rte_eth_dev *dev;
> > > > > > +
> > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> port_id);
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > +		return -ENODEV;
> > > > > > +	}
> > > > > > +
> > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> > > > > ENOTSUP);
> > > > > > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> > > > >
> > > > > I think it will be a useful addition to the ethdev API  to have
> > > > > an ability to retrieve current RX/TX queue parameters.
> > > > > Though again, it need to be more generic, so it could be useful
> > > > > for
> > > > > non- ethtool upper layer too.
> > > > > So I suggest to modify it a bit.
> > > > > Something like that:
> > > > >
> > > > > struct rte_eth_tx_queue_info {
> > > > >     struct rte_eth_txconf txconf;
> > > > >     uint32_t nb_tx_desc;
> > > > >     uint32_t nb_max_tx_desc; /*max allowable TXDs for that queue */
> > > > >     uint32_t nb_tx_free;            /* number of free TXDs at the moment
> of
> > > call.
> > > > > */
> > > > >     /* other tx queue data. */
> > > > > };
> > > > >
> > > > > int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> > > > > rte_eth_tx_queue_info *qinfo)
> > > > >
> > > > > Then, your upper layer ethtool wrapper, can implement yours
> > > > > ethtool_get_ringparam() by:
> > > > >
> > > > >  ...
> > > > >  struct rte_eth_tx_queue_info qinfo;
> > > > > rte_ethdev_get_tx_queue_info(port, 0, &qinfo);
> > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > rte_eth_rx_queue_count(port, 0);
> > > > >
> > > > > Or probably even:
> > > > > ring_param->tx_pending = qinfo.nb_tx_desc - qinfo.nb_tx_free;
> > > > >
> > > > > Same for RX.
> > > > >
> > > > For now, this descriptor ring information is used by the ethtool op.
> > > > To make this interface simple, i.e. caller doesn't need to access
> > > > other
> > > queue information.
> > >
> > > I just repeat what I said to you in off-line conversation:
> > > ethdev API is not equal ethtool API.
> > > It is ok to add  a new function/structure to ethdev if it really
> > > needed, but we should do mechanical one to one copy.
> > > It is much better to add  a function/structure that would be more
> > > generic, and suit other users, not only ethtool.
> > > There is no point to have dozen functions in rte_ethdev API
> > > providing similar information.
> > > BTW, I don't see how API I proposed is much more  complex, then yours
> one.
> > The ring parameter is a run-time information which is different than data
> structure described in this discussion.
> 
> I don't see how they are different.
> Looking at ixgbe_get_ringparam(), it returns:
> rx_max_pending - that's a static IXGBE PMD value (max possible number of
> RXDs per one queue).
> rx_pending - number of RXD currently in use by the HW for queue 0 (that
> information can be changed at each call).
> 
> With the approach I suggesting - you can get same information for each RX
> queue by calling rte_ethdev_get_rx_queue_info() and
> rte_eth_rx_queue_count().
> Plus you are getting other RX queue data.
> 
> Another thing - what is practical usage of the information you retrieving now
> by get_ringparam()?
> Let say it returned to you: rx_max_pending=4096; rx_pending=128; How that
> information would help to understand what is going on with the device?
> Without knowing  value of nb_tx_desc for the queue, you can't say is you
> queue full or not.
> Again, it could be that all your traffic going through some other queue (not
> 0).
> So from my point rte_eth_dev_get_ringparam()  usage is very limited, and
> doesn't provide enough information about current queue state.
> 
> Same thing applies for TX.
> 

After careful review the suggestion in this comment, and review the existing dpdk source code. 
I came to realize that neither rte_ethdev_get_rx_queue_info, rte_ethdev_get_tx_queue_info, struct rte_eth_rx_queue_info and struct rte_eth_tx_queue_info are available in the existing dpdk source code. I could not make a patch based upon a set of non-existent API and data structure.

> > It's the desire of this patch to separate each data structure to avoid cross
> dependency.
> 
> That's too cryptic to me.
> Could you explain what cross dependency you are talking about?
> 
> Konstantin

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-15 13:26               ` Wang, Liang-min
@ 2015-06-15 13:45                 ` Ananyev, Konstantin
  2015-06-15 14:47                   ` Wang, Liang-min
  2015-06-15 16:05                   ` David Harton (dharton)
  0 siblings, 2 replies; 174+ messages in thread
From: Ananyev, Konstantin @ 2015-06-15 13:45 UTC (permalink / raw)
  To: Wang, Liang-min, dev



> -----Original Message-----
> From: Wang, Liang-min
> Sent: Monday, June 15, 2015 2:26 PM
> To: Ananyev, Konstantin; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
> 
> 
> 
> > -----Original Message-----
> > From: Ananyev, Konstantin
> > Sent: Friday, June 12, 2015 8:31 AM
> > To: Wang, Liang-min; dev@dpdk.org
> > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> > device info
> >
> >
> >
> > > -----Original Message-----
> > > From: Wang, Liang-min
> > > Sent: Thursday, June 11, 2015 10:51 PM
> > > To: Ananyev, Konstantin; dev@dpdk.org
> > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > access device info
> > >
> > >
> > >
> > > > -----Original Message-----
> > > > From: Ananyev, Konstantin
> > > > Sent: Thursday, June 11, 2015 9:07 AM
> > > > To: Wang, Liang-min; dev@dpdk.org
> > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > access device info
> > > >
> > > >
> > > >
> > > > > -----Original Message-----
> > > > > From: Wang, Liang-min
> > > > > Sent: Thursday, June 11, 2015 1:58 PM
> > > > > To: Ananyev, Konstantin; dev@dpdk.org
> > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > > access device info
> > > > >
> > > > > Hi Konstantin,
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: Ananyev, Konstantin
> > > > > > Sent: Thursday, June 11, 2015 8:26 AM
> > > > > > To: Wang, Liang-min; dev@dpdk.org
> > > > > > Cc: Wang, Liang-min
> > > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > support access device info
> > > > > >
> > > > > > Hi Larry,
> > > > > >
> > > > > > > -----Original Message-----
> > > > > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Liang-Min
> > > > > > > Larry Wang
> > > > > > > Sent: Wednesday, June 10, 2015 4:10 PM
> > > > > > > To: dev@dpdk.org
> > > > > > > Cc: Wang, Liang-min
> > > > > > > Subject: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > > > > access device info
> > > > > > >
> > > > > > > add new apis:
> > > > > > > - rte_eth_dev_default_mac_addr_set
> > > > > > > - rte_eth_dev_reg_leng
> > > > > > > - rte_eth_dev_reg_info
> > > > > > > - rte_eth_dev_eeprom_leng
> > > > > > > - rte_eth_dev_get_eeprom
> > > > > > > - rte_eth_dev_set_eeprom
> > > > > > > - rte_eth_dev_get_ringparam
> > > > > > > - rte_eth_dev_set_ringparam
> > > > > > >
> > > > > > > to enable reading device parameters (mac-addr, register,
> > > > > > > eeprom,
> > > > > > > ring) based upon ethtool alike data parameter specification.
> > > > > > >
> > > > > > > Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> > > > > > > ---
> > > > > > >  lib/librte_ether/Makefile              |   1 +
> > > > > > >  lib/librte_ether/rte_eth_dev_info.h    |  80 +++++++++++++++++
> > > > > > >  lib/librte_ether/rte_ethdev.c          | 159
> > > > > > +++++++++++++++++++++++++++++++++
> > > > > > >  lib/librte_ether/rte_ethdev.h          | 158
> > > > > > ++++++++++++++++++++++++++++++++
> > > > > > >  lib/librte_ether/rte_ether_version.map |   8 ++
> > > > > > >  5 files changed, 406 insertions(+)  create mode 100644
> > > > > > > lib/librte_ether/rte_eth_dev_info.h
> > > > > > >
> > > > > > > diff --git a/lib/librte_ether/Makefile
> > > > > > > b/lib/librte_ether/Makefile index c0e5768..05209e9 100644
> > > > > > > --- a/lib/librte_ether/Makefile
> > > > > > > +++ b/lib/librte_ether/Makefile
> > > > > > > @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c  SYMLINK-y-include +=
> > > > > > > rte_ether.h  SYMLINK-y-include += rte_ethdev.h
> > > > > > > SYMLINK-y-include
> > > > > > > += rte_eth_ctrl.h
> > > > > > > +SYMLINK-y-include += rte_eth_dev_info.h
> > > > > > >
> > > > > > >  # this lib depends upon:
> > > > > > >  DEPDIRS-y += lib/librte_eal lib/librte_mempool
> > > > > > > lib/librte_ring lib/librte_mbuf diff --git
> > > > > > > a/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > new file mode 100644
> > > > > > > index 0000000..002c4b5
> > > > > > > --- /dev/null
> > > > > > > +++ b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > @@ -0,0 +1,80 @@
> > > > > > > +/*-
> > > > > > > + *   BSD LICENSE
> > > > > > > + *
> > > > > > > + *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> > > > > > > + *   All rights reserved.
> > > > > > > + *
> > > > > > > + *   Redistribution and use in source and binary forms, with or
> > without
> > > > > > > + *   modification, are permitted provided that the following
> > conditions
> > > > > > > + *   are met:
> > > > > > > + *
> > > > > > > + *     * Redistributions of source code must retain the above
> > copyright
> > > > > > > + *       notice, this list of conditions and the following disclaimer.
> > > > > > > + *     * Redistributions in binary form must reproduce the above
> > > > copyright
> > > > > > > + *       notice, this list of conditions and the following disclaimer in
> > > > > > > + *       the documentation and/or other materials provided with the
> > > > > > > + *       distribution.
> > > > > > > + *     * Neither the name of Intel Corporation nor the names of its
> > > > > > > + *       contributors may be used to endorse or promote products
> > > > derived
> > > > > > > + *       from this software without specific prior written permission.
> > > > > > > + *
> > > > > > > + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > > > > > CONTRIBUTORS
> > > > > > > + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> > INCLUDING,
> > > > BUT
> > > > > > NOT
> > > > > > > + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
> > AND
> > > > > > FITNESS FOR
> > > > > > > + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
> > THE
> > > > > > COPYRIGHT
> > > > > > > + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
> > INDIRECT,
> > > > > > INCIDENTAL,
> > > > > > > + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> > > > (INCLUDING,
> > > > > > BUT NOT
> > > > > > > + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> > SERVICES;
> > > > > > LOSS OF USE,
> > > > > > > + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> > > > CAUSED
> > > > > > AND ON ANY
> > > > > > > + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> > LIABILITY,
> > > > OR
> > > > > > TORT
> > > > > > > + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> > WAY
> > > > OUT
> > > > > > OF THE USE
> > > > > > > + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> > SUCH
> > > > > > DAMAGE.
> > > > > > > + */
> > > > > > > +
> > > > > > > +#ifndef _RTE_ETH_DEV_INFO_H_
> > > > > > > +#define _RTE_ETH_DEV_INFO_H_
> > > > > > > +
> > > > > > > +
> > > > > > > +/*
> > > > > > > + * Placeholder for accessing device registers  */ struct
> > > > > > > +rte_dev_reg_info {
> > > > > > > +	void *buf; /**< Buffer for register */
> > > > > > > +	uint32_t offset; /**< Offset for 1st register to fetch */
> > > > > > > +	uint32_t leng; /**< Number of registers to fetch */
> > > > > > > +	uint32_t version; /**< Device version */ };
> > > > > > > +
> > > > > > > +/*
> > > > > > > + * Placeholder for accessing device eeprom  */ struct
> > > > > > > +rte_dev_eeprom_info {
> > > > > > > +	void *buf; /**< Buffer for eeprom */
> > > > > > > +	uint32_t offset; /**< Offset for 1st eeprom location to access
> > */
> > > > > > > +	uint32_t leng; /**< Length of eeprom region to access */
> > > > > > > +	uint32_t magic; /**< Device ID */ };
> > > > > > > +
> > > > > > > +/*
> > > > > > > + * Placeholder for accessing device ring parameters  */
> > > > > > > +struct rte_dev_ring_info {
> > > > > > > +	uint32_t rx_pending; /**< Number of outstanding Rx ring */
> > > > > > > +	uint32_t tx_pending; /**< Number of outstanding Tx ring */
> > > > > > > +	uint32_t rx_max_pending; /**< Maximum number of
> > outstanding
> > > > > > > +Rx
> > > > > > ring */
> > > > > > > +	uint32_t tx_max_pending; /**< Maximum number of
> > outstanding
> > > > > > > +Tx
> > > > > > ring
> > > > > > > +*/ };
> > > > > > > +
> > > > > > > +/*
> > > > > > > + * A data structure captures information as defined in struct
> > > > > > > +ifla_vf_info
> > > > > > > + * for user-space api
> > > > > > > + */
> > > > > > > +struct rte_dev_vf_info {
> > > > > > > +	uint32_t vf;
> > > > > > > +	uint8_t mac[ETHER_ADDR_LEN];
> > > > > > > +	uint32_t vlan;
> > > > > > > +	uint32_t tx_rate;
> > > > > > > +	uint32_t spoofchk;
> > > > > > > +};
> > > > > >
> > > > > >
> > > > > > Wonder what that structure is for?
> > > > > > I can't see it used in any function below?
> > > > > >
> > > > >
> > > > > Good catch, this is designed for other ethtool ops that I did not
> > > > > include in
> > > > this release, I will remove this from next fix.
> > > > >
> > > > > > > +
> > > > > > > +#endif /* _RTE_ETH_DEV_INFO_H_ */
> > > > > > > diff --git a/lib/librte_ether/rte_ethdev.c
> > > > > > > b/lib/librte_ether/rte_ethdev.c index 5a94654..186e85c 100644
> > > > > > > --- a/lib/librte_ether/rte_ethdev.c
> > > > > > > +++ b/lib/librte_ether/rte_ethdev.c
> > > > > > > @@ -2751,6 +2751,32 @@ rte_eth_dev_mac_addr_remove(uint8_t
> > > > > > port_id,
> > > > > > > struct ether_addr *addr)  }
> > > > > > >
> > > > > > >  int
> > > > > > > +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct
> > > > > > > +ether_addr
> > > > > > > +*addr) {
> > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > +	const int index = 0;
> > > > > > > +	const uint32_t pool = 0;
> > > > > > > +
> > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > port_id);
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	dev = &rte_eth_devices[port_id];
> > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > >mac_addr_remove, -
> > > > > > ENOTSUP);
> > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -
> > > > > > ENOTSUP);
> > > > > > > +
> > > > > > > +	/* Update NIC default MAC address*/
> > > > > > > +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> > > > > > > +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> > > > > > > +
> > > > > > > +	/* Update default address in NIC data structure */
> > > > > > > +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> > > > > > > +
> > > > > > > +	return 0;
> > > > > > > +}
> > > > > > > +
> > > > > > > +int
> > > > > > >  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
> > > > > > >  				uint16_t rx_mode, uint8_t on)  { @@
> > -3627,3
> > > > +3653,136 @@
> > > > > > > rte_eth_remove_tx_callback(uint8_t port_id,
> > > > > > uint16_t queue_id,
> > > > > > >  	/* Callback wasn't found. */
> > > > > > >  	return -EINVAL;
> > > > > > >  }
> > > > > > > +
> > > > > > > +int
> > > > > > > +rte_eth_dev_reg_leng(uint8_t port_id) {
> > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > +
> > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > port_id);
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length,
> > -
> > > > > > ENOTSUP);
> > > > > > > +	return (*dev->dev_ops->get_reg_length)(dev);
> > > > > > > +}
> > > > > > > +
> > > > > > > +int
> > > > > > > +rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info
> > > > > > > +*info) {
> > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > +
> > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > port_id);
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -
> > ENOTSUP);
> > > > > > > +	return (*dev->dev_ops->get_reg)(dev, info); }
> > > > > >
> > > > > > Seems that *get_reg* stuff, will be really good addition for
> > > > > > DPDK debugging abilities.
> > > > > > Though, I'd suggest we change it a bit to make more generic and
> > flexible:
> > > > > >
> > > > > > Introduce rte_eth_reg_read/rte_eth_reg_write(),
> > > > > > or probably even better rte_pcidev_reg_read
> > > > > > /rte_pcidev_reg_write at
> > > > EAL.
> > > > > > Something similar to what port_pci_reg_read/port_pci_reg_write()
> > > > > > are doing now at testpmd.h.
> > > > > >
> > > > > > struct rte_pcidev_reg_info {
> > > > > >    const char *name;
> > > > > >    uint32_t endianes, bar, offset, size, count; };
> > > > > >
> > > > > > int rte_pcidev_reg_read(const struct rte_pci_device *, const
> > > > > > struct rte_pcidev_reg_info *, uint64_t *reg_val);
> > > > > >
> > > > > > Then:
> > > > > > int rte_eth_dev_get_reg_info(port_id, const struct
> > > > > > rte_pcidev_reg_info **info);
> > > > > >
> > > > > > So each device would store in info a pointer to an array of it's
> > > > > > register descriptions (finished by zero elem?).
> > > > > >
> > > > > > Then your ethtool (or any other upper layer) can do the
> > > > > > following to read all device regs:
> > > > > >
> > > > >
> > > > > The proposed reg info structure allows future improvement to
> > > > > support
> > > > individual register read/write.
> > > > > Also, because each NIC device has a very distinguish register definition.
> > > > > So, the plan is to have more comprehensive interface to support
> > > > > query operation (for example, register name) before introduce
> > > > > individual/group
> > > > register access.
> > > > > Points taken, the support will be in future release.
> > > >
> > > > Sorry, didn't get you.
> > > > So you are ok to make these changes in next patch version?
> > > >
> > > I would like to get a consensus from dpdk community on how to provide
> > register information.
> >
> > Well, that' ok, but if it is just a trial patch that is not intended to be applied,
> > then you should mark it as RFC.
> >
> > > Currently, it's designed for debug dumping. The register information is very
> > hardware dependent.
> > > Need to consider current supported NIC device and future devices for
> > DPDK, so we won't make it a bulky interface.
> >
> > Ok, could you explain what exactly  concerns you in the approach described
> > above?
> > What part you feel is bulky?
> >
> > > > >
> > > > > > const struct rte_eth_dev_reg_info *reg_info; struct
> > > > > > rte_eth_dev_info dev_info;
> > > > > >
> > > > > > rte_eth_dev_info_get(pid, &dev_info);
> > > > > > rte_eth_dev_get_reg_info(port_id, &reg_info);
> > > > > >
> > > > > > for (i = 0; reg_info[i].name != NULL; i++) {
> > > > > >    ...
> > > > > >    rte_pcidev_read_reg(dev_info. pci_dev, reg_info[i], &v);
> > > > > >   ..
> > > > > > }
> > > > > >
> > > > > > > +
> > > > > > > +int
> > > > > > > +rte_eth_dev_eeprom_leng(uint8_t port_id) {
> > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > +
> > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > port_id);
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > >get_eeprom_length, -
> > > > > > ENOTSUP);
> > > > > > > +	return (*dev->dev_ops->get_eeprom_length)(dev);
> > > > > > > +}
> > > > > > > +
> > > > > > > +int
> > > > > > > +rte_eth_dev_get_eeprom(uint8_t port_id, struct
> > > > > > > +rte_dev_eeprom_info
> > > > > > > +*info) {
> > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > +
> > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > port_id);
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -
> > > > > > ENOTSUP);
> > > > > > > +	return (*dev->dev_ops->get_eeprom)(dev, info); }
> > > > > > > +
> > > > > > > +int
> > > > > > > +rte_eth_dev_set_eeprom(uint8_t port_id, struct
> > > > > > > +rte_dev_eeprom_info
> > > > > > > +*info) {
> > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > +
> > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > port_id);
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -
> > > > > > ENOTSUP);
> > > > > > > +	return (*dev->dev_ops->set_eeprom)(dev, info); }
> > > > > > > +
> > > > > > > +int
> > > > > > > +rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > > > > > +rte_dev_ring_info
> > > > > > > +*info) {
> > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > +
> > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > port_id);
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > +		return -ENODEV;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> > > > > > ENOTSUP);
> > > > > > > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> > > > > >
> > > > > > I think it will be a useful addition to the ethdev API  to have
> > > > > > an ability to retrieve current RX/TX queue parameters.
> > > > > > Though again, it need to be more generic, so it could be useful
> > > > > > for
> > > > > > non- ethtool upper layer too.
> > > > > > So I suggest to modify it a bit.
> > > > > > Something like that:
> > > > > >
> > > > > > struct rte_eth_tx_queue_info {
> > > > > >     struct rte_eth_txconf txconf;
> > > > > >     uint32_t nb_tx_desc;
> > > > > >     uint32_t nb_max_tx_desc; /*max allowable TXDs for that queue */
> > > > > >     uint32_t nb_tx_free;            /* number of free TXDs at the moment
> > of
> > > > call.
> > > > > > */
> > > > > >     /* other tx queue data. */
> > > > > > };
> > > > > >
> > > > > > int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> > > > > > rte_eth_tx_queue_info *qinfo)
> > > > > >
> > > > > > Then, your upper layer ethtool wrapper, can implement yours
> > > > > > ethtool_get_ringparam() by:
> > > > > >
> > > > > >  ...
> > > > > >  struct rte_eth_tx_queue_info qinfo;
> > > > > > rte_ethdev_get_tx_queue_info(port, 0, &qinfo);
> > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > rte_eth_rx_queue_count(port, 0);
> > > > > >
> > > > > > Or probably even:
> > > > > > ring_param->tx_pending = qinfo.nb_tx_desc - qinfo.nb_tx_free;
> > > > > >
> > > > > > Same for RX.
> > > > > >
> > > > > For now, this descriptor ring information is used by the ethtool op.
> > > > > To make this interface simple, i.e. caller doesn't need to access
> > > > > other
> > > > queue information.
> > > >
> > > > I just repeat what I said to you in off-line conversation:
> > > > ethdev API is not equal ethtool API.
> > > > It is ok to add  a new function/structure to ethdev if it really
> > > > needed, but we should do mechanical one to one copy.
> > > > It is much better to add  a function/structure that would be more
> > > > generic, and suit other users, not only ethtool.
> > > > There is no point to have dozen functions in rte_ethdev API
> > > > providing similar information.
> > > > BTW, I don't see how API I proposed is much more  complex, then yours
> > one.
> > > The ring parameter is a run-time information which is different than data
> > structure described in this discussion.
> >
> > I don't see how they are different.
> > Looking at ixgbe_get_ringparam(), it returns:
> > rx_max_pending - that's a static IXGBE PMD value (max possible number of
> > RXDs per one queue).
> > rx_pending - number of RXD currently in use by the HW for queue 0 (that
> > information can be changed at each call).
> >
> > With the approach I suggesting - you can get same information for each RX
> > queue by calling rte_ethdev_get_rx_queue_info() and
> > rte_eth_rx_queue_count().
> > Plus you are getting other RX queue data.
> >
> > Another thing - what is practical usage of the information you retrieving now
> > by get_ringparam()?
> > Let say it returned to you: rx_max_pending=4096; rx_pending=128; How that
> > information would help to understand what is going on with the device?
> > Without knowing  value of nb_tx_desc for the queue, you can't say is you
> > queue full or not.
> > Again, it could be that all your traffic going through some other queue (not
> > 0).
> > So from my point rte_eth_dev_get_ringparam()  usage is very limited, and
> > doesn't provide enough information about current queue state.
> >
> > Same thing applies for TX.
> >
> 
> After careful review the suggestion in this comment, and review the existing dpdk source code.
> I came to realize that neither rte_ethdev_get_rx_queue_info, rte_ethdev_get_tx_queue_info, struct rte_eth_rx_queue_info and
> struct rte_eth_tx_queue_info are available in the existing dpdk source code. I could not make a patch based upon a set of non-
> existent API and data structure.

Right now, in dpdk.org source code, struct  rte_eth_dev_ring_info, struct  rte_dev_eeprom_info and struct  rte_dev_reg_info
don't exist also.
Same as  all these functions:

rte_eth_dev_default_mac_addr_set
rte_eth_dev_reg_length
rte_eth_dev_reg_info
rte_eth_dev_eeprom_length
rte_eth_dev_get_eeprom
rte_eth_dev_set_eeprom
rte_eth_dev_get_ringparam

All this is a new API that's you are trying to add.
But, by some reason you consider it is ok to add 'struct  rte_eth_dev_ring_info', but couldn't add  struct 'rte_ethdev_get_tx_queue_info'
That just doesn't make any sense to me.
In fact, I think our conversation is going in cycles.
If you are not happy with the suggested approach, please provide some meaningful reason why.
Konstantin

> 
> > > It's the desire of this patch to separate each data structure to avoid cross
> > dependency.
> >
> > That's too cryptic to me.
> > Could you explain what cross dependency you are talking about?
> >
> > Konstantin

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-15 13:45                 ` Ananyev, Konstantin
@ 2015-06-15 14:47                   ` Wang, Liang-min
  2015-06-15 18:10                     ` Ananyev, Konstantin
  2015-06-15 16:05                   ` David Harton (dharton)
  1 sibling, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-15 14:47 UTC (permalink / raw)
  To: Ananyev, Konstantin, dev



> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Monday, June 15, 2015 9:46 AM
> To: Wang, Liang-min; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> device info
> 
> 
> 
> > -----Original Message-----
> > From: Wang, Liang-min
> > Sent: Monday, June 15, 2015 2:26 PM
> > To: Ananyev, Konstantin; dev@dpdk.org
> > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > access device info
> >
> >
> >
> > > -----Original Message-----
> > > From: Ananyev, Konstantin
> > > Sent: Friday, June 12, 2015 8:31 AM
> > > To: Wang, Liang-min; dev@dpdk.org
> > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > access device info
> > >
> > >
> > >
> > > > -----Original Message-----
> > > > From: Wang, Liang-min
> > > > Sent: Thursday, June 11, 2015 10:51 PM
> > > > To: Ananyev, Konstantin; dev@dpdk.org
> > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > access device info
> > > >
> > > >
> > > >
> > > > > -----Original Message-----
> > > > > From: Ananyev, Konstantin
> > > > > Sent: Thursday, June 11, 2015 9:07 AM
> > > > > To: Wang, Liang-min; dev@dpdk.org
> > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > support access device info
> > > > >
> > > > >
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: Wang, Liang-min
> > > > > > Sent: Thursday, June 11, 2015 1:58 PM
> > > > > > To: Ananyev, Konstantin; dev@dpdk.org
> > > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > support access device info
> > > > > >
> > > > > > Hi Konstantin,
> > > > > >
> > > > > > > -----Original Message-----
> > > > > > > From: Ananyev, Konstantin
> > > > > > > Sent: Thursday, June 11, 2015 8:26 AM
> > > > > > > To: Wang, Liang-min; dev@dpdk.org
> > > > > > > Cc: Wang, Liang-min
> > > > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > > support access device info
> > > > > > >
> > > > > > > Hi Larry,
> > > > > > >
> > > > > > > > -----Original Message-----
> > > > > > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of
> > > > > > > > Liang-Min Larry Wang
> > > > > > > > Sent: Wednesday, June 10, 2015 4:10 PM
> > > > > > > > To: dev@dpdk.org
> > > > > > > > Cc: Wang, Liang-min
> > > > > > > > Subject: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > > > support access device info
> > > > > > > >
> > > > > > > > add new apis:
> > > > > > > > - rte_eth_dev_default_mac_addr_set
> > > > > > > > - rte_eth_dev_reg_leng
> > > > > > > > - rte_eth_dev_reg_info
> > > > > > > > - rte_eth_dev_eeprom_leng
> > > > > > > > - rte_eth_dev_get_eeprom
> > > > > > > > - rte_eth_dev_set_eeprom
> > > > > > > > - rte_eth_dev_get_ringparam
> > > > > > > > - rte_eth_dev_set_ringparam
> > > > > > > >
> > > > > > > > to enable reading device parameters (mac-addr, register,
> > > > > > > > eeprom,
> > > > > > > > ring) based upon ethtool alike data parameter specification.
> > > > > > > >
> > > > > > > > Signed-off-by: Liang-Min Larry Wang
> > > > > > > > <liang-min.wang@intel.com>
> > > > > > > > ---
> > > > > > > >  lib/librte_ether/Makefile              |   1 +
> > > > > > > >  lib/librte_ether/rte_eth_dev_info.h    |  80
> +++++++++++++++++
> > > > > > > >  lib/librte_ether/rte_ethdev.c          | 159
> > > > > > > +++++++++++++++++++++++++++++++++
> > > > > > > >  lib/librte_ether/rte_ethdev.h          | 158
> > > > > > > ++++++++++++++++++++++++++++++++
> > > > > > > >  lib/librte_ether/rte_ether_version.map |   8 ++
> > > > > > > >  5 files changed, 406 insertions(+)  create mode 100644
> > > > > > > > lib/librte_ether/rte_eth_dev_info.h
> > > > > > > >
> > > > > > > > diff --git a/lib/librte_ether/Makefile
> > > > > > > > b/lib/librte_ether/Makefile index c0e5768..05209e9 100644
> > > > > > > > --- a/lib/librte_ether/Makefile
> > > > > > > > +++ b/lib/librte_ether/Makefile
> > > > > > > > @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
> > > > > > > > SYMLINK-y-include += rte_ether.h  SYMLINK-y-include +=
> > > > > > > > rte_ethdev.h SYMLINK-y-include
> > > > > > > > += rte_eth_ctrl.h
> > > > > > > > +SYMLINK-y-include += rte_eth_dev_info.h
> > > > > > > >
> > > > > > > >  # this lib depends upon:
> > > > > > > >  DEPDIRS-y += lib/librte_eal lib/librte_mempool
> > > > > > > > lib/librte_ring lib/librte_mbuf diff --git
> > > > > > > > a/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > new file mode 100644
> > > > > > > > index 0000000..002c4b5
> > > > > > > > --- /dev/null
> > > > > > > > +++ b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > @@ -0,0 +1,80 @@
> > > > > > > > +/*-
> > > > > > > > + *   BSD LICENSE
> > > > > > > > + *
> > > > > > > > + *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> > > > > > > > + *   All rights reserved.
> > > > > > > > + *
> > > > > > > > + *   Redistribution and use in source and binary forms, with or
> > > without
> > > > > > > > + *   modification, are permitted provided that the following
> > > conditions
> > > > > > > > + *   are met:
> > > > > > > > + *
> > > > > > > > + *     * Redistributions of source code must retain the above
> > > copyright
> > > > > > > > + *       notice, this list of conditions and the following disclaimer.
> > > > > > > > + *     * Redistributions in binary form must reproduce the above
> > > > > copyright
> > > > > > > > + *       notice, this list of conditions and the following disclaimer
> in
> > > > > > > > + *       the documentation and/or other materials provided with
> the
> > > > > > > > + *       distribution.
> > > > > > > > + *     * Neither the name of Intel Corporation nor the names of
> its
> > > > > > > > + *       contributors may be used to endorse or promote
> products
> > > > > derived
> > > > > > > > + *       from this software without specific prior written
> permission.
> > > > > > > > + *
> > > > > > > > + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
> AND
> > > > > > > CONTRIBUTORS
> > > > > > > > + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> > > INCLUDING,
> > > > > BUT
> > > > > > > NOT
> > > > > > > > + *   LIMITED TO, THE IMPLIED WARRANTIES OF
> MERCHANTABILITY
> > > AND
> > > > > > > FITNESS FOR
> > > > > > > > + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
> SHALL
> > > THE
> > > > > > > COPYRIGHT
> > > > > > > > + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
> > > INDIRECT,
> > > > > > > INCIDENTAL,
> > > > > > > > + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> > > > > (INCLUDING,
> > > > > > > BUT NOT
> > > > > > > > + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> > > SERVICES;
> > > > > > > LOSS OF USE,
> > > > > > > > + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> HOWEVER
> > > > > CAUSED
> > > > > > > AND ON ANY
> > > > > > > > + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> > > LIABILITY,
> > > > > OR
> > > > > > > TORT
> > > > > > > > + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> > > WAY
> > > > > OUT
> > > > > > > OF THE USE
> > > > > > > > + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
> OF
> > > SUCH
> > > > > > > DAMAGE.
> > > > > > > > + */
> > > > > > > > +
> > > > > > > > +#ifndef _RTE_ETH_DEV_INFO_H_ #define
> _RTE_ETH_DEV_INFO_H_
> > > > > > > > +
> > > > > > > > +
> > > > > > > > +/*
> > > > > > > > + * Placeholder for accessing device registers  */ struct
> > > > > > > > +rte_dev_reg_info {
> > > > > > > > +	void *buf; /**< Buffer for register */
> > > > > > > > +	uint32_t offset; /**< Offset for 1st register to fetch */
> > > > > > > > +	uint32_t leng; /**< Number of registers to fetch */
> > > > > > > > +	uint32_t version; /**< Device version */ };
> > > > > > > > +
> > > > > > > > +/*
> > > > > > > > + * Placeholder for accessing device eeprom  */ struct
> > > > > > > > +rte_dev_eeprom_info {
> > > > > > > > +	void *buf; /**< Buffer for eeprom */
> > > > > > > > +	uint32_t offset; /**< Offset for 1st eeprom location to
> > > > > > > > +access
> > > */
> > > > > > > > +	uint32_t leng; /**< Length of eeprom region to access */
> > > > > > > > +	uint32_t magic; /**< Device ID */ };
> > > > > > > > +
> > > > > > > > +/*
> > > > > > > > + * Placeholder for accessing device ring parameters  */
> > > > > > > > +struct rte_dev_ring_info {
> > > > > > > > +	uint32_t rx_pending; /**< Number of outstanding Rx ring */
> > > > > > > > +	uint32_t tx_pending; /**< Number of outstanding Tx ring */
> > > > > > > > +	uint32_t rx_max_pending; /**< Maximum number of
> > > outstanding
> > > > > > > > +Rx
> > > > > > > ring */
> > > > > > > > +	uint32_t tx_max_pending; /**< Maximum number of
> > > outstanding
> > > > > > > > +Tx
> > > > > > > ring
> > > > > > > > +*/ };
> > > > > > > > +
> > > > > > > > +/*
> > > > > > > > + * A data structure captures information as defined in
> > > > > > > > +struct ifla_vf_info
> > > > > > > > + * for user-space api
> > > > > > > > + */
> > > > > > > > +struct rte_dev_vf_info {
> > > > > > > > +	uint32_t vf;
> > > > > > > > +	uint8_t mac[ETHER_ADDR_LEN];
> > > > > > > > +	uint32_t vlan;
> > > > > > > > +	uint32_t tx_rate;
> > > > > > > > +	uint32_t spoofchk;
> > > > > > > > +};
> > > > > > >
> > > > > > >
> > > > > > > Wonder what that structure is for?
> > > > > > > I can't see it used in any function below?
> > > > > > >
> > > > > >
> > > > > > Good catch, this is designed for other ethtool ops that I did
> > > > > > not include in
> > > > > this release, I will remove this from next fix.
> > > > > >
> > > > > > > > +
> > > > > > > > +#endif /* _RTE_ETH_DEV_INFO_H_ */
> > > > > > > > diff --git a/lib/librte_ether/rte_ethdev.c
> > > > > > > > b/lib/librte_ether/rte_ethdev.c index 5a94654..186e85c
> > > > > > > > 100644
> > > > > > > > --- a/lib/librte_ether/rte_ethdev.c
> > > > > > > > +++ b/lib/librte_ether/rte_ethdev.c
> > > > > > > > @@ -2751,6 +2751,32 @@
> rte_eth_dev_mac_addr_remove(uint8_t
> > > > > > > port_id,
> > > > > > > > struct ether_addr *addr)  }
> > > > > > > >
> > > > > > > >  int
> > > > > > > > +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct
> > > > > > > > +ether_addr
> > > > > > > > +*addr) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +	const int index = 0;
> > > > > > > > +	const uint32_t pool = 0;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	dev = &rte_eth_devices[port_id];
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > > >mac_addr_remove, -
> > > > > > > ENOTSUP);
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -
> > > > > > > ENOTSUP);
> > > > > > > > +
> > > > > > > > +	/* Update NIC default MAC address*/
> > > > > > > > +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> > > > > > > > +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> > > > > > > > +
> > > > > > > > +	/* Update default address in NIC data structure */
> > > > > > > > +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> > > > > > > > +
> > > > > > > > +	return 0;
> > > > > > > > +}
> > > > > > > > +
> > > > > > > > +int
> > > > > > > >  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
> > > > > > > >  				uint16_t rx_mode, uint8_t on)  { @@
> > > -3627,3
> > > > > +3653,136 @@
> > > > > > > > rte_eth_remove_tx_callback(uint8_t port_id,
> > > > > > > uint16_t queue_id,
> > > > > > > >  	/* Callback wasn't found. */
> > > > > > > >  	return -EINVAL;
> > > > > > > >  }
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_reg_leng(uint8_t port_id) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length,
> > > -
> > > > > > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->get_reg_length)(dev);
> > > > > > > > +}
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_reg_info(uint8_t port_id, struct
> > > > > > > > +rte_dev_reg_info
> > > > > > > > +*info) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -
> > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->get_reg)(dev, info); }
> > > > > > >
> > > > > > > Seems that *get_reg* stuff, will be really good addition for
> > > > > > > DPDK debugging abilities.
> > > > > > > Though, I'd suggest we change it a bit to make more generic
> > > > > > > and
> > > flexible:
> > > > > > >
> > > > > > > Introduce rte_eth_reg_read/rte_eth_reg_write(),
> > > > > > > or probably even better rte_pcidev_reg_read
> > > > > > > /rte_pcidev_reg_write at
> > > > > EAL.
> > > > > > > Something similar to what
> > > > > > > port_pci_reg_read/port_pci_reg_write()
> > > > > > > are doing now at testpmd.h.
> > > > > > >
> > > > > > > struct rte_pcidev_reg_info {
> > > > > > >    const char *name;
> > > > > > >    uint32_t endianes, bar, offset, size, count; };
> > > > > > >
> > > > > > > int rte_pcidev_reg_read(const struct rte_pci_device *, const
> > > > > > > struct rte_pcidev_reg_info *, uint64_t *reg_val);
> > > > > > >
> > > > > > > Then:
> > > > > > > int rte_eth_dev_get_reg_info(port_id, const struct
> > > > > > > rte_pcidev_reg_info **info);
> > > > > > >
> > > > > > > So each device would store in info a pointer to an array of
> > > > > > > it's register descriptions (finished by zero elem?).
> > > > > > >
> > > > > > > Then your ethtool (or any other upper layer) can do the
> > > > > > > following to read all device regs:
> > > > > > >
> > > > > >
> > > > > > The proposed reg info structure allows future improvement to
> > > > > > support
> > > > > individual register read/write.
> > > > > > Also, because each NIC device has a very distinguish register
> definition.
> > > > > > So, the plan is to have more comprehensive interface to
> > > > > > support query operation (for example, register name) before
> > > > > > introduce individual/group
> > > > > register access.
> > > > > > Points taken, the support will be in future release.
> > > > >
> > > > > Sorry, didn't get you.
> > > > > So you are ok to make these changes in next patch version?
> > > > >
> > > > I would like to get a consensus from dpdk community on how to
> > > > provide
> > > register information.
> > >
> > > Well, that' ok, but if it is just a trial patch that is not intended
> > > to be applied, then you should mark it as RFC.
> > >
> > > > Currently, it's designed for debug dumping. The register
> > > > information is very
> > > hardware dependent.
> > > > Need to consider current supported NIC device and future devices
> > > > for
> > > DPDK, so we won't make it a bulky interface.
> > >
> > > Ok, could you explain what exactly  concerns you in the approach
> > > described above?
> > > What part you feel is bulky?
> > >
> > > > > >
> > > > > > > const struct rte_eth_dev_reg_info *reg_info; struct
> > > > > > > rte_eth_dev_info dev_info;
> > > > > > >
> > > > > > > rte_eth_dev_info_get(pid, &dev_info);
> > > > > > > rte_eth_dev_get_reg_info(port_id, &reg_info);
> > > > > > >
> > > > > > > for (i = 0; reg_info[i].name != NULL; i++) {
> > > > > > >    ...
> > > > > > >    rte_pcidev_read_reg(dev_info. pci_dev, reg_info[i], &v);
> > > > > > >   ..
> > > > > > > }
> > > > > > >
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_eeprom_leng(uint8_t port_id) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > > >get_eeprom_length, -
> > > > > > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->get_eeprom_length)(dev);
> > > > > > > > +}
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_get_eeprom(uint8_t port_id, struct
> > > > > > > > +rte_dev_eeprom_info
> > > > > > > > +*info) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -
> > > > > > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->get_eeprom)(dev, info); }
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_set_eeprom(uint8_t port_id, struct
> > > > > > > > +rte_dev_eeprom_info
> > > > > > > > +*info) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -
> > > > > > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->set_eeprom)(dev, info); }
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > > > > > > +rte_dev_ring_info
> > > > > > > > +*info) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> > > > > > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> > > > > > >
> > > > > > > I think it will be a useful addition to the ethdev API  to
> > > > > > > have an ability to retrieve current RX/TX queue parameters.
> > > > > > > Though again, it need to be more generic, so it could be
> > > > > > > useful for
> > > > > > > non- ethtool upper layer too.
> > > > > > > So I suggest to modify it a bit.
> > > > > > > Something like that:
> > > > > > >
> > > > > > > struct rte_eth_tx_queue_info {
> > > > > > >     struct rte_eth_txconf txconf;
> > > > > > >     uint32_t nb_tx_desc;
> > > > > > >     uint32_t nb_max_tx_desc; /*max allowable TXDs for that
> queue */
> > > > > > >     uint32_t nb_tx_free;            /* number of free TXDs at the
> moment
> > > of
> > > > > call.
> > > > > > > */
> > > > > > >     /* other tx queue data. */ };
> > > > > > >
> > > > > > > int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> > > > > > > rte_eth_tx_queue_info *qinfo)
> > > > > > >
> > > > > > > Then, your upper layer ethtool wrapper, can implement yours
> > > > > > > ethtool_get_ringparam() by:
> > > > > > >
> > > > > > >  ...
> > > > > > >  struct rte_eth_tx_queue_info qinfo;
> > > > > > > rte_ethdev_get_tx_queue_info(port, 0, &qinfo);
> > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > rte_eth_rx_queue_count(port, 0);
> > > > > > >
> > > > > > > Or probably even:
> > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > qinfo.nb_tx_free;
> > > > > > >
> > > > > > > Same for RX.
> > > > > > >
> > > > > > For now, this descriptor ring information is used by the ethtool op.
> > > > > > To make this interface simple, i.e. caller doesn't need to
> > > > > > access other
> > > > > queue information.
> > > > >
> > > > > I just repeat what I said to you in off-line conversation:
> > > > > ethdev API is not equal ethtool API.
> > > > > It is ok to add  a new function/structure to ethdev if it really
> > > > > needed, but we should do mechanical one to one copy.
> > > > > It is much better to add  a function/structure that would be
> > > > > more generic, and suit other users, not only ethtool.
> > > > > There is no point to have dozen functions in rte_ethdev API
> > > > > providing similar information.
> > > > > BTW, I don't see how API I proposed is much more  complex, then
> > > > > yours
> > > one.
> > > > The ring parameter is a run-time information which is different
> > > > than data
> > > structure described in this discussion.
> > >
> > > I don't see how they are different.
> > > Looking at ixgbe_get_ringparam(), it returns:
> > > rx_max_pending - that's a static IXGBE PMD value (max possible
> > > number of RXDs per one queue).
> > > rx_pending - number of RXD currently in use by the HW for queue 0
> > > (that information can be changed at each call).
> > >
> > > With the approach I suggesting - you can get same information for
> > > each RX queue by calling rte_ethdev_get_rx_queue_info() and
> > > rte_eth_rx_queue_count().
> > > Plus you are getting other RX queue data.
> > >
> > > Another thing - what is practical usage of the information you
> > > retrieving now by get_ringparam()?
> > > Let say it returned to you: rx_max_pending=4096; rx_pending=128; How
> > > that information would help to understand what is going on with the
> device?
> > > Without knowing  value of nb_tx_desc for the queue, you can't say is
> > > you queue full or not.
> > > Again, it could be that all your traffic going through some other
> > > queue (not 0).
> > > So from my point rte_eth_dev_get_ringparam()  usage is very limited,
> > > and doesn't provide enough information about current queue state.
> > >
> > > Same thing applies for TX.
> > >
> >
> > After careful review the suggestion in this comment, and review the
> existing dpdk source code.
> > I came to realize that neither rte_ethdev_get_rx_queue_info,
> > rte_ethdev_get_tx_queue_info, struct rte_eth_rx_queue_info and struct
> > rte_eth_tx_queue_info are available in the existing dpdk source code. I
> could not make a patch based upon a set of non- existent API and data
> structure.
> 
> Right now, in dpdk.org source code, struct  rte_eth_dev_ring_info, struct
> rte_dev_eeprom_info and struct  rte_dev_reg_info don't exist also.
> Same as  all these functions:
> 
> rte_eth_dev_default_mac_addr_set
> rte_eth_dev_reg_length
> rte_eth_dev_reg_info
> rte_eth_dev_eeprom_length
> rte_eth_dev_get_eeprom
> rte_eth_dev_set_eeprom
> rte_eth_dev_get_ringparam
> 
> All this is a new API that's you are trying to add.
> But, by some reason you consider it is ok to add 'struct
> rte_eth_dev_ring_info', but couldn't add  struct
> 'rte_ethdev_get_tx_queue_info'
> That just doesn't make any sense to me.
> In fact, I think our conversation is going in cycles.
> If you are not happy with the suggested approach, please provide some
> meaningful reason why.

All the API's and data structure that you have questions in this comment are available from the submitted patch, you could run to see if it works.
What I learned from your comments are a couple of API name and incomplete data structure description, so I could not make my patch according to your suggestion.
If you strongly feel the API's that you are proposing are useful for get_ringparam(), please create a patch and submit it for evaluation.
As coded in this patch, it's a simple and clean interface and most important, it can be validated and it works.

> Konstantin
> 
> >
> > > > It's the desire of this patch to separate each data structure to
> > > > avoid cross
> > > dependency.
> > >
> > > That's too cryptic to me.
> > > Could you explain what cross dependency you are talking about?
> > >
> > > Konstantin

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-15 13:45                 ` Ananyev, Konstantin
  2015-06-15 14:47                   ` Wang, Liang-min
@ 2015-06-15 16:05                   ` David Harton (dharton)
  2015-06-15 18:23                     ` Ananyev, Konstantin
  1 sibling, 1 reply; 174+ messages in thread
From: David Harton (dharton) @ 2015-06-15 16:05 UTC (permalink / raw)
  To: Ananyev, Konstantin, Wang, Liang-min, dev



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ananyev, Konstantin
> Sent: Monday, June 15, 2015 9:46 AM
> To: Wang, Liang-min; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> device info
> 
> 
> 
> > -----Original Message-----
> > From: Wang, Liang-min
> > Sent: Monday, June 15, 2015 2:26 PM
> > To: Ananyev, Konstantin; dev@dpdk.org
> > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > access device info
> >
> >
> >
> > > -----Original Message-----
> > > From: Ananyev, Konstantin
> > > Sent: Friday, June 12, 2015 8:31 AM
> > > To: Wang, Liang-min; dev@dpdk.org
> > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > access device info
> > >
> > >
> > >
> > > > -----Original Message-----
> > > > From: Wang, Liang-min
> > > > Sent: Thursday, June 11, 2015 10:51 PM
> > > > To: Ananyev, Konstantin; dev@dpdk.org
> > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > access device info
> > > >
> > > >
> > > >
> > > > > -----Original Message-----
> > > > > From: Ananyev, Konstantin
> > > > > Sent: Thursday, June 11, 2015 9:07 AM
> > > > > To: Wang, Liang-min; dev@dpdk.org
> > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > support access device info
> > > > >
> > > > >
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: Wang, Liang-min
> > > > > > Sent: Thursday, June 11, 2015 1:58 PM
> > > > > > To: Ananyev, Konstantin; dev@dpdk.org
> > > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > support access device info
> > > > > >
> > > > > > Hi Konstantin,
> > > > > >
> > > > > > > -----Original Message-----
> > > > > > > From: Ananyev, Konstantin
> > > > > > > Sent: Thursday, June 11, 2015 8:26 AM
> > > > > > > To: Wang, Liang-min; dev@dpdk.org
> > > > > > > Cc: Wang, Liang-min
> > > > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > > support access device info
> > > > > > >
> > > > > > > Hi Larry,
> > > > > > >
> > > > > > > > -----Original Message-----
> > > > > > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of
> > > > > > > > Liang-Min Larry Wang
> > > > > > > > Sent: Wednesday, June 10, 2015 4:10 PM
> > > > > > > > To: dev@dpdk.org
> > > > > > > > Cc: Wang, Liang-min
> > > > > > > > Subject: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > > > support access device info
> > > > > > > >
> > > > > > > > add new apis:
> > > > > > > > - rte_eth_dev_default_mac_addr_set
> > > > > > > > - rte_eth_dev_reg_leng
> > > > > > > > - rte_eth_dev_reg_info
> > > > > > > > - rte_eth_dev_eeprom_leng
> > > > > > > > - rte_eth_dev_get_eeprom
> > > > > > > > - rte_eth_dev_set_eeprom
> > > > > > > > - rte_eth_dev_get_ringparam
> > > > > > > > - rte_eth_dev_set_ringparam
> > > > > > > >
> > > > > > > > to enable reading device parameters (mac-addr, register,
> > > > > > > > eeprom,
> > > > > > > > ring) based upon ethtool alike data parameter specification.
> > > > > > > >
> > > > > > > > Signed-off-by: Liang-Min Larry Wang
> > > > > > > > <liang-min.wang@intel.com>
> > > > > > > > ---
> > > > > > > >  lib/librte_ether/Makefile              |   1 +
> > > > > > > >  lib/librte_ether/rte_eth_dev_info.h    |  80
> +++++++++++++++++
> > > > > > > >  lib/librte_ether/rte_ethdev.c          | 159
> > > > > > > +++++++++++++++++++++++++++++++++
> > > > > > > >  lib/librte_ether/rte_ethdev.h          | 158
> > > > > > > ++++++++++++++++++++++++++++++++
> > > > > > > >  lib/librte_ether/rte_ether_version.map |   8 ++
> > > > > > > >  5 files changed, 406 insertions(+)  create mode 100644
> > > > > > > > lib/librte_ether/rte_eth_dev_info.h
> > > > > > > >
> > > > > > > > diff --git a/lib/librte_ether/Makefile
> > > > > > > > b/lib/librte_ether/Makefile index c0e5768..05209e9 100644
> > > > > > > > --- a/lib/librte_ether/Makefile
> > > > > > > > +++ b/lib/librte_ether/Makefile
> > > > > > > > @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
> > > > > > > > SYMLINK-y-include += rte_ether.h  SYMLINK-y-include +=
> > > > > > > > rte_ethdev.h SYMLINK-y-include
> > > > > > > > += rte_eth_ctrl.h
> > > > > > > > +SYMLINK-y-include += rte_eth_dev_info.h
> > > > > > > >
> > > > > > > >  # this lib depends upon:
> > > > > > > >  DEPDIRS-y += lib/librte_eal lib/librte_mempool
> > > > > > > > lib/librte_ring lib/librte_mbuf diff --git
> > > > > > > > a/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > new file mode 100644
> > > > > > > > index 0000000..002c4b5
> > > > > > > > --- /dev/null
> > > > > > > > +++ b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > @@ -0,0 +1,80 @@
> > > > > > > > +/*-
> > > > > > > > + *   BSD LICENSE
> > > > > > > > + *
> > > > > > > > + *   Copyright(c) 2015 Intel Corporation. All rights
> reserved.
> > > > > > > > + *   All rights reserved.
> > > > > > > > + *
> > > > > > > > + *   Redistribution and use in source and binary forms,
> with or
> > > without
> > > > > > > > + *   modification, are permitted provided that the
> following
> > > conditions
> > > > > > > > + *   are met:
> > > > > > > > + *
> > > > > > > > + *     * Redistributions of source code must retain the
> above
> > > copyright
> > > > > > > > + *       notice, this list of conditions and the following
> disclaimer.
> > > > > > > > + *     * Redistributions in binary form must reproduce the
> above
> > > > > copyright
> > > > > > > > + *       notice, this list of conditions and the following
> disclaimer in
> > > > > > > > + *       the documentation and/or other materials provided
> with the
> > > > > > > > + *       distribution.
> > > > > > > > + *     * Neither the name of Intel Corporation nor the
> names of its
> > > > > > > > + *       contributors may be used to endorse or promote
> products
> > > > > derived
> > > > > > > > + *       from this software without specific prior written
> permission.
> > > > > > > > + *
> > > > > > > > + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > > > > > > CONTRIBUTORS
> > > > > > > > + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> > > INCLUDING,
> > > > > BUT
> > > > > > > NOT
> > > > > > > > + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
> > > AND
> > > > > > > FITNESS FOR
> > > > > > > > + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
> > > THE
> > > > > > > COPYRIGHT
> > > > > > > > + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
> > > INDIRECT,
> > > > > > > INCIDENTAL,
> > > > > > > > + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> > > > > (INCLUDING,
> > > > > > > BUT NOT
> > > > > > > > + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> > > SERVICES;
> > > > > > > LOSS OF USE,
> > > > > > > > + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> > > > > CAUSED
> > > > > > > AND ON ANY
> > > > > > > > + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> > > LIABILITY,
> > > > > OR
> > > > > > > TORT
> > > > > > > > + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> > > WAY
> > > > > OUT
> > > > > > > OF THE USE
> > > > > > > > + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
> OF
> > > SUCH
> > > > > > > DAMAGE.
> > > > > > > > + */
> > > > > > > > +
> > > > > > > > +#ifndef _RTE_ETH_DEV_INFO_H_ #define _RTE_ETH_DEV_INFO_H_
> > > > > > > > +
> > > > > > > > +
> > > > > > > > +/*
> > > > > > > > + * Placeholder for accessing device registers  */ struct
> > > > > > > > +rte_dev_reg_info {
> > > > > > > > +	void *buf; /**< Buffer for register */
> > > > > > > > +	uint32_t offset; /**< Offset for 1st register to fetch
> */
> > > > > > > > +	uint32_t leng; /**< Number of registers to fetch */
> > > > > > > > +	uint32_t version; /**< Device version */ };
> > > > > > > > +
> > > > > > > > +/*
> > > > > > > > + * Placeholder for accessing device eeprom  */ struct
> > > > > > > > +rte_dev_eeprom_info {
> > > > > > > > +	void *buf; /**< Buffer for eeprom */
> > > > > > > > +	uint32_t offset; /**< Offset for 1st eeprom location to
> > > > > > > > +access
> > > */
> > > > > > > > +	uint32_t leng; /**< Length of eeprom region to access */
> > > > > > > > +	uint32_t magic; /**< Device ID */ };
> > > > > > > > +
> > > > > > > > +/*
> > > > > > > > + * Placeholder for accessing device ring parameters  */
> > > > > > > > +struct rte_dev_ring_info {
> > > > > > > > +	uint32_t rx_pending; /**< Number of outstanding Rx ring
> */
> > > > > > > > +	uint32_t tx_pending; /**< Number of outstanding Tx ring
> */
> > > > > > > > +	uint32_t rx_max_pending; /**< Maximum number of
> > > outstanding
> > > > > > > > +Rx
> > > > > > > ring */
> > > > > > > > +	uint32_t tx_max_pending; /**< Maximum number of
> > > outstanding
> > > > > > > > +Tx
> > > > > > > ring
> > > > > > > > +*/ };
> > > > > > > > +
> > > > > > > > +/*
> > > > > > > > + * A data structure captures information as defined in
> > > > > > > > +struct ifla_vf_info
> > > > > > > > + * for user-space api
> > > > > > > > + */
> > > > > > > > +struct rte_dev_vf_info {
> > > > > > > > +	uint32_t vf;
> > > > > > > > +	uint8_t mac[ETHER_ADDR_LEN];
> > > > > > > > +	uint32_t vlan;
> > > > > > > > +	uint32_t tx_rate;
> > > > > > > > +	uint32_t spoofchk;
> > > > > > > > +};
> > > > > > >
> > > > > > >
> > > > > > > Wonder what that structure is for?
> > > > > > > I can't see it used in any function below?
> > > > > > >
> > > > > >
> > > > > > Good catch, this is designed for other ethtool ops that I did
> > > > > > not include in
> > > > > this release, I will remove this from next fix.
> > > > > >
> > > > > > > > +
> > > > > > > > +#endif /* _RTE_ETH_DEV_INFO_H_ */
> > > > > > > > diff --git a/lib/librte_ether/rte_ethdev.c
> > > > > > > > b/lib/librte_ether/rte_ethdev.c index 5a94654..186e85c
> > > > > > > > 100644
> > > > > > > > --- a/lib/librte_ether/rte_ethdev.c
> > > > > > > > +++ b/lib/librte_ether/rte_ethdev.c
> > > > > > > > @@ -2751,6 +2751,32 @@ rte_eth_dev_mac_addr_remove(uint8_t
> > > > > > > port_id,
> > > > > > > > struct ether_addr *addr)  }
> > > > > > > >
> > > > > > > >  int
> > > > > > > > +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct
> > > > > > > > +ether_addr
> > > > > > > > +*addr) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +	const int index = 0;
> > > > > > > > +	const uint32_t pool = 0;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	dev = &rte_eth_devices[port_id];
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > > >mac_addr_remove, -
> > > > > > > ENOTSUP);
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -
> > > > > > > ENOTSUP);
> > > > > > > > +
> > > > > > > > +	/* Update NIC default MAC address*/
> > > > > > > > +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> > > > > > > > +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> > > > > > > > +
> > > > > > > > +	/* Update default address in NIC data structure */
> > > > > > > > +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> > > > > > > > +
> > > > > > > > +	return 0;
> > > > > > > > +}
> > > > > > > > +
> > > > > > > > +int
> > > > > > > >  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
> > > > > > > >  				uint16_t rx_mode, uint8_t on)  { @@
> > > -3627,3
> > > > > +3653,136 @@
> > > > > > > > rte_eth_remove_tx_callback(uint8_t port_id,
> > > > > > > uint16_t queue_id,
> > > > > > > >  	/* Callback wasn't found. */
> > > > > > > >  	return -EINVAL;
> > > > > > > >  }
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_reg_leng(uint8_t port_id) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length,
> > > -
> > > > > > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->get_reg_length)(dev);
> > > > > > > > +}
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_reg_info(uint8_t port_id, struct
> > > > > > > > +rte_dev_reg_info
> > > > > > > > +*info) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -
> > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->get_reg)(dev, info); }
> > > > > > >
> > > > > > > Seems that *get_reg* stuff, will be really good addition for
> > > > > > > DPDK debugging abilities.
> > > > > > > Though, I'd suggest we change it a bit to make more generic
> > > > > > > and
> > > flexible:
> > > > > > >
> > > > > > > Introduce rte_eth_reg_read/rte_eth_reg_write(),
> > > > > > > or probably even better rte_pcidev_reg_read
> > > > > > > /rte_pcidev_reg_write at
> > > > > EAL.
> > > > > > > Something similar to what
> > > > > > > port_pci_reg_read/port_pci_reg_write()
> > > > > > > are doing now at testpmd.h.
> > > > > > >
> > > > > > > struct rte_pcidev_reg_info {
> > > > > > >    const char *name;
> > > > > > >    uint32_t endianes, bar, offset, size, count; };
> > > > > > >
> > > > > > > int rte_pcidev_reg_read(const struct rte_pci_device *, const
> > > > > > > struct rte_pcidev_reg_info *, uint64_t *reg_val);
> > > > > > >
> > > > > > > Then:
> > > > > > > int rte_eth_dev_get_reg_info(port_id, const struct
> > > > > > > rte_pcidev_reg_info **info);
> > > > > > >
> > > > > > > So each device would store in info a pointer to an array of
> > > > > > > it's register descriptions (finished by zero elem?).
> > > > > > >
> > > > > > > Then your ethtool (or any other upper layer) can do the
> > > > > > > following to read all device regs:
> > > > > > >
> > > > > >
> > > > > > The proposed reg info structure allows future improvement to
> > > > > > support
> > > > > individual register read/write.
> > > > > > Also, because each NIC device has a very distinguish register
> definition.
> > > > > > So, the plan is to have more comprehensive interface to
> > > > > > support query operation (for example, register name) before
> > > > > > introduce individual/group
> > > > > register access.
> > > > > > Points taken, the support will be in future release.
> > > > >
> > > > > Sorry, didn't get you.
> > > > > So you are ok to make these changes in next patch version?
> > > > >
> > > > I would like to get a consensus from dpdk community on how to
> > > > provide
> > > register information.
> > >
> > > Well, that' ok, but if it is just a trial patch that is not intended
> > > to be applied, then you should mark it as RFC.
> > >
> > > > Currently, it's designed for debug dumping. The register
> > > > information is very
> > > hardware dependent.
> > > > Need to consider current supported NIC device and future devices
> > > > for
> > > DPDK, so we won't make it a bulky interface.
> > >
> > > Ok, could you explain what exactly  concerns you in the approach
> > > described above?
> > > What part you feel is bulky?
> > >
> > > > > >
> > > > > > > const struct rte_eth_dev_reg_info *reg_info; struct
> > > > > > > rte_eth_dev_info dev_info;
> > > > > > >
> > > > > > > rte_eth_dev_info_get(pid, &dev_info);
> > > > > > > rte_eth_dev_get_reg_info(port_id, &reg_info);
> > > > > > >
> > > > > > > for (i = 0; reg_info[i].name != NULL; i++) {
> > > > > > >    ...
> > > > > > >    rte_pcidev_read_reg(dev_info. pci_dev, reg_info[i], &v);
> > > > > > >   ..
> > > > > > > }
> > > > > > >
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_eeprom_leng(uint8_t port_id) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > > >get_eeprom_length, -
> > > > > > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->get_eeprom_length)(dev);
> > > > > > > > +}
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_get_eeprom(uint8_t port_id, struct
> > > > > > > > +rte_dev_eeprom_info
> > > > > > > > +*info) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -
> > > > > > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->get_eeprom)(dev, info); }
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_set_eeprom(uint8_t port_id, struct
> > > > > > > > +rte_dev_eeprom_info
> > > > > > > > +*info) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -
> > > > > > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->set_eeprom)(dev, info); }
> > > > > > > > +
> > > > > > > > +int
> > > > > > > > +rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > > > > > > +rte_dev_ring_info
> > > > > > > > +*info) {
> > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > +
> > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > port_id);
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > +		return -ENODEV;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> > > > > > > ENOTSUP);
> > > > > > > > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> > > > > > >
> > > > > > > I think it will be a useful addition to the ethdev API  to
> > > > > > > have an ability to retrieve current RX/TX queue parameters.
> > > > > > > Though again, it need to be more generic, so it could be
> > > > > > > useful for
> > > > > > > non- ethtool upper layer too.
> > > > > > > So I suggest to modify it a bit.
> > > > > > > Something like that:
> > > > > > >
> > > > > > > struct rte_eth_tx_queue_info {
> > > > > > >     struct rte_eth_txconf txconf;
> > > > > > >     uint32_t nb_tx_desc;
> > > > > > >     uint32_t nb_max_tx_desc; /*max allowable TXDs for that
> queue */
> > > > > > >     uint32_t nb_tx_free;            /* number of free TXDs at
> the moment
> > > of
> > > > > call.
> > > > > > > */
> > > > > > >     /* other tx queue data. */ };
> > > > > > >
> > > > > > > int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> > > > > > > rte_eth_tx_queue_info *qinfo)
> > > > > > >
> > > > > > > Then, your upper layer ethtool wrapper, can implement yours
> > > > > > > ethtool_get_ringparam() by:
> > > > > > >
> > > > > > >  ...
> > > > > > >  struct rte_eth_tx_queue_info qinfo;
> > > > > > > rte_ethdev_get_tx_queue_info(port, 0, &qinfo);
> > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > rte_eth_rx_queue_count(port, 0);
> > > > > > >
> > > > > > > Or probably even:
> > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > qinfo.nb_tx_free;
> > > > > > >
> > > > > > > Same for RX.
> > > > > > >
> > > > > > For now, this descriptor ring information is used by the ethtool
> op.
> > > > > > To make this interface simple, i.e. caller doesn't need to
> > > > > > access other
> > > > > queue information.
> > > > >
> > > > > I just repeat what I said to you in off-line conversation:
> > > > > ethdev API is not equal ethtool API.
> > > > > It is ok to add  a new function/structure to ethdev if it really
> > > > > needed, but we should do mechanical one to one copy.
> > > > > It is much better to add  a function/structure that would be
> > > > > more generic, and suit other users, not only ethtool.
> > > > > There is no point to have dozen functions in rte_ethdev API
> > > > > providing similar information.
> > > > > BTW, I don't see how API I proposed is much more  complex, then
> > > > > yours
> > > one.
> > > > The ring parameter is a run-time information which is different
> > > > than data
> > > structure described in this discussion.
> > >
> > > I don't see how they are different.
> > > Looking at ixgbe_get_ringparam(), it returns:
> > > rx_max_pending - that's a static IXGBE PMD value (max possible
> > > number of RXDs per one queue).
> > > rx_pending - number of RXD currently in use by the HW for queue 0
> > > (that information can be changed at each call).
> > >
> > > With the approach I suggesting - you can get same information for
> > > each RX queue by calling rte_ethdev_get_rx_queue_info() and
> > > rte_eth_rx_queue_count().
> > > Plus you are getting other RX queue data.
> > >
> > > Another thing - what is practical usage of the information you
> > > retrieving now by get_ringparam()?
> > > Let say it returned to you: rx_max_pending=4096; rx_pending=128; How
> > > that information would help to understand what is going on with the
> device?
> > > Without knowing  value of nb_tx_desc for the queue, you can't say is
> > > you queue full or not.
> > > Again, it could be that all your traffic going through some other
> > > queue (not 0).
> > > So from my point rte_eth_dev_get_ringparam()  usage is very limited,
> > > and doesn't provide enough information about current queue state.
> > >
> > > Same thing applies for TX.
> > >
> >
> > After careful review the suggestion in this comment, and review the
> existing dpdk source code.
> > I came to realize that neither rte_ethdev_get_rx_queue_info,
> > rte_ethdev_get_tx_queue_info, struct rte_eth_rx_queue_info and struct
> > rte_eth_tx_queue_info are available in the existing dpdk source code. I
> could not make a patch based upon a set of non- existent API and data
> structure.
> 
> Right now, in dpdk.org source code, struct  rte_eth_dev_ring_info, struct
> rte_dev_eeprom_info and struct  rte_dev_reg_info don't exist also.
> Same as  all these functions:
> 
> rte_eth_dev_default_mac_addr_set
> rte_eth_dev_reg_length
> rte_eth_dev_reg_info
> rte_eth_dev_eeprom_length
> rte_eth_dev_get_eeprom
> rte_eth_dev_set_eeprom
> rte_eth_dev_get_ringparam
> 
> All this is a new API that's you are trying to add.
> But, by some reason you consider it is ok to add 'struct
> rte_eth_dev_ring_info', but couldn't add  struct
> 'rte_ethdev_get_tx_queue_info'
> That just doesn't make any sense to me.
> In fact, I think our conversation is going in cycles.
> If you are not happy with the suggested approach, please provide some
> meaningful reason why.
> Konstantin

It seems the new API aims at providing users a mechanism to quickly and 
gracefully migrate from using ethtool/ioctl calls.  The provided get/set 
ring param info is very similar to that of ethtool and facilitates the
ethtool needs.

While additional enhancements to the API to provide additional details 
such as those you have suggested are certainly possible, I believe Larry 
is stating those ideas are outside the scope he has intended with the 
API introduction and that they should be discussed further and delivered
in a future patch.

Does that seem reasonable?

Thanks,
Dave

> 
> >
> > > > It's the desire of this patch to separate each data structure to
> > > > avoid cross
> > > dependency.
> > >
> > > That's too cryptic to me.
> > > Could you explain what cross dependency you are talking about?
> > >
> > > Konstantin

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-15 14:47                   ` Wang, Liang-min
@ 2015-06-15 18:10                     ` Ananyev, Konstantin
  2015-06-17 17:25                       ` Ananyev, Konstantin
  0 siblings, 1 reply; 174+ messages in thread
From: Ananyev, Konstantin @ 2015-06-15 18:10 UTC (permalink / raw)
  To: Wang, Liang-min, dev



> -----Original Message-----
> From: Wang, Liang-min
> Sent: Monday, June 15, 2015 3:47 PM
> To: Ananyev, Konstantin; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
> 
> 
> 
> > -----Original Message-----
> > From: Ananyev, Konstantin
> > Sent: Monday, June 15, 2015 9:46 AM
> > To: Wang, Liang-min; dev@dpdk.org
> > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> > device info
> >
> >
> >
> > > -----Original Message-----
> > > From: Wang, Liang-min
> > > Sent: Monday, June 15, 2015 2:26 PM
> > > To: Ananyev, Konstantin; dev@dpdk.org
> > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > access device info
> > >
> > >
> > >
> > > > -----Original Message-----
> > > > From: Ananyev, Konstantin
> > > > Sent: Friday, June 12, 2015 8:31 AM
> > > > To: Wang, Liang-min; dev@dpdk.org
> > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > access device info
> > > >
> > > >
> > > >
> > > > > -----Original Message-----
> > > > > From: Wang, Liang-min
> > > > > Sent: Thursday, June 11, 2015 10:51 PM
> > > > > To: Ananyev, Konstantin; dev@dpdk.org
> > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > > access device info
> > > > >
> > > > >
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: Ananyev, Konstantin
> > > > > > Sent: Thursday, June 11, 2015 9:07 AM
> > > > > > To: Wang, Liang-min; dev@dpdk.org
> > > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > support access device info
> > > > > >
> > > > > >
> > > > > >
> > > > > > > -----Original Message-----
> > > > > > > From: Wang, Liang-min
> > > > > > > Sent: Thursday, June 11, 2015 1:58 PM
> > > > > > > To: Ananyev, Konstantin; dev@dpdk.org
> > > > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > > support access device info
> > > > > > >
> > > > > > > Hi Konstantin,
> > > > > > >
> > > > > > > > -----Original Message-----
> > > > > > > > From: Ananyev, Konstantin
> > > > > > > > Sent: Thursday, June 11, 2015 8:26 AM
> > > > > > > > To: Wang, Liang-min; dev@dpdk.org
> > > > > > > > Cc: Wang, Liang-min
> > > > > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > > > support access device info
> > > > > > > >
> > > > > > > > Hi Larry,
> > > > > > > >
> > > > > > > > > -----Original Message-----
> > > > > > > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of
> > > > > > > > > Liang-Min Larry Wang
> > > > > > > > > Sent: Wednesday, June 10, 2015 4:10 PM
> > > > > > > > > To: dev@dpdk.org
> > > > > > > > > Cc: Wang, Liang-min
> > > > > > > > > Subject: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > > > > support access device info
> > > > > > > > >
> > > > > > > > > add new apis:
> > > > > > > > > - rte_eth_dev_default_mac_addr_set
> > > > > > > > > - rte_eth_dev_reg_leng
> > > > > > > > > - rte_eth_dev_reg_info
> > > > > > > > > - rte_eth_dev_eeprom_leng
> > > > > > > > > - rte_eth_dev_get_eeprom
> > > > > > > > > - rte_eth_dev_set_eeprom
> > > > > > > > > - rte_eth_dev_get_ringparam
> > > > > > > > > - rte_eth_dev_set_ringparam
> > > > > > > > >
> > > > > > > > > to enable reading device parameters (mac-addr, register,
> > > > > > > > > eeprom,
> > > > > > > > > ring) based upon ethtool alike data parameter specification.
> > > > > > > > >
> > > > > > > > > Signed-off-by: Liang-Min Larry Wang
> > > > > > > > > <liang-min.wang@intel.com>
> > > > > > > > > ---
> > > > > > > > >  lib/librte_ether/Makefile              |   1 +
> > > > > > > > >  lib/librte_ether/rte_eth_dev_info.h    |  80
> > +++++++++++++++++
> > > > > > > > >  lib/librte_ether/rte_ethdev.c          | 159
> > > > > > > > +++++++++++++++++++++++++++++++++
> > > > > > > > >  lib/librte_ether/rte_ethdev.h          | 158
> > > > > > > > ++++++++++++++++++++++++++++++++
> > > > > > > > >  lib/librte_ether/rte_ether_version.map |   8 ++
> > > > > > > > >  5 files changed, 406 insertions(+)  create mode 100644
> > > > > > > > > lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > >
> > > > > > > > > diff --git a/lib/librte_ether/Makefile
> > > > > > > > > b/lib/librte_ether/Makefile index c0e5768..05209e9 100644
> > > > > > > > > --- a/lib/librte_ether/Makefile
> > > > > > > > > +++ b/lib/librte_ether/Makefile
> > > > > > > > > @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
> > > > > > > > > SYMLINK-y-include += rte_ether.h  SYMLINK-y-include +=
> > > > > > > > > rte_ethdev.h SYMLINK-y-include
> > > > > > > > > += rte_eth_ctrl.h
> > > > > > > > > +SYMLINK-y-include += rte_eth_dev_info.h
> > > > > > > > >
> > > > > > > > >  # this lib depends upon:
> > > > > > > > >  DEPDIRS-y += lib/librte_eal lib/librte_mempool
> > > > > > > > > lib/librte_ring lib/librte_mbuf diff --git
> > > > > > > > > a/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > > b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > > new file mode 100644
> > > > > > > > > index 0000000..002c4b5
> > > > > > > > > --- /dev/null
> > > > > > > > > +++ b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > > @@ -0,0 +1,80 @@
> > > > > > > > > +/*-
> > > > > > > > > + *   BSD LICENSE
> > > > > > > > > + *
> > > > > > > > > + *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> > > > > > > > > + *   All rights reserved.
> > > > > > > > > + *
> > > > > > > > > + *   Redistribution and use in source and binary forms, with or
> > > > without
> > > > > > > > > + *   modification, are permitted provided that the following
> > > > conditions
> > > > > > > > > + *   are met:
> > > > > > > > > + *
> > > > > > > > > + *     * Redistributions of source code must retain the above
> > > > copyright
> > > > > > > > > + *       notice, this list of conditions and the following disclaimer.
> > > > > > > > > + *     * Redistributions in binary form must reproduce the above
> > > > > > copyright
> > > > > > > > > + *       notice, this list of conditions and the following disclaimer
> > in
> > > > > > > > > + *       the documentation and/or other materials provided with
> > the
> > > > > > > > > + *       distribution.
> > > > > > > > > + *     * Neither the name of Intel Corporation nor the names of
> > its
> > > > > > > > > + *       contributors may be used to endorse or promote
> > products
> > > > > > derived
> > > > > > > > > + *       from this software without specific prior written
> > permission.
> > > > > > > > > + *
> > > > > > > > > + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
> > AND
> > > > > > > > CONTRIBUTORS
> > > > > > > > > + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> > > > INCLUDING,
> > > > > > BUT
> > > > > > > > NOT
> > > > > > > > > + *   LIMITED TO, THE IMPLIED WARRANTIES OF
> > MERCHANTABILITY
> > > > AND
> > > > > > > > FITNESS FOR
> > > > > > > > > + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
> > SHALL
> > > > THE
> > > > > > > > COPYRIGHT
> > > > > > > > > + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
> > > > INDIRECT,
> > > > > > > > INCIDENTAL,
> > > > > > > > > + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> > > > > > (INCLUDING,
> > > > > > > > BUT NOT
> > > > > > > > > + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> > > > SERVICES;
> > > > > > > > LOSS OF USE,
> > > > > > > > > + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> > HOWEVER
> > > > > > CAUSED
> > > > > > > > AND ON ANY
> > > > > > > > > + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> > > > LIABILITY,
> > > > > > OR
> > > > > > > > TORT
> > > > > > > > > + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> > > > WAY
> > > > > > OUT
> > > > > > > > OF THE USE
> > > > > > > > > + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
> > OF
> > > > SUCH
> > > > > > > > DAMAGE.
> > > > > > > > > + */
> > > > > > > > > +
> > > > > > > > > +#ifndef _RTE_ETH_DEV_INFO_H_ #define
> > _RTE_ETH_DEV_INFO_H_
> > > > > > > > > +
> > > > > > > > > +
> > > > > > > > > +/*
> > > > > > > > > + * Placeholder for accessing device registers  */ struct
> > > > > > > > > +rte_dev_reg_info {
> > > > > > > > > +	void *buf; /**< Buffer for register */
> > > > > > > > > +	uint32_t offset; /**< Offset for 1st register to fetch */
> > > > > > > > > +	uint32_t leng; /**< Number of registers to fetch */
> > > > > > > > > +	uint32_t version; /**< Device version */ };
> > > > > > > > > +
> > > > > > > > > +/*
> > > > > > > > > + * Placeholder for accessing device eeprom  */ struct
> > > > > > > > > +rte_dev_eeprom_info {
> > > > > > > > > +	void *buf; /**< Buffer for eeprom */
> > > > > > > > > +	uint32_t offset; /**< Offset for 1st eeprom location to
> > > > > > > > > +access
> > > > */
> > > > > > > > > +	uint32_t leng; /**< Length of eeprom region to access */
> > > > > > > > > +	uint32_t magic; /**< Device ID */ };
> > > > > > > > > +
> > > > > > > > > +/*
> > > > > > > > > + * Placeholder for accessing device ring parameters  */
> > > > > > > > > +struct rte_dev_ring_info {
> > > > > > > > > +	uint32_t rx_pending; /**< Number of outstanding Rx ring */
> > > > > > > > > +	uint32_t tx_pending; /**< Number of outstanding Tx ring */
> > > > > > > > > +	uint32_t rx_max_pending; /**< Maximum number of
> > > > outstanding
> > > > > > > > > +Rx
> > > > > > > > ring */
> > > > > > > > > +	uint32_t tx_max_pending; /**< Maximum number of
> > > > outstanding
> > > > > > > > > +Tx
> > > > > > > > ring
> > > > > > > > > +*/ };
> > > > > > > > > +
> > > > > > > > > +/*
> > > > > > > > > + * A data structure captures information as defined in
> > > > > > > > > +struct ifla_vf_info
> > > > > > > > > + * for user-space api
> > > > > > > > > + */
> > > > > > > > > +struct rte_dev_vf_info {
> > > > > > > > > +	uint32_t vf;
> > > > > > > > > +	uint8_t mac[ETHER_ADDR_LEN];
> > > > > > > > > +	uint32_t vlan;
> > > > > > > > > +	uint32_t tx_rate;
> > > > > > > > > +	uint32_t spoofchk;
> > > > > > > > > +};
> > > > > > > >
> > > > > > > >
> > > > > > > > Wonder what that structure is for?
> > > > > > > > I can't see it used in any function below?
> > > > > > > >
> > > > > > >
> > > > > > > Good catch, this is designed for other ethtool ops that I did
> > > > > > > not include in
> > > > > > this release, I will remove this from next fix.
> > > > > > >
> > > > > > > > > +
> > > > > > > > > +#endif /* _RTE_ETH_DEV_INFO_H_ */
> > > > > > > > > diff --git a/lib/librte_ether/rte_ethdev.c
> > > > > > > > > b/lib/librte_ether/rte_ethdev.c index 5a94654..186e85c
> > > > > > > > > 100644
> > > > > > > > > --- a/lib/librte_ether/rte_ethdev.c
> > > > > > > > > +++ b/lib/librte_ether/rte_ethdev.c
> > > > > > > > > @@ -2751,6 +2751,32 @@
> > rte_eth_dev_mac_addr_remove(uint8_t
> > > > > > > > port_id,
> > > > > > > > > struct ether_addr *addr)  }
> > > > > > > > >
> > > > > > > > >  int
> > > > > > > > > +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct
> > > > > > > > > +ether_addr
> > > > > > > > > +*addr) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +	const int index = 0;
> > > > > > > > > +	const uint32_t pool = 0;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	dev = &rte_eth_devices[port_id];
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > > > >mac_addr_remove, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +
> > > > > > > > > +	/* Update NIC default MAC address*/
> > > > > > > > > +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> > > > > > > > > +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> > > > > > > > > +
> > > > > > > > > +	/* Update default address in NIC data structure */
> > > > > > > > > +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> > > > > > > > > +
> > > > > > > > > +	return 0;
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > >  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
> > > > > > > > >  				uint16_t rx_mode, uint8_t on)  { @@
> > > > -3627,3
> > > > > > +3653,136 @@
> > > > > > > > > rte_eth_remove_tx_callback(uint8_t port_id,
> > > > > > > > uint16_t queue_id,
> > > > > > > > >  	/* Callback wasn't found. */
> > > > > > > > >  	return -EINVAL;
> > > > > > > > >  }
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_reg_leng(uint8_t port_id) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length,
> > > > -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->get_reg_length)(dev);
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_reg_info(uint8_t port_id, struct
> > > > > > > > > +rte_dev_reg_info
> > > > > > > > > +*info) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -
> > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->get_reg)(dev, info); }
> > > > > > > >
> > > > > > > > Seems that *get_reg* stuff, will be really good addition for
> > > > > > > > DPDK debugging abilities.
> > > > > > > > Though, I'd suggest we change it a bit to make more generic
> > > > > > > > and
> > > > flexible:
> > > > > > > >
> > > > > > > > Introduce rte_eth_reg_read/rte_eth_reg_write(),
> > > > > > > > or probably even better rte_pcidev_reg_read
> > > > > > > > /rte_pcidev_reg_write at
> > > > > > EAL.
> > > > > > > > Something similar to what
> > > > > > > > port_pci_reg_read/port_pci_reg_write()
> > > > > > > > are doing now at testpmd.h.
> > > > > > > >
> > > > > > > > struct rte_pcidev_reg_info {
> > > > > > > >    const char *name;
> > > > > > > >    uint32_t endianes, bar, offset, size, count; };
> > > > > > > >
> > > > > > > > int rte_pcidev_reg_read(const struct rte_pci_device *, const
> > > > > > > > struct rte_pcidev_reg_info *, uint64_t *reg_val);
> > > > > > > >
> > > > > > > > Then:
> > > > > > > > int rte_eth_dev_get_reg_info(port_id, const struct
> > > > > > > > rte_pcidev_reg_info **info);
> > > > > > > >
> > > > > > > > So each device would store in info a pointer to an array of
> > > > > > > > it's register descriptions (finished by zero elem?).
> > > > > > > >
> > > > > > > > Then your ethtool (or any other upper layer) can do the
> > > > > > > > following to read all device regs:
> > > > > > > >
> > > > > > >
> > > > > > > The proposed reg info structure allows future improvement to
> > > > > > > support
> > > > > > individual register read/write.
> > > > > > > Also, because each NIC device has a very distinguish register
> > definition.
> > > > > > > So, the plan is to have more comprehensive interface to
> > > > > > > support query operation (for example, register name) before
> > > > > > > introduce individual/group
> > > > > > register access.
> > > > > > > Points taken, the support will be in future release.
> > > > > >
> > > > > > Sorry, didn't get you.
> > > > > > So you are ok to make these changes in next patch version?
> > > > > >
> > > > > I would like to get a consensus from dpdk community on how to
> > > > > provide
> > > > register information.
> > > >
> > > > Well, that' ok, but if it is just a trial patch that is not intended
> > > > to be applied, then you should mark it as RFC.
> > > >
> > > > > Currently, it's designed for debug dumping. The register
> > > > > information is very
> > > > hardware dependent.
> > > > > Need to consider current supported NIC device and future devices
> > > > > for
> > > > DPDK, so we won't make it a bulky interface.
> > > >
> > > > Ok, could you explain what exactly  concerns you in the approach
> > > > described above?
> > > > What part you feel is bulky?
> > > >
> > > > > > >
> > > > > > > > const struct rte_eth_dev_reg_info *reg_info; struct
> > > > > > > > rte_eth_dev_info dev_info;
> > > > > > > >
> > > > > > > > rte_eth_dev_info_get(pid, &dev_info);
> > > > > > > > rte_eth_dev_get_reg_info(port_id, &reg_info);
> > > > > > > >
> > > > > > > > for (i = 0; reg_info[i].name != NULL; i++) {
> > > > > > > >    ...
> > > > > > > >    rte_pcidev_read_reg(dev_info. pci_dev, reg_info[i], &v);
> > > > > > > >   ..
> > > > > > > > }
> > > > > > > >
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_eeprom_leng(uint8_t port_id) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > > > >get_eeprom_length, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->get_eeprom_length)(dev);
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_get_eeprom(uint8_t port_id, struct
> > > > > > > > > +rte_dev_eeprom_info
> > > > > > > > > +*info) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->get_eeprom)(dev, info); }
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_set_eeprom(uint8_t port_id, struct
> > > > > > > > > +rte_dev_eeprom_info
> > > > > > > > > +*info) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->set_eeprom)(dev, info); }
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > > > > > > > +rte_dev_ring_info
> > > > > > > > > +*info) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> > > > > > > >
> > > > > > > > I think it will be a useful addition to the ethdev API  to
> > > > > > > > have an ability to retrieve current RX/TX queue parameters.
> > > > > > > > Though again, it need to be more generic, so it could be
> > > > > > > > useful for
> > > > > > > > non- ethtool upper layer too.
> > > > > > > > So I suggest to modify it a bit.
> > > > > > > > Something like that:
> > > > > > > >
> > > > > > > > struct rte_eth_tx_queue_info {
> > > > > > > >     struct rte_eth_txconf txconf;
> > > > > > > >     uint32_t nb_tx_desc;
> > > > > > > >     uint32_t nb_max_tx_desc; /*max allowable TXDs for that
> > queue */
> > > > > > > >     uint32_t nb_tx_free;            /* number of free TXDs at the
> > moment
> > > > of
> > > > > > call.
> > > > > > > > */
> > > > > > > >     /* other tx queue data. */ };
> > > > > > > >
> > > > > > > > int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> > > > > > > > rte_eth_tx_queue_info *qinfo)
> > > > > > > >
> > > > > > > > Then, your upper layer ethtool wrapper, can implement yours
> > > > > > > > ethtool_get_ringparam() by:
> > > > > > > >
> > > > > > > >  ...
> > > > > > > >  struct rte_eth_tx_queue_info qinfo;
> > > > > > > > rte_ethdev_get_tx_queue_info(port, 0, &qinfo);
> > > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > > rte_eth_rx_queue_count(port, 0);
> > > > > > > >
> > > > > > > > Or probably even:
> > > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > > qinfo.nb_tx_free;
> > > > > > > >
> > > > > > > > Same for RX.
> > > > > > > >
> > > > > > > For now, this descriptor ring information is used by the ethtool op.
> > > > > > > To make this interface simple, i.e. caller doesn't need to
> > > > > > > access other
> > > > > > queue information.
> > > > > >
> > > > > > I just repeat what I said to you in off-line conversation:
> > > > > > ethdev API is not equal ethtool API.
> > > > > > It is ok to add  a new function/structure to ethdev if it really
> > > > > > needed, but we should do mechanical one to one copy.
> > > > > > It is much better to add  a function/structure that would be
> > > > > > more generic, and suit other users, not only ethtool.
> > > > > > There is no point to have dozen functions in rte_ethdev API
> > > > > > providing similar information.
> > > > > > BTW, I don't see how API I proposed is much more  complex, then
> > > > > > yours
> > > > one.
> > > > > The ring parameter is a run-time information which is different
> > > > > than data
> > > > structure described in this discussion.
> > > >
> > > > I don't see how they are different.
> > > > Looking at ixgbe_get_ringparam(), it returns:
> > > > rx_max_pending - that's a static IXGBE PMD value (max possible
> > > > number of RXDs per one queue).
> > > > rx_pending - number of RXD currently in use by the HW for queue 0
> > > > (that information can be changed at each call).
> > > >
> > > > With the approach I suggesting - you can get same information for
> > > > each RX queue by calling rte_ethdev_get_rx_queue_info() and
> > > > rte_eth_rx_queue_count().
> > > > Plus you are getting other RX queue data.
> > > >
> > > > Another thing - what is practical usage of the information you
> > > > retrieving now by get_ringparam()?
> > > > Let say it returned to you: rx_max_pending=4096; rx_pending=128; How
> > > > that information would help to understand what is going on with the
> > device?
> > > > Without knowing  value of nb_tx_desc for the queue, you can't say is
> > > > you queue full or not.
> > > > Again, it could be that all your traffic going through some other
> > > > queue (not 0).
> > > > So from my point rte_eth_dev_get_ringparam()  usage is very limited,
> > > > and doesn't provide enough information about current queue state.
> > > >
> > > > Same thing applies for TX.
> > > >
> > >
> > > After careful review the suggestion in this comment, and review the
> > existing dpdk source code.
> > > I came to realize that neither rte_ethdev_get_rx_queue_info,
> > > rte_ethdev_get_tx_queue_info, struct rte_eth_rx_queue_info and struct
> > > rte_eth_tx_queue_info are available in the existing dpdk source code. I
> > could not make a patch based upon a set of non- existent API and data
> > structure.
> >
> > Right now, in dpdk.org source code, struct  rte_eth_dev_ring_info, struct
> > rte_dev_eeprom_info and struct  rte_dev_reg_info don't exist also.
> > Same as  all these functions:
> >
> > rte_eth_dev_default_mac_addr_set
> > rte_eth_dev_reg_length
> > rte_eth_dev_reg_info
> > rte_eth_dev_eeprom_length
> > rte_eth_dev_get_eeprom
> > rte_eth_dev_set_eeprom
> > rte_eth_dev_get_ringparam
> >
> > All this is a new API that's you are trying to add.
> > But, by some reason you consider it is ok to add 'struct
> > rte_eth_dev_ring_info', but couldn't add  struct
> > 'rte_ethdev_get_tx_queue_info'
> > That just doesn't make any sense to me.
> > In fact, I think our conversation is going in cycles.
> > If you are not happy with the suggested approach, please provide some
> > meaningful reason why.
> 
> All the API's and data structure that you have questions in this comment are available from the submitted patch, you could run to see
> if it works.
> What I learned from your comments are a couple of API name and incomplete data structure description, so I could not make my
> patch according to your suggestion.
> If you strongly feel the API's that you are proposing are useful for get_ringparam(), please create a patch and submit it for evaluation.

Ok, I'll try to create a patch in next few days.
Hopefully it will make things clearer to you and fit everyone.
Konstantin

> As coded in this patch, it's a simple and clean interface and most important, it can be validated and it works.
> 
> > Konstantin
> >
> > >
> > > > > It's the desire of this patch to separate each data structure to
> > > > > avoid cross
> > > > dependency.
> > > >
> > > > That's too cryptic to me.
> > > > Could you explain what cross dependency you are talking about?
> > > >
> > > > Konstantin

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-15 16:05                   ` David Harton (dharton)
@ 2015-06-15 18:23                     ` Ananyev, Konstantin
  2015-06-16 18:15                       ` Ananyev, Konstantin
  0 siblings, 1 reply; 174+ messages in thread
From: Ananyev, Konstantin @ 2015-06-15 18:23 UTC (permalink / raw)
  To: David Harton (dharton), Wang, Liang-min, dev



> -----Original Message-----
> From: David Harton (dharton) [mailto:dharton@cisco.com]
> Sent: Monday, June 15, 2015 5:05 PM
> To: Ananyev, Konstantin; Wang, Liang-min; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
> 
> 
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ananyev, Konstantin
> > Sent: Monday, June 15, 2015 9:46 AM
> > To: Wang, Liang-min; dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access
> > device info
> >
> >
> >
> > > -----Original Message-----
> > > From: Wang, Liang-min
> > > Sent: Monday, June 15, 2015 2:26 PM
> > > To: Ananyev, Konstantin; dev@dpdk.org
> > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > access device info
> > >
> > >
> > >
> > > > -----Original Message-----
> > > > From: Ananyev, Konstantin
> > > > Sent: Friday, June 12, 2015 8:31 AM
> > > > To: Wang, Liang-min; dev@dpdk.org
> > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > access device info
> > > >
> > > >
> > > >
> > > > > -----Original Message-----
> > > > > From: Wang, Liang-min
> > > > > Sent: Thursday, June 11, 2015 10:51 PM
> > > > > To: Ananyev, Konstantin; dev@dpdk.org
> > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support
> > > > > access device info
> > > > >
> > > > >
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: Ananyev, Konstantin
> > > > > > Sent: Thursday, June 11, 2015 9:07 AM
> > > > > > To: Wang, Liang-min; dev@dpdk.org
> > > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > support access device info
> > > > > >
> > > > > >
> > > > > >
> > > > > > > -----Original Message-----
> > > > > > > From: Wang, Liang-min
> > > > > > > Sent: Thursday, June 11, 2015 1:58 PM
> > > > > > > To: Ananyev, Konstantin; dev@dpdk.org
> > > > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > > support access device info
> > > > > > >
> > > > > > > Hi Konstantin,
> > > > > > >
> > > > > > > > -----Original Message-----
> > > > > > > > From: Ananyev, Konstantin
> > > > > > > > Sent: Thursday, June 11, 2015 8:26 AM
> > > > > > > > To: Wang, Liang-min; dev@dpdk.org
> > > > > > > > Cc: Wang, Liang-min
> > > > > > > > Subject: RE: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > > > support access device info
> > > > > > > >
> > > > > > > > Hi Larry,
> > > > > > > >
> > > > > > > > > -----Original Message-----
> > > > > > > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of
> > > > > > > > > Liang-Min Larry Wang
> > > > > > > > > Sent: Wednesday, June 10, 2015 4:10 PM
> > > > > > > > > To: dev@dpdk.org
> > > > > > > > > Cc: Wang, Liang-min
> > > > > > > > > Subject: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to
> > > > > > > > > support access device info
> > > > > > > > >
> > > > > > > > > add new apis:
> > > > > > > > > - rte_eth_dev_default_mac_addr_set
> > > > > > > > > - rte_eth_dev_reg_leng
> > > > > > > > > - rte_eth_dev_reg_info
> > > > > > > > > - rte_eth_dev_eeprom_leng
> > > > > > > > > - rte_eth_dev_get_eeprom
> > > > > > > > > - rte_eth_dev_set_eeprom
> > > > > > > > > - rte_eth_dev_get_ringparam
> > > > > > > > > - rte_eth_dev_set_ringparam
> > > > > > > > >
> > > > > > > > > to enable reading device parameters (mac-addr, register,
> > > > > > > > > eeprom,
> > > > > > > > > ring) based upon ethtool alike data parameter specification.
> > > > > > > > >
> > > > > > > > > Signed-off-by: Liang-Min Larry Wang
> > > > > > > > > <liang-min.wang@intel.com>
> > > > > > > > > ---
> > > > > > > > >  lib/librte_ether/Makefile              |   1 +
> > > > > > > > >  lib/librte_ether/rte_eth_dev_info.h    |  80
> > +++++++++++++++++
> > > > > > > > >  lib/librte_ether/rte_ethdev.c          | 159
> > > > > > > > +++++++++++++++++++++++++++++++++
> > > > > > > > >  lib/librte_ether/rte_ethdev.h          | 158
> > > > > > > > ++++++++++++++++++++++++++++++++
> > > > > > > > >  lib/librte_ether/rte_ether_version.map |   8 ++
> > > > > > > > >  5 files changed, 406 insertions(+)  create mode 100644
> > > > > > > > > lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > >
> > > > > > > > > diff --git a/lib/librte_ether/Makefile
> > > > > > > > > b/lib/librte_ether/Makefile index c0e5768..05209e9 100644
> > > > > > > > > --- a/lib/librte_ether/Makefile
> > > > > > > > > +++ b/lib/librte_ether/Makefile
> > > > > > > > > @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
> > > > > > > > > SYMLINK-y-include += rte_ether.h  SYMLINK-y-include +=
> > > > > > > > > rte_ethdev.h SYMLINK-y-include
> > > > > > > > > += rte_eth_ctrl.h
> > > > > > > > > +SYMLINK-y-include += rte_eth_dev_info.h
> > > > > > > > >
> > > > > > > > >  # this lib depends upon:
> > > > > > > > >  DEPDIRS-y += lib/librte_eal lib/librte_mempool
> > > > > > > > > lib/librte_ring lib/librte_mbuf diff --git
> > > > > > > > > a/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > > b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > > new file mode 100644
> > > > > > > > > index 0000000..002c4b5
> > > > > > > > > --- /dev/null
> > > > > > > > > +++ b/lib/librte_ether/rte_eth_dev_info.h
> > > > > > > > > @@ -0,0 +1,80 @@
> > > > > > > > > +/*-
> > > > > > > > > + *   BSD LICENSE
> > > > > > > > > + *
> > > > > > > > > + *   Copyright(c) 2015 Intel Corporation. All rights
> > reserved.
> > > > > > > > > + *   All rights reserved.
> > > > > > > > > + *
> > > > > > > > > + *   Redistribution and use in source and binary forms,
> > with or
> > > > without
> > > > > > > > > + *   modification, are permitted provided that the
> > following
> > > > conditions
> > > > > > > > > + *   are met:
> > > > > > > > > + *
> > > > > > > > > + *     * Redistributions of source code must retain the
> > above
> > > > copyright
> > > > > > > > > + *       notice, this list of conditions and the following
> > disclaimer.
> > > > > > > > > + *     * Redistributions in binary form must reproduce the
> > above
> > > > > > copyright
> > > > > > > > > + *       notice, this list of conditions and the following
> > disclaimer in
> > > > > > > > > + *       the documentation and/or other materials provided
> > with the
> > > > > > > > > + *       distribution.
> > > > > > > > > + *     * Neither the name of Intel Corporation nor the
> > names of its
> > > > > > > > > + *       contributors may be used to endorse or promote
> > products
> > > > > > derived
> > > > > > > > > + *       from this software without specific prior written
> > permission.
> > > > > > > > > + *
> > > > > > > > > + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > > > > > > > CONTRIBUTORS
> > > > > > > > > + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> > > > INCLUDING,
> > > > > > BUT
> > > > > > > > NOT
> > > > > > > > > + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
> > > > AND
> > > > > > > > FITNESS FOR
> > > > > > > > > + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
> > > > THE
> > > > > > > > COPYRIGHT
> > > > > > > > > + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
> > > > INDIRECT,
> > > > > > > > INCIDENTAL,
> > > > > > > > > + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> > > > > > (INCLUDING,
> > > > > > > > BUT NOT
> > > > > > > > > + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> > > > SERVICES;
> > > > > > > > LOSS OF USE,
> > > > > > > > > + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> > > > > > CAUSED
> > > > > > > > AND ON ANY
> > > > > > > > > + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> > > > LIABILITY,
> > > > > > OR
> > > > > > > > TORT
> > > > > > > > > + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
> > > > WAY
> > > > > > OUT
> > > > > > > > OF THE USE
> > > > > > > > > + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
> > OF
> > > > SUCH
> > > > > > > > DAMAGE.
> > > > > > > > > + */
> > > > > > > > > +
> > > > > > > > > +#ifndef _RTE_ETH_DEV_INFO_H_ #define _RTE_ETH_DEV_INFO_H_
> > > > > > > > > +
> > > > > > > > > +
> > > > > > > > > +/*
> > > > > > > > > + * Placeholder for accessing device registers  */ struct
> > > > > > > > > +rte_dev_reg_info {
> > > > > > > > > +	void *buf; /**< Buffer for register */
> > > > > > > > > +	uint32_t offset; /**< Offset for 1st register to fetch
> > */
> > > > > > > > > +	uint32_t leng; /**< Number of registers to fetch */
> > > > > > > > > +	uint32_t version; /**< Device version */ };
> > > > > > > > > +
> > > > > > > > > +/*
> > > > > > > > > + * Placeholder for accessing device eeprom  */ struct
> > > > > > > > > +rte_dev_eeprom_info {
> > > > > > > > > +	void *buf; /**< Buffer for eeprom */
> > > > > > > > > +	uint32_t offset; /**< Offset for 1st eeprom location to
> > > > > > > > > +access
> > > > */
> > > > > > > > > +	uint32_t leng; /**< Length of eeprom region to access */
> > > > > > > > > +	uint32_t magic; /**< Device ID */ };
> > > > > > > > > +
> > > > > > > > > +/*
> > > > > > > > > + * Placeholder for accessing device ring parameters  */
> > > > > > > > > +struct rte_dev_ring_info {
> > > > > > > > > +	uint32_t rx_pending; /**< Number of outstanding Rx ring
> > */
> > > > > > > > > +	uint32_t tx_pending; /**< Number of outstanding Tx ring
> > */
> > > > > > > > > +	uint32_t rx_max_pending; /**< Maximum number of
> > > > outstanding
> > > > > > > > > +Rx
> > > > > > > > ring */
> > > > > > > > > +	uint32_t tx_max_pending; /**< Maximum number of
> > > > outstanding
> > > > > > > > > +Tx
> > > > > > > > ring
> > > > > > > > > +*/ };
> > > > > > > > > +
> > > > > > > > > +/*
> > > > > > > > > + * A data structure captures information as defined in
> > > > > > > > > +struct ifla_vf_info
> > > > > > > > > + * for user-space api
> > > > > > > > > + */
> > > > > > > > > +struct rte_dev_vf_info {
> > > > > > > > > +	uint32_t vf;
> > > > > > > > > +	uint8_t mac[ETHER_ADDR_LEN];
> > > > > > > > > +	uint32_t vlan;
> > > > > > > > > +	uint32_t tx_rate;
> > > > > > > > > +	uint32_t spoofchk;
> > > > > > > > > +};
> > > > > > > >
> > > > > > > >
> > > > > > > > Wonder what that structure is for?
> > > > > > > > I can't see it used in any function below?
> > > > > > > >
> > > > > > >
> > > > > > > Good catch, this is designed for other ethtool ops that I did
> > > > > > > not include in
> > > > > > this release, I will remove this from next fix.
> > > > > > >
> > > > > > > > > +
> > > > > > > > > +#endif /* _RTE_ETH_DEV_INFO_H_ */
> > > > > > > > > diff --git a/lib/librte_ether/rte_ethdev.c
> > > > > > > > > b/lib/librte_ether/rte_ethdev.c index 5a94654..186e85c
> > > > > > > > > 100644
> > > > > > > > > --- a/lib/librte_ether/rte_ethdev.c
> > > > > > > > > +++ b/lib/librte_ether/rte_ethdev.c
> > > > > > > > > @@ -2751,6 +2751,32 @@ rte_eth_dev_mac_addr_remove(uint8_t
> > > > > > > > port_id,
> > > > > > > > > struct ether_addr *addr)  }
> > > > > > > > >
> > > > > > > > >  int
> > > > > > > > > +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct
> > > > > > > > > +ether_addr
> > > > > > > > > +*addr) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +	const int index = 0;
> > > > > > > > > +	const uint32_t pool = 0;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	dev = &rte_eth_devices[port_id];
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > > > >mac_addr_remove, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_add, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +
> > > > > > > > > +	/* Update NIC default MAC address*/
> > > > > > > > > +	(*dev->dev_ops->mac_addr_remove)(dev, index);
> > > > > > > > > +	(*dev->dev_ops->mac_addr_add)(dev, addr, index, pool);
> > > > > > > > > +
> > > > > > > > > +	/* Update default address in NIC data structure */
> > > > > > > > > +	ether_addr_copy(addr, &dev->data->mac_addrs[index]);
> > > > > > > > > +
> > > > > > > > > +	return 0;
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > >  rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
> > > > > > > > >  				uint16_t rx_mode, uint8_t on)  { @@
> > > > -3627,3
> > > > > > +3653,136 @@
> > > > > > > > > rte_eth_remove_tx_callback(uint8_t port_id,
> > > > > > > > uint16_t queue_id,
> > > > > > > > >  	/* Callback wasn't found. */
> > > > > > > > >  	return -EINVAL;
> > > > > > > > >  }
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_reg_leng(uint8_t port_id) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length,
> > > > -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->get_reg_length)(dev);
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_reg_info(uint8_t port_id, struct
> > > > > > > > > +rte_dev_reg_info
> > > > > > > > > +*info) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -
> > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->get_reg)(dev, info); }
> > > > > > > >
> > > > > > > > Seems that *get_reg* stuff, will be really good addition for
> > > > > > > > DPDK debugging abilities.
> > > > > > > > Though, I'd suggest we change it a bit to make more generic
> > > > > > > > and
> > > > flexible:
> > > > > > > >
> > > > > > > > Introduce rte_eth_reg_read/rte_eth_reg_write(),
> > > > > > > > or probably even better rte_pcidev_reg_read
> > > > > > > > /rte_pcidev_reg_write at
> > > > > > EAL.
> > > > > > > > Something similar to what
> > > > > > > > port_pci_reg_read/port_pci_reg_write()
> > > > > > > > are doing now at testpmd.h.
> > > > > > > >
> > > > > > > > struct rte_pcidev_reg_info {
> > > > > > > >    const char *name;
> > > > > > > >    uint32_t endianes, bar, offset, size, count; };
> > > > > > > >
> > > > > > > > int rte_pcidev_reg_read(const struct rte_pci_device *, const
> > > > > > > > struct rte_pcidev_reg_info *, uint64_t *reg_val);
> > > > > > > >
> > > > > > > > Then:
> > > > > > > > int rte_eth_dev_get_reg_info(port_id, const struct
> > > > > > > > rte_pcidev_reg_info **info);
> > > > > > > >
> > > > > > > > So each device would store in info a pointer to an array of
> > > > > > > > it's register descriptions (finished by zero elem?).
> > > > > > > >
> > > > > > > > Then your ethtool (or any other upper layer) can do the
> > > > > > > > following to read all device regs:
> > > > > > > >
> > > > > > >
> > > > > > > The proposed reg info structure allows future improvement to
> > > > > > > support
> > > > > > individual register read/write.
> > > > > > > Also, because each NIC device has a very distinguish register
> > definition.
> > > > > > > So, the plan is to have more comprehensive interface to
> > > > > > > support query operation (for example, register name) before
> > > > > > > introduce individual/group
> > > > > > register access.
> > > > > > > Points taken, the support will be in future release.
> > > > > >
> > > > > > Sorry, didn't get you.
> > > > > > So you are ok to make these changes in next patch version?
> > > > > >
> > > > > I would like to get a consensus from dpdk community on how to
> > > > > provide
> > > > register information.
> > > >
> > > > Well, that' ok, but if it is just a trial patch that is not intended
> > > > to be applied, then you should mark it as RFC.
> > > >
> > > > > Currently, it's designed for debug dumping. The register
> > > > > information is very
> > > > hardware dependent.
> > > > > Need to consider current supported NIC device and future devices
> > > > > for
> > > > DPDK, so we won't make it a bulky interface.
> > > >
> > > > Ok, could you explain what exactly  concerns you in the approach
> > > > described above?
> > > > What part you feel is bulky?
> > > >
> > > > > > >
> > > > > > > > const struct rte_eth_dev_reg_info *reg_info; struct
> > > > > > > > rte_eth_dev_info dev_info;
> > > > > > > >
> > > > > > > > rte_eth_dev_info_get(pid, &dev_info);
> > > > > > > > rte_eth_dev_get_reg_info(port_id, &reg_info);
> > > > > > > >
> > > > > > > > for (i = 0; reg_info[i].name != NULL; i++) {
> > > > > > > >    ...
> > > > > > > >    rte_pcidev_read_reg(dev_info. pci_dev, reg_info[i], &v);
> > > > > > > >   ..
> > > > > > > > }
> > > > > > > >
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_eeprom_leng(uint8_t port_id) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > > > >get_eeprom_length, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->get_eeprom_length)(dev);
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_get_eeprom(uint8_t port_id, struct
> > > > > > > > > +rte_dev_eeprom_info
> > > > > > > > > +*info) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->get_eeprom)(dev, info); }
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_set_eeprom(uint8_t port_id, struct
> > > > > > > > > +rte_dev_eeprom_info
> > > > > > > > > +*info) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->set_eeprom)(dev, info); }
> > > > > > > > > +
> > > > > > > > > +int
> > > > > > > > > +rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > > > > > > > +rte_dev_ring_info
> > > > > > > > > +*info) {
> > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > +
> > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > port_id);
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > +		return -ENODEV;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> > > > > > > > ENOTSUP);
> > > > > > > > > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> > > > > > > >
> > > > > > > > I think it will be a useful addition to the ethdev API  to
> > > > > > > > have an ability to retrieve current RX/TX queue parameters.
> > > > > > > > Though again, it need to be more generic, so it could be
> > > > > > > > useful for
> > > > > > > > non- ethtool upper layer too.
> > > > > > > > So I suggest to modify it a bit.
> > > > > > > > Something like that:
> > > > > > > >
> > > > > > > > struct rte_eth_tx_queue_info {
> > > > > > > >     struct rte_eth_txconf txconf;
> > > > > > > >     uint32_t nb_tx_desc;
> > > > > > > >     uint32_t nb_max_tx_desc; /*max allowable TXDs for that
> > queue */
> > > > > > > >     uint32_t nb_tx_free;            /* number of free TXDs at
> > the moment
> > > > of
> > > > > > call.
> > > > > > > > */
> > > > > > > >     /* other tx queue data. */ };
> > > > > > > >
> > > > > > > > int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> > > > > > > > rte_eth_tx_queue_info *qinfo)
> > > > > > > >
> > > > > > > > Then, your upper layer ethtool wrapper, can implement yours
> > > > > > > > ethtool_get_ringparam() by:
> > > > > > > >
> > > > > > > >  ...
> > > > > > > >  struct rte_eth_tx_queue_info qinfo;
> > > > > > > > rte_ethdev_get_tx_queue_info(port, 0, &qinfo);
> > > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > > rte_eth_rx_queue_count(port, 0);
> > > > > > > >
> > > > > > > > Or probably even:
> > > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > > qinfo.nb_tx_free;
> > > > > > > >
> > > > > > > > Same for RX.
> > > > > > > >
> > > > > > > For now, this descriptor ring information is used by the ethtool
> > op.
> > > > > > > To make this interface simple, i.e. caller doesn't need to
> > > > > > > access other
> > > > > > queue information.
> > > > > >
> > > > > > I just repeat what I said to you in off-line conversation:
> > > > > > ethdev API is not equal ethtool API.
> > > > > > It is ok to add  a new function/structure to ethdev if it really
> > > > > > needed, but we should do mechanical one to one copy.
> > > > > > It is much better to add  a function/structure that would be
> > > > > > more generic, and suit other users, not only ethtool.
> > > > > > There is no point to have dozen functions in rte_ethdev API
> > > > > > providing similar information.
> > > > > > BTW, I don't see how API I proposed is much more  complex, then
> > > > > > yours
> > > > one.
> > > > > The ring parameter is a run-time information which is different
> > > > > than data
> > > > structure described in this discussion.
> > > >
> > > > I don't see how they are different.
> > > > Looking at ixgbe_get_ringparam(), it returns:
> > > > rx_max_pending - that's a static IXGBE PMD value (max possible
> > > > number of RXDs per one queue).
> > > > rx_pending - number of RXD currently in use by the HW for queue 0
> > > > (that information can be changed at each call).
> > > >
> > > > With the approach I suggesting - you can get same information for
> > > > each RX queue by calling rte_ethdev_get_rx_queue_info() and
> > > > rte_eth_rx_queue_count().
> > > > Plus you are getting other RX queue data.
> > > >
> > > > Another thing - what is practical usage of the information you
> > > > retrieving now by get_ringparam()?
> > > > Let say it returned to you: rx_max_pending=4096; rx_pending=128; How
> > > > that information would help to understand what is going on with the
> > device?
> > > > Without knowing  value of nb_tx_desc for the queue, you can't say is
> > > > you queue full or not.
> > > > Again, it could be that all your traffic going through some other
> > > > queue (not 0).
> > > > So from my point rte_eth_dev_get_ringparam()  usage is very limited,
> > > > and doesn't provide enough information about current queue state.
> > > >
> > > > Same thing applies for TX.
> > > >
> > >
> > > After careful review the suggestion in this comment, and review the
> > existing dpdk source code.
> > > I came to realize that neither rte_ethdev_get_rx_queue_info,
> > > rte_ethdev_get_tx_queue_info, struct rte_eth_rx_queue_info and struct
> > > rte_eth_tx_queue_info are available in the existing dpdk source code. I
> > could not make a patch based upon a set of non- existent API and data
> > structure.
> >
> > Right now, in dpdk.org source code, struct  rte_eth_dev_ring_info, struct
> > rte_dev_eeprom_info and struct  rte_dev_reg_info don't exist also.
> > Same as  all these functions:
> >
> > rte_eth_dev_default_mac_addr_set
> > rte_eth_dev_reg_length
> > rte_eth_dev_reg_info
> > rte_eth_dev_eeprom_length
> > rte_eth_dev_get_eeprom
> > rte_eth_dev_set_eeprom
> > rte_eth_dev_get_ringparam
> >
> > All this is a new API that's you are trying to add.
> > But, by some reason you consider it is ok to add 'struct
> > rte_eth_dev_ring_info', but couldn't add  struct
> > 'rte_ethdev_get_tx_queue_info'
> > That just doesn't make any sense to me.
> > In fact, I think our conversation is going in cycles.
> > If you are not happy with the suggested approach, please provide some
> > meaningful reason why.
> > Konstantin
> 
> It seems the new API aims at providing users a mechanism to quickly and
> gracefully migrate from using ethtool/ioctl calls.

I am fine with that goal in general.
But it doesn't mean that all ethool API should be pushed into rte_ethdev layer.
That's why  a shim layer on top of rte_ethdev is created -
it's goal is to provide for the upper layer an ethool-like API and
hide actual implementation based on rte_ethdev API inside.

>  The provided get/set
> ring param info is very similar to that of ethtool and facilitates the
> ethtool needs.

If rte_ethtool shim layer has to provide get/set ring_param API as it is - that's ok with me.
Though I don't see any good reason why rte_ethdev layer API should restrict itself with exactly the same ethtool-like API.
As I said before - current practical usage of rte_eth_dev_get_ringparam() looks quite limited.
Probably it just me, but I don't see how user can conclude what is the device state,
using  information provided by rte_eth_dev_get_ringparam().

My concern is - if we'll introduce rte_eth_dev_get_ringparam() as it suggested by Larry now,
one of two things would happen:
- no one except ethtool shim layer would use it.
- people will complain that it doesn't provide desired information. 
So, in next release we'll have to either introduce a new function and support 2 functions doing similar things
(code duplication), or modify existing API (ABI breakage pain).

It would be much better to introduce a new rte_ethdev API here that would be generic enough
and fit common needs, not only one particular case (ethtool).
After all, I don't think the changes I suggesting  differ that much from current approach.
Konstantin

> While additional enhancements to the API to provide additional details
> such as those you have suggested are certainly possible, I believe Larry
> is stating those ideas are outside the scope he has intended with the
> API introduction and that they should be discussed further and delivered
> in a future patch.

> 
> Does that seem reasonable?
> 
> Thanks,
> Dave
> 
> >
> > >
> > > > > It's the desire of this patch to separate each data structure to
> > > > > avoid cross
> > > > dependency.
> > > >
> > > > That's too cryptic to me.
> > > > Could you explain what cross dependency you are talking about?
> > > >
> > > > Konstantin

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-15 18:23                     ` Ananyev, Konstantin
@ 2015-06-16 18:15                       ` Ananyev, Konstantin
  0 siblings, 0 replies; 174+ messages in thread
From: Ananyev, Konstantin @ 2015-06-16 18:15 UTC (permalink / raw)
  To: 'David Harton (dharton)', Wang, Liang-min; +Cc: dev



> > > > > > > > > > +int
> > > > > > > > > > +rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > > > > > > > > +rte_dev_ring_info
> > > > > > > > > > +*info) {
> > > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > > +
> > > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > > port_id);
> > > > > > > > > > +		return -ENODEV;
> > > > > > > > > > +	}
> > > > > > > > > > +
> > > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > > +		return -ENODEV;
> > > > > > > > > > +	}
> > > > > > > > > > +
> > > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> > > > > > > > > ENOTSUP);
> > > > > > > > > > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> > > > > > > > >
> > > > > > > > > I think it will be a useful addition to the ethdev API  to
> > > > > > > > > have an ability to retrieve current RX/TX queue parameters.
> > > > > > > > > Though again, it need to be more generic, so it could be
> > > > > > > > > useful for
> > > > > > > > > non- ethtool upper layer too.
> > > > > > > > > So I suggest to modify it a bit.
> > > > > > > > > Something like that:
> > > > > > > > >
> > > > > > > > > struct rte_eth_tx_queue_info {
> > > > > > > > >     struct rte_eth_txconf txconf;
> > > > > > > > >     uint32_t nb_tx_desc;
> > > > > > > > >     uint32_t nb_max_tx_desc; /*max allowable TXDs for that
> > > queue */
> > > > > > > > >     uint32_t nb_tx_free;            /* number of free TXDs at
> > > the moment
> > > > > of
> > > > > > > call.
> > > > > > > > > */
> > > > > > > > >     /* other tx queue data. */ };
> > > > > > > > >
> > > > > > > > > int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> > > > > > > > > rte_eth_tx_queue_info *qinfo)
> > > > > > > > >
> > > > > > > > > Then, your upper layer ethtool wrapper, can implement yours
> > > > > > > > > ethtool_get_ringparam() by:
> > > > > > > > >
> > > > > > > > >  ...
> > > > > > > > >  struct rte_eth_tx_queue_info qinfo;
> > > > > > > > > rte_ethdev_get_tx_queue_info(port, 0, &qinfo);
> > > > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > > > rte_eth_rx_queue_count(port, 0);
> > > > > > > > >
> > > > > > > > > Or probably even:
> > > > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > > > qinfo.nb_tx_free;
> > > > > > > > >
> > > > > > > > > Same for RX.
> > > > > > > > >
> > > > > > > > For now, this descriptor ring information is used by the ethtool
> > > op.
> > > > > > > > To make this interface simple, i.e. caller doesn't need to
> > > > > > > > access other
> > > > > > > queue information.
> > > > > > >
> > > > > > > I just repeat what I said to you in off-line conversation:
> > > > > > > ethdev API is not equal ethtool API.
> > > > > > > It is ok to add  a new function/structure to ethdev if it really
> > > > > > > needed, but we should do mechanical one to one copy.
> > > > > > > It is much better to add  a function/structure that would be
> > > > > > > more generic, and suit other users, not only ethtool.
> > > > > > > There is no point to have dozen functions in rte_ethdev API
> > > > > > > providing similar information.
> > > > > > > BTW, I don't see how API I proposed is much more  complex, then
> > > > > > > yours
> > > > > one.
> > > > > > The ring parameter is a run-time information which is different
> > > > > > than data
> > > > > structure described in this discussion.
> > > > >
> > > > > I don't see how they are different.
> > > > > Looking at ixgbe_get_ringparam(), it returns:
> > > > > rx_max_pending - that's a static IXGBE PMD value (max possible
> > > > > number of RXDs per one queue).
> > > > > rx_pending - number of RXD currently in use by the HW for queue 0
> > > > > (that information can be changed at each call).
> > > > >
> > > > > With the approach I suggesting - you can get same information for
> > > > > each RX queue by calling rte_ethdev_get_rx_queue_info() and
> > > > > rte_eth_rx_queue_count().
> > > > > Plus you are getting other RX queue data.
> > > > >
> > > > > Another thing - what is practical usage of the information you
> > > > > retrieving now by get_ringparam()?
> > > > > Let say it returned to you: rx_max_pending=4096; rx_pending=128; How
> > > > > that information would help to understand what is going on with the
> > > device?
> > > > > Without knowing  value of nb_tx_desc for the queue, you can't say is
> > > > > you queue full or not.
> > > > > Again, it could be that all your traffic going through some other
> > > > > queue (not 0).
> > > > > So from my point rte_eth_dev_get_ringparam()  usage is very limited,
> > > > > and doesn't provide enough information about current queue state.
> > > > >
> > > > > Same thing applies for TX.
> > > > >
> > > >
> > > > After careful review the suggestion in this comment, and review the
> > > existing dpdk source code.
> > > > I came to realize that neither rte_ethdev_get_rx_queue_info,
> > > > rte_ethdev_get_tx_queue_info, struct rte_eth_rx_queue_info and struct
> > > > rte_eth_tx_queue_info are available in the existing dpdk source code. I
> > > could not make a patch based upon a set of non- existent API and data
> > > structure.
> > >
> > > Right now, in dpdk.org source code, struct  rte_eth_dev_ring_info, struct
> > > rte_dev_eeprom_info and struct  rte_dev_reg_info don't exist also.
> > > Same as  all these functions:
> > >
> > > rte_eth_dev_default_mac_addr_set
> > > rte_eth_dev_reg_length
> > > rte_eth_dev_reg_info
> > > rte_eth_dev_eeprom_length
> > > rte_eth_dev_get_eeprom
> > > rte_eth_dev_set_eeprom
> > > rte_eth_dev_get_ringparam
> > >
> > > All this is a new API that's you are trying to add.
> > > But, by some reason you consider it is ok to add 'struct
> > > rte_eth_dev_ring_info', but couldn't add  struct
> > > 'rte_ethdev_get_tx_queue_info'
> > > That just doesn't make any sense to me.
> > > In fact, I think our conversation is going in cycles.
> > > If you are not happy with the suggested approach, please provide some
> > > meaningful reason why.
> > > Konstantin
> >
> > It seems the new API aims at providing users a mechanism to quickly and
> > gracefully migrate from using ethtool/ioctl calls.
> 
> I am fine with that goal in general.
> But it doesn't mean that all ethool API should be pushed into rte_ethdev layer.
> That's why  a shim layer on top of rte_ethdev is created -
> it's goal is to provide for the upper layer an ethool-like API and
> hide actual implementation based on rte_ethdev API inside.
> 
> >  The provided get/set
> > ring param info is very similar to that of ethtool and facilitates the
> > ethtool needs.
> 

Actually a quick questions to you guys:
Looking at linux struct ethtool_ringparam description, I am seeing:
http://lxr.free-electrons.com/source/include/uapi/linux/ethtool.h:
@rx_pending: Current maximum number of pending entries per RX ring

And all linux driver I looked at (ixgbe,i40e,virtio,vmxbet3) returns number
of configured RX descriptors for queue 0.
In DPDK terms: nb_desc for the queue.

While in Larry's patch,  ixgbe_get_ringparam() for rx_pending returns
number of RX descriptors that are in HW use (for queue 0).
So, did you intentionally change linux ethool get_ringparam() behaviour here,
or is it just a mistake?

Konstantin
 

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info
  2015-06-15 18:10                     ` Ananyev, Konstantin
@ 2015-06-17 17:25                       ` Ananyev, Konstantin
  0 siblings, 0 replies; 174+ messages in thread
From: Ananyev, Konstantin @ 2015-06-17 17:25 UTC (permalink / raw)
  To: Wang, Liang-min, 'dev@dpdk.org'


...
> > > > > > > > > > +
> > > > > > > > > > +int
> > > > > > > > > > +rte_eth_dev_get_ringparam(uint8_t port_id, struct
> > > > > > > > > > +rte_dev_ring_info
> > > > > > > > > > +*info) {
> > > > > > > > > > +	struct rte_eth_dev *dev;
> > > > > > > > > > +
> > > > > > > > > > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n",
> > > > > port_id);
> > > > > > > > > > +		return -ENODEV;
> > > > > > > > > > +	}
> > > > > > > > > > +
> > > > > > > > > > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > > > > > > > > > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > > > > > > > > > +		return -ENODEV;
> > > > > > > > > > +	}
> > > > > > > > > > +
> > > > > > > > > > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_ringparam, -
> > > > > > > > > ENOTSUP);
> > > > > > > > > > +	return (*dev->dev_ops->get_ringparam)(dev, info); }
> > > > > > > > >
> > > > > > > > > I think it will be a useful addition to the ethdev API  to
> > > > > > > > > have an ability to retrieve current RX/TX queue parameters.
> > > > > > > > > Though again, it need to be more generic, so it could be
> > > > > > > > > useful for
> > > > > > > > > non- ethtool upper layer too.
> > > > > > > > > So I suggest to modify it a bit.
> > > > > > > > > Something like that:
> > > > > > > > >
> > > > > > > > > struct rte_eth_tx_queue_info {
> > > > > > > > >     struct rte_eth_txconf txconf;
> > > > > > > > >     uint32_t nb_tx_desc;
> > > > > > > > >     uint32_t nb_max_tx_desc; /*max allowable TXDs for that
> > > queue */
> > > > > > > > >     uint32_t nb_tx_free;            /* number of free TXDs at the
> > > moment
> > > > > of
> > > > > > > call.
> > > > > > > > > */
> > > > > > > > >     /* other tx queue data. */ };
> > > > > > > > >
> > > > > > > > > int rte_etdev_get_tx_queue_info(portid, queue_id, struct
> > > > > > > > > rte_eth_tx_queue_info *qinfo)
> > > > > > > > >
> > > > > > > > > Then, your upper layer ethtool wrapper, can implement yours
> > > > > > > > > ethtool_get_ringparam() by:
> > > > > > > > >
> > > > > > > > >  ...
> > > > > > > > >  struct rte_eth_tx_queue_info qinfo;
> > > > > > > > > rte_ethdev_get_tx_queue_info(port, 0, &qinfo);
> > > > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > > > rte_eth_rx_queue_count(port, 0);
> > > > > > > > >
> > > > > > > > > Or probably even:
> > > > > > > > > ring_param->tx_pending = qinfo.nb_tx_desc -
> > > > > > > > > qinfo.nb_tx_free;
> > > > > > > > >
> > > > > > > > > Same for RX.
> > > > > > > > >
> > > > > > > > For now, this descriptor ring information is used by the ethtool op.
> > > > > > > > To make this interface simple, i.e. caller doesn't need to
> > > > > > > > access other
> > > > > > > queue information.
> > > > > > >
> > > > > > > I just repeat what I said to you in off-line conversation:
> > > > > > > ethdev API is not equal ethtool API.
> > > > > > > It is ok to add  a new function/structure to ethdev if it really
> > > > > > > needed, but we should do mechanical one to one copy.
> > > > > > > It is much better to add  a function/structure that would be
> > > > > > > more generic, and suit other users, not only ethtool.
> > > > > > > There is no point to have dozen functions in rte_ethdev API
> > > > > > > providing similar information.
> > > > > > > BTW, I don't see how API I proposed is much more  complex, then
> > > > > > > yours
> > > > > one.
> > > > > > The ring parameter is a run-time information which is different
> > > > > > than data
> > > > > structure described in this discussion.
> > > > >
> > > > > I don't see how they are different.
> > > > > Looking at ixgbe_get_ringparam(), it returns:
> > > > > rx_max_pending - that's a static IXGBE PMD value (max possible
> > > > > number of RXDs per one queue).
> > > > > rx_pending - number of RXD currently in use by the HW for queue 0
> > > > > (that information can be changed at each call).
> > > > >
> > > > > With the approach I suggesting - you can get same information for
> > > > > each RX queue by calling rte_ethdev_get_rx_queue_info() and
> > > > > rte_eth_rx_queue_count().
> > > > > Plus you are getting other RX queue data.
> > > > >
> > > > > Another thing - what is practical usage of the information you
> > > > > retrieving now by get_ringparam()?
> > > > > Let say it returned to you: rx_max_pending=4096; rx_pending=128; How
> > > > > that information would help to understand what is going on with the
> > > device?
> > > > > Without knowing  value of nb_tx_desc for the queue, you can't say is
> > > > > you queue full or not.
> > > > > Again, it could be that all your traffic going through some other
> > > > > queue (not 0).
> > > > > So from my point rte_eth_dev_get_ringparam()  usage is very limited,
> > > > > and doesn't provide enough information about current queue state.
> > > > >
> > > > > Same thing applies for TX.
> > > > >
> > > >
> > > > After careful review the suggestion in this comment, and review the
> > > existing dpdk source code.
> > > > I came to realize that neither rte_ethdev_get_rx_queue_info,
> > > > rte_ethdev_get_tx_queue_info, struct rte_eth_rx_queue_info and struct
> > > > rte_eth_tx_queue_info are available in the existing dpdk source code. I
> > > could not make a patch based upon a set of non- existent API and data
> > > structure.
> > >
> > > Right now, in dpdk.org source code, struct  rte_eth_dev_ring_info, struct
> > > rte_dev_eeprom_info and struct  rte_dev_reg_info don't exist also.
> > > Same as  all these functions:
> > >
> > > rte_eth_dev_default_mac_addr_set
> > > rte_eth_dev_reg_length
> > > rte_eth_dev_reg_info
> > > rte_eth_dev_eeprom_length
> > > rte_eth_dev_get_eeprom
> > > rte_eth_dev_set_eeprom
> > > rte_eth_dev_get_ringparam
> > >
> > > All this is a new API that's you are trying to add.
> > > But, by some reason you consider it is ok to add 'struct
> > > rte_eth_dev_ring_info', but couldn't add  struct
> > > 'rte_ethdev_get_tx_queue_info'
> > > That just doesn't make any sense to me.
> > > In fact, I think our conversation is going in cycles.
> > > If you are not happy with the suggested approach, please provide some
> > > meaningful reason why.
> >
> > All the API's and data structure that you have questions in this comment are available from the submitted patch, you could run to
> see
> > if it works.
> > What I learned from your comments are a couple of API name and incomplete data structure description, so I could not make my
> > patch according to your suggestion.
> > If you strongly feel the API's that you are proposing are useful for get_ringparam(), please create a patch and submit it for
> evaluation.
> 
> Ok, I'll try to create a patch in next few days.
> Hopefully it will make things clearer to you and fit everyone.
> Konstantin

Here is the patch I submitted for proposed changes at re_ethdev and PMDs, as discussed:
http://dpdk.org/dev/patchwork/patch/5482/
Please have a look.

With that, get_ringraram for ethtool shim layer, would look something like:

int
rte_ethtool_get_ringparam(uint8_t port_id,
	struct ethtool_ringparam *ring_param)
{
	struct rte_eth_rx_qinfo rx_qinfo;
                struct rte_eth_tx_qinfo tx_qinfo;
	int status;

                if ((status = rte_eth_rx_queue_info_get (port_id, 0, &rx_qinfo)) != 0)
		return status;

               if ((status = rte_eth_tx_queue_info_get (port_id, 0, &tx_qinfo)) != 0)
		return status;

              memset(ring_param, 0, sizeof(*ring_param)

              ring_param->rx_pending = rx_qinfo.nb_desc;
              ring_param->tx_pending = tx_qinfo.nb_desc;
              ring_param->rx_max_pending = rx_qinfo.max_desc;
              ring_param->tx_max_pending = tx_qinfo.max_desc;

              return 0;
}


As you can see, the changes at ethtool are minimal, while it provides desired info.
>From other side, we have much more generic and easily extendable API at rte_ethdev.

Konstantin

> 
> > As coded in this patch, it's a simple and clean interface and most important, it can be validated and it works.
> >
> > > Konstantin
> > >
> > > >
> > > > > > It's the desire of this patch to separate each data structure to
> > > > > > avoid cross
> > > > > dependency.
> > > > >
> > > > > That's too cryptic to me.
> > > > > Could you explain what cross dependency you are talking about?
> > > > >
> > > > > Konstantin

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v7 0/4] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (4 preceding siblings ...)
  2015-06-12 22:03 ` [dpdk-dev] [PATCH v6 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-06-17 22:22 ` Liang-Min Larry Wang
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (6 more replies)
  2015-06-26 14:26 ` [dpdk-dev] [PATCH v8 0/5] " Liang-Min Larry Wang
                   ` (9 subsequent siblings)
  15 siblings, 7 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-17 22:22 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v7 change:
- Remove rte_eth_dev_get_ringparam implementation
v6 change:
- Rebase to match new changes over librte_ether
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (4):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  186 ++++
 drivers/net/e1000/igb_regs.h                     |  217 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  183 ++++
 drivers/net/ixgbe/ixgbe_regs.h                   |  357 ++++++++
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1030 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  781 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  151 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  301 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  378 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  412 +++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   57 ++
 lib/librte_ether/rte_ethdev.c                    |  115 +++
 lib/librte_ether/rte_ethdev.h                    |  117 +++
 lib/librte_ether/rte_ether_version.map           |    6 +
 19 files changed, 4515 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access device info
  2015-06-17 22:22 ` [dpdk-dev] [PATCH v7 " Liang-Min Larry Wang
@ 2015-06-17 22:22   ` Liang-Min Larry Wang
  2015-06-25 13:39     ` Stephen Hemminger
  2015-06-25 13:44     ` Stephen Hemminger
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (5 subsequent siblings)
  6 siblings, 2 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-17 22:22 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add new apis:
- rte_eth_dev_default_mac_addr_set
- rte_eth_dev_reg_length
- rte_eth_dev_reg_info
- rte_eth_dev_eeprom_length
- rte_eth_dev_get_eeprom
- rte_eth_dev_set_eeprom

to enable reading device parameters (mac-addr, register,
eeprom) based upon ethtool alike
data parameter specification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  57 ++++++++++++++++
 lib/librte_ether/rte_ethdev.c          | 115 ++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 117 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   6 ++
 5 files changed, 296 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..6848051
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,57 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index e13fde5..3cd13cd 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2751,6 +2751,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3644,3 +3668,94 @@ rte_eth_dev_set_mc_addr_list(uint8_t port_id,
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_mc_addr_list, -ENOTSUP);
 	return dev->dev_ops->set_mc_addr_list(dev, mc_addr_set, nb_mc_addr);
 }
+
+int
+rte_eth_dev_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 04c192d..2418cde 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1233,6 +1234,24 @@ typedef int (*eth_set_mc_addr_list_t)(struct rte_eth_dev *dev,
 				      uint32_t nb_mc_addr);
 /**< @internal set the list of multicast addresses on an Ethernet device */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1372,6 +1391,17 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -2987,6 +3017,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3616,6 +3660,79 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 012a82e..40d025b 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,12 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v7 2/4] ixgbe: add ops to support ethtool ops
  2015-06-17 22:22 ` [dpdk-dev] [PATCH v7 " Liang-Min Larry Wang
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-17 22:22   ` Liang-Min Larry Wang
  2015-06-25 13:45     ` Stephen Hemminger
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 3/4] igb: " Liang-Min Larry Wang
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-17 22:22 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 183 ++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_regs.h   | 357 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 540 insertions(+)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 7414a2e..b1917ff 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -179,6 +183,7 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -223,6 +228,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+		struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -260,6 +267,15 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -359,6 +375,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -386,6 +403,11 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.rss_hash_conf_get    = ixgbe_dev_rss_hash_conf_get,
 	.filter_ctrl          = ixgbe_dev_filter_ctrl,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -412,6 +434,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2889,6 +2914,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3719,6 +3752,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4471,6 +4512,148 @@ ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 					 ixgbe_dev_addr_list_itr, TRUE);
 }
 
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+	reg_info **reg_set =
+		(hw->mac.type == ixgbe_mac_82598EB)?ixgbe_regs_mac_82598EB:ixgbe_regs_others;
+
+	reg_group = reg_set[g_ind++];
+	while(reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = reg_set[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = ixgbevf_regs[g_ind++];
+	while(reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = ixgbevf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+	reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB)?
+					ixgbe_regs_mac_82598EB:ixgbe_regs_others;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = reg_set[g_ind++];
+		while(reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = reg_set[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = ixgbevf_regs[g_ind++];
+		while(reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = ixgbevf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size*2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+		((first+leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+		((first+leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..7025ed8
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,357 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+typedef struct _reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_nvm [] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_interrupt [] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_interrupt [] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_rx [] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_tx [] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_tx [] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_wakeup [] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_dcb [] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_mac [] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_diagnostic [] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static reg_info* ixgbe_regs_others[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+                                ixgbe_regs_fctl_others, ixgbe_regs_rxdma, ixgbe_regs_rx,
+                                ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
+                                ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
+
+static reg_info* ixgbe_regs_mac_82598EB[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+                                ixgbe_regs_fctl_mac_82598EB, ixgbe_regs_rxdma, ixgbe_regs_rx,
+                                ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
+                                ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
+
+/* VF registers */
+static reg_info* ixgbevf_regs[] = { ixgbevf_regs_general, ixgbevf_regs_interrupt,
+                                ixgbevf_regs_rxdma, ixgbevf_regs_tx, NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for(i = 0; i < reg->count; i++) {
+		reg_buf[i] = IXGBE_READ_REG(hw, reg->base_addr + i*reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += ixgbe_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif // _IXGBE_REGS_H_
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v7 3/4] igb: add ops to support ethtool ops
  2015-06-17 22:22 ` [dpdk-dev] [PATCH v7 " Liang-Min Larry Wang
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-06-17 22:22   ` Liang-Min Larry Wang
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-17 22:22 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 186 +++++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 217 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 403 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 24c7510..cde6840 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -129,6 +130,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -142,6 +145,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -193,6 +202,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -268,12 +285,18 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
 	.rss_hash_conf_get    = eth_igb_rss_hash_conf_get,
 	.filter_ctrl          = eth_igb_filter_ctrl,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -295,6 +318,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2113,6 +2139,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+	                     struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2347,6 +2381,16 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.rar_set(hw, (void *)addr, 0); /* index is not used by rar_set() */
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3660,6 +3704,148 @@ eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = igb_regs[g_ind++];
+	while(reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igb_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = igbvf_regs[g_ind++];
+	while(reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igbvf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igb_regs[g_ind++];
+		while(reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = igb_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igbvf_regs[g_ind++];
+		while(reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = igbvf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size*2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) || ((first+leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) || ((first+leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..14602e8
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,217 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+typedef struct _reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_nvm [] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_interrupt [] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_rx [] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_tx [] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_wakeup [] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_mac [] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info* igb_regs[] = { igb_regs_general, igb_regs_nvm,
+                                igb_regs_interrupt, igb_regs_fctl,
+                                igb_regs_rxdma, igb_regs_rx,
+                                igb_regs_tx, igb_regs_wakeup, igb_regs_mac,
+                                NULL};
+
+static reg_info* igbvf_regs[] = { igb_regs_general,
+	/*
+	 * FIXME: reading igb_regs_interrupt results side-effect which doesn't work with VFIO
+	 *
+	 * igb_regs_interrupt,
+	 */
+                                  igb_regs_rxdma, igb_regs_tx, NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for(i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw, reg->base_addr + i*reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += igb_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif // _IGB_REGS_H_
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v7 4/4] examples: new example: l2fwd-ethtool
  2015-06-17 22:22 ` [dpdk-dev] [PATCH v7 " Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 3/4] igb: " Liang-Min Larry Wang
@ 2015-06-17 22:22   ` Liang-Min Larry Wang
  2015-06-18  2:04   ` [dpdk-dev] [PATCH v7 0/4] User-space Ethtool Stephen Hemminger
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-17 22:22 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1030 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  781 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  151 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  301 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  378 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  412 +++++++++
 10 files changed, 3276 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..a753c33
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..3d31cb1
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -lrte_ethtool
+LDFLAGS += -L$(SRCDIR)/../lib/build
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..23df781
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1030 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id)            ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id)     ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask = 0;
+
+/* virtio setup enable */
+static int virtio_setup = 0;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+    return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done (void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ------------------------------"
+			   "\nPackets sent: %24"PRIu64
+			   "\nPackets received: %20"PRIu64
+			   "\nPackets dropped: %21"PRIu64,
+			   portid,
+			   port_statistics[portid].tx,
+			   port_statistics[portid].rx,
+			   port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ==============================="
+		   "\nTotal packets sent: %18"PRIu64
+		   "\nTotal packets received: %14"PRIu64
+		   "\nTotal packets dropped: %15"PRIu64,
+		   total_packets_tx,
+		   total_packets_rx,
+		   total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid =0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+    if(virtio_setup) {
+        while (is_ipc_done() == 0) usleep(50);
+    }
+	while (1) {
+
+		cur_tsc = rte_rdtsc();
+
+		/*
+		 * TX burst queue drain
+		 */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >= (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id == rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+	       "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+	       "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+           "  -V : setting rx/tx mode to enable virtio\n"
+		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
+	       prgname);
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+            virtio_setup = l2fwd_parse_virtio_setup(optarg);
+            if (virtio_setup) {
+			    port_conf.rxmode.hw_vlan_strip = 0;
+			    port_conf.rxmode.hw_vlan_extend = 0;
+            }
+            break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status)
+					printf("Port %d Link Up - speed %u "
+						"Mbps - %s\n", (uint8_t)portid,
+						(unsigned)link.link_speed,
+				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+					("full-duplex") : ("half-duplex\n"));
+				else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+inline static char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+    static char addr_string[MAC_STR_SIZE];
+
+    snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+        mac_addr[0], mac_addr[1], mac_addr[2],
+        mac_addr[3], mac_addr[4], mac_addr[5]);
+    return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+    uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for(port_id = 0; port_id < num_of_ports; port_id++){
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of rte_eth_promiscuous_enable */
+		/* to test rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data = (struct rte_eth_dev_data*)dev->data;
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is %s", port_id, mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))) {
+				if (rte_ethtool_net_set_mac_addr(port_id, (void *)new_mac_addr) == 0) {
+					printf(", and it's being re-assigned to %s\n", mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1, &param2_size, param2);
+		if (req_type != (req_t)ipc_begin) {
+			proc_invalid(req_id);
+		} else {
+			break;
+		}
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1, &param2_size, param2);
+		port_id = param1[0];
+
+		switch((req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id, first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0) {
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			}
+			if (reg_count) {
+				status = proc_ethtool_get_regs(port_id, req_id, first_param, reply1);
+			}
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0) {
+				eeprom_size = rte_ethtool_get_eeprom_len(port_id);
+			}
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id, first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id, first_param, param2);
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param = (void *)reply1;
+				status = proc_ethtool_get_pauseparam(port_id, req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param = (void *)reply1;
+				status = proc_ethtool_set_pauseparam(port_id, req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id, req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id, req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id, req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id, req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id, req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id, req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id, req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id, req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type: %d\n",req_type);
+			break;
+		}
+		if ( status < 0)
+			printf("Service request with type (=%d) failed or not supported!!!\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+    init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		}
+		else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+		       lcore_queue_conf[rx_lcore_id].n_rx_port ==
+		       l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n", (unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					     rte_eth_dev_socket_id(portid),
+					     NULL,
+					     l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+    cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+			"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..91a4fcd
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,781 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE								6
+#define quad_aligned_size(x)						(x & 0x7)?((x+7)&0x7): x
+
+#define size16(data_type)							(uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED			-1
+#define NETDEV_INVALID				-1
+#define NETDEV_STATUS(data_size)	(GOOD_RETURN(data_size)?0:NETDEV_INVALID)
+#define UNUSED(x)					(void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id = 0;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY );
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close (fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY );
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close (fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	// block on read if reply is not available
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id) {
+		return -1;
+	}
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return leng;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs), param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size)){
+		return link_status;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return leng;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return valid;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t* param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY );
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else {
+			*param2_size = 0;
+		}
+	}
+	close (fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(struct ethtool_drvinfo);
+	}
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	if ((reg_len = rte_ethtool_get_regs_len(port_id)) == 0) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(int);
+	}
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	}
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	if ((eeprom_leng = rte_ethtool_get_eeprom_len(port_id)) == 0) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(int);
+	}
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	}
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = MAC_ADDR_SIZE;
+	}
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(struct rte_eth_stats);
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..e16410a
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,151 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE			"/tmp/nic_request"
+#define REP_PIPE			"/tmp/nic_reply"
+#define PAGE_SIZE			(4*1024)
+#define STACK_SIZE			(4*PAGE_SIZE)
+#define MAXI_DATA			(1024 *6)
+#define MAXI_PARA			1024
+#define STATUS_MASK			0x8000
+#define MULTIPLE_DATA_MASK	0x4000
+#define MAXI_REQ_TYPE		16
+#define FIRST_DATA_OFFSET	8
+#define to_ptr(new_ptr_type, data, offset)			(new_ptr_type)(&((unsigned char *)(void*)data)[offset])
+#define u8ptr(x)									(uint8_t*)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT						(sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye)	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size)	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes)		(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes)				(data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size)			(data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)						(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)					((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)						((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)				(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)				((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)						(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)				((dword_ptr[0] >> 16)& 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)				(dword_ptr[1])
+
+#define BAD_RETURN(data_size)					(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)					((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)				(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)					(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)						((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)					(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data,ptr_type)	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+typedef enum _REQ_TYPE {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+} req_t;
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif // _SHARED_FIFO_H_
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..b3b8c83
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..7dea10c
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,301 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	if ((n = rte_eth_dev_reg_length(port_id)) > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	if ((n = rte_eth_dev_eeprom_length(port_id)) > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	if ((status = rte_eth_dev_reg_info(port_id, &reg_info))
+		!= 0)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	if ((status = rte_eth_dev_get_eeprom(port_id, &eeprom_info)) != 0)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	if ((status = rte_eth_dev_set_eeprom(port_id, &eeprom_info)) != 0)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	if ((status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf)) != 0)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch(fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	if ((status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf)) != 0)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	if ((status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf)) != 0)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..a139859
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,378 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom, void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom, void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..d49ca98
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..ebacc26
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,412 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES/(after_ts - before_ts)
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES*8/(after_ts - before_ts)
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES*64*8/(after_ts - before_ts)
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
+}
+
+static uint32_t port_mask = 0;
+static uint32_t vf_port_mask = 0;
+static uint8_t num_of_ports = 0;
+static int keep_traffic = 1;
+
+inline static int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1<< port_id)) > 0;
+}
+
+inline static int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports	= reply_data[0];
+	port_mask		= reply_data2[0];
+	vf_port_mask	= reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0) {
+				printf("setrlimit returned result = %d\n", result);
+			} else {
+				printf("setrlimit succeed!!!\n");
+			}
+		} else {
+			printf("default stack size is 0x%x\n", (int)(rl.rlim_cur));
+		}
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id)) {
+		port_id = rand() & 0x1F;
+	}
+	return port_id;
+}
+
+inline static char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1) {
+		keep_traffic = atoi(argv[1]);
+	}
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0) {
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+	}
+
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0) {
+				netdev_net_set_rx_mode(port_id);
+			} else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id ++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port #%d!!!\n", port_id);
+			} else {
+				printf("\nPort #%d mac addr is %s \n", port_id,
+					mac_addr_str(mac_addr));
+			}
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s fw_version: %s bus_info=%s\n"
+					"reg-size(bytes)=%d eeprom-size=%d\n", drvinfo.driver,
+					drvinfo.version, drvinfo.fw_version, drvinfo.bus_info,
+					drvinfo.regdump_len, drvinfo.eedump_len);
+			}
+
+			if ((count =netdev_ethtool_get_regs_len(port_id)) <= 0) {
+				printf("There are no registers available from device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers for dump\n", count);
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF, sizeof(struct ethtool_regs));
+				if ((count =netdev_ethtool_get_regs(port_id, &regs, reply_data))) {
+					printf("failed to run ethtool_get_regs from port #%d (error-code=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x version=0x%x\n",
+						int_ptr[0], int_ptr[10], regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			if (!is_vf_port(port_id)) {
+				if((count = netdev_ethtool_get_eeprom_len(0)) == 0)
+					printf("fail to retrieve eeprom count from port #%d\n", port_id);
+				else {
+
+					printf("eeprom size is %d bytes\n", count);
+					eeprom.offset = 20;
+					eeprom.len = 80;
+					eeprom.magic = 0;
+					if (netdev_ethtool_get_eeprom(port_id, &eeprom, reply_data)) {
+						printf("Fail to read eeprom from port #%d\n", port_id);
+					} else {
+						int i;
+						uint16_t *word = (uint16_t *)((void*)reply_data);
+
+						printf("eeprom-magic: %x; read-back eeprom data ...\n", eeprom.magic);
+						for(i = 0; i < (int)(eeprom.len >> 1); i++) {
+							if (((i+1) %16) == 0)
+								printf("\n");
+							printf("%4x ", word[i]);
+						}
+						printf("\n");
+					}
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id ++) {
+		if (netdev_net_get_mac_addr(port_id, to_mac_type(mac_addr))) {
+			printf("Fail to get mac addr from port #%d!!!\n", port_id);
+		} else {
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+		}
+
+		if (!netdev_net_validate_addr(port_id, to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr, MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n", mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id, to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id, to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign, device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n", port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n", port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets, last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets, last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes, last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes, last_ts, ts));
+
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		for(port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for(port_id = 0; port_id < num_of_ports; port_id++) {
+			if (!is_vf_port(port_id)) {
+				link_up = netdev_ethtool_get_link(port_id);
+				if (!link_up) {
+					eeprom.offset = 20;
+					eeprom.len = 80;
+					if (netdev_ethtool_get_eeprom(port_id, &eeprom,
+						reply_data)) {
+						printf("failed to read eeprom break from post-run"
+							" testing!!!\n");
+						break;
+					}
+					if (netdev_ethtool_set_eeprom(port_id, &eeprom,
+						reply_data)) {
+						printf("Fail to write read-back data to eeprom!!!\n");
+						break;
+					}
+					/* checking mtu setting */
+					if (netdev_net_change_mtu(port_id, mtu))
+						printf("failed to set mtu to %d\n", mtu);
+
+					/* add/remove vlan to vid */
+					if (netdev_net_vlan_rx_add_vid(port_id, 0) == 0) {
+						if (netdev_net_vlan_rx_kill_vid(port_id, 0)) {
+							printf("fail to kill vid 0 vlan\n");
+							break;
+						}
+					} else {
+						printf("fail to add vid 0 vlan\n");
+						break;
+					}
+
+					/* testing pause parameter get/set functions */
+					if (netdev_ethtool_get_pauseparam(port_id, &pause_param)) {
+						printf("fail to get pause param\n");
+						break;
+					}
+					printf("pause setup: autoneg: %d tx_pause: "
+						"%d rx_pause: %d\n",
+						pause_param.autoneg, pause_param.tx_pause,
+						pause_param.rx_pause);
+
+					if (netdev_ethtool_set_pauseparam(port_id, &pause_param)) {
+						printf("fail to set pause param\n");
+						break;
+					}
+
+				}
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0);
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v7 0/4] User-space Ethtool
  2015-06-17 22:22 ` [dpdk-dev] [PATCH v7 " Liang-Min Larry Wang
                     ` (3 preceding siblings ...)
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
@ 2015-06-18  2:04   ` Stephen Hemminger
  2015-06-18 12:47     ` Wang, Liang-min
  2015-06-24 13:55   ` Andrew Harvey (agh)
  2015-06-24 17:16   ` David Harton (dharton)
  6 siblings, 1 reply; 174+ messages in thread
From: Stephen Hemminger @ 2015-06-18  2:04 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

On Wed, Jun 17, 2015 at 6:22 PM, Liang-Min Larry Wang <
liang-min.wang@intel.com> wrote:

> This implementation is designed to provide a familar interface for
> applications that rely on kernel-space driver to support ethtool_op and
> net_device_op for device management. The initial implementation focuses on
> ops that can be implemented through existing netdev APIs. More ops will be
> supported in latter release.
>
> v7 change:
> - Remove rte_eth_dev_get_ringparam implementation
> v6 change:
> - Rebase to match new changes over librte_ether
> v5 change:
> - Change API name from 'leng' to 'length'
> - Remove unused data structure rte_dev_vf_info
> - Remove placeholder API rte_eth_dev_set_ringparam
> - Clean up set_mac_addr implementation
> v4 change:
> - Add rte_eth_xxx apis and respective ops over igb and ixgbe
>   to support ethtool and net device alike ops
> - Add an example to demonstrate the use of ethtool library
> v3 change:
> - Fix a build issue
> v2 change:
> - Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set
> so it would support NIC devices other than ixgbe and igb
>
> Liang-Min Larry Wang (4):
>   ethdev: add apis to support access device info
>   ixgbe: add ops to support ethtool ops
>   igb: add ops to support ethtool ops
>   examples: new example: l2fwd-ethtool
>
>  drivers/net/e1000/igb_ethdev.c                   |  186 ++++
>  drivers/net/e1000/igb_regs.h                     |  217 +++++
>  drivers/net/ixgbe/ixgbe_ethdev.c                 |  183 ++++
>  drivers/net/ixgbe/ixgbe_regs.h                   |  357 ++++++++
>  examples/l2fwd-ethtool/Makefile                  |   55 ++
>  examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
>  examples/l2fwd-ethtool/l2fwd-app/main.c          | 1030
> ++++++++++++++++++++++
>  examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  781 ++++++++++++++++
>  examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  151 ++++
>  examples/l2fwd-ethtool/lib/Makefile              |   55 ++
>  examples/l2fwd-ethtool/lib/rte_ethtool.c         |  301 +++++++
>  examples/l2fwd-ethtool/lib/rte_ethtool.h         |  378 ++++++++
>  examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
>  examples/l2fwd-ethtool/nic-control/nic_control.c |  412 +++++++++
>  lib/librte_ether/Makefile                        |    1 +
>  lib/librte_ether/rte_eth_dev_info.h              |   57 ++
>  lib/librte_ether/rte_ethdev.c                    |  115 +++
>  lib/librte_ether/rte_ethdev.h                    |  117 +++
>  lib/librte_ether/rte_ether_version.map           |    6 +
>  19 files changed, 4515 insertions(+)
>  create mode 100644 drivers/net/e1000/igb_regs.h
>  create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
>  create mode 100644 examples/l2fwd-ethtool/Makefile
>  create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
>  create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
>  create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
>  create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
>  create mode 100644 examples/l2fwd-ethtool/lib/Makefile
>  create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
>  create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
>  create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
>  create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
>  create mode 100644 lib/librte_ether/rte_eth_dev_info.h
>
> --
> 2.1.4
>
>
I agree with having a more complete API, but have some nits to pick.
Could the API be more abstract to reduce ABI issues in future?

I know choosing names is hard, but as a Linux developer ethtool has a very
specific meaning to me.
This API encompasses things broader than Linux ethtool and has different
semantics therefore
not sure having something in DPDK with same name is really a good idea.

It would be better to call it something else like netdev_?? Or dpnet_??

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v7 0/4] User-space Ethtool
  2015-06-18  2:04   ` [dpdk-dev] [PATCH v7 0/4] User-space Ethtool Stephen Hemminger
@ 2015-06-18 12:47     ` Wang, Liang-min
  2015-06-23 15:19       ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-18 12:47 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

>I agree with having a more complete API, but have some nits to pick.
>Could the API be more abstract to reduce ABI issues in future?

Which API? Are you referring to the APIs over ethdev level, or something else?
More abstract on input/output data structure definition or else? Could you be more specific?

>I know choosing names is hard, but as a Linux developer ethtool has a very specific meaning to me.
>This API encompasses things broader than Linux ethtool and has different semantics therefore
>not sure having something in DPDK with same name is really a good idea.
>
>It would be better to call it something else like netdev_?? Or dpnet_??

Just to clarify the naming suggestion, in this patch, the prefix “ethtool” only appears on example and on this patch description.
Are you suggesting changing the name over example/l2fwd-ethtool or on this patch description, or may be both?



^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v7 0/4] User-space Ethtool
  2015-06-18 12:47     ` Wang, Liang-min
@ 2015-06-23 15:19       ` Wang, Liang-min
  0 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-23 15:19 UTC (permalink / raw)
  To: 'Stephen Hemminger'; +Cc: 'dev@dpdk.org'

Stephen,

From: Wang, Liang-min 
Sent: Thursday, June 18, 2015 8:47 AM
To: Stephen Hemminger
Cc: dev@dpdk.org
Subject: RE: [dpdk-dev] [PATCH v7 0/4] User-space Ethtool

>>I agree with having a more complete API, but have some nits to pick.
>>Could the API be more abstract to reduce ABI issues in future?

>Which API? Are you referring to the APIs over ethdev level, or something else?
>More abstract on input/output data structure definition or else? Could you be more specific?

>>I know choosing names is hard, but as a Linux developer ethtool has a very specific meaning to me.
>>This API encompasses things broader than Linux ethtool and has different semantics therefore
>>not sure having something in DPDK with same name is really a good idea.
>>
>>It would be better to call it something else like netdev_?? Or dpnet_??

>Just to clarify the naming suggestion, in this patch, the prefix “ethtool” only appears on example and on this patch description.
>Are you suggesting changing the name over example/l2fwd-ethtool or on this patch description, or may be both?

Have not heard your feedback on last request?



^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v7 0/4] User-space Ethtool
  2015-06-17 22:22 ` [dpdk-dev] [PATCH v7 " Liang-Min Larry Wang
                     ` (4 preceding siblings ...)
  2015-06-18  2:04   ` [dpdk-dev] [PATCH v7 0/4] User-space Ethtool Stephen Hemminger
@ 2015-06-24 13:55   ` Andrew Harvey (agh)
  2015-06-24 17:16   ` David Harton (dharton)
  6 siblings, 0 replies; 174+ messages in thread
From: Andrew Harvey (agh) @ 2015-06-24 13:55 UTC (permalink / raw)
  To: Liang-Min Larry Wang, dev

On 6/17/15, 3:22 PM, "Liang-Min Larry Wang" <liang-min.wang@intel.com>
wrote:

>This implementation is designed to provide a familar interface for
>applications that rely on kernel-space driver to support ethtool_op and
>net_device_op for device management. The initial implementation focuses
>on ops that can be implemented through existing netdev APIs. More ops
>will be supported in latter release.
>
>v7 change:
>- Remove rte_eth_dev_get_ringparam implementation
>v6 change:
>- Rebase to match new changes over librte_ether
>v5 change:
>- Change API name from 'leng' to 'length'
>- Remove unused data structure rte_dev_vf_info
>- Remove placeholder API rte_eth_dev_set_ringparam
>- Clean up set_mac_addr implementation
>v4 change:
>- Add rte_eth_xxx apis and respective ops over igb and ixgbe
>  to support ethtool and net device alike ops
>- Add an example to demonstrate the use of ethtool library
>v3 change:
>- Fix a build issue
>v2 change:
>- Implement rte_eth_dev_default_mac_addr_set through
>dev_ops::mac_addr_set so it would support NIC devices other than ixgbe
>and igb
>
>Liang-Min Larry Wang (4):
>  ethdev: add apis to support access device info
>  ixgbe: add ops to support ethtool ops
>  igb: add ops to support ethtool ops
>  examples: new example: l2fwd-ethtool
>
> drivers/net/e1000/igb_ethdev.c                   |  186 ++++
> drivers/net/e1000/igb_regs.h                     |  217 +++++
> drivers/net/ixgbe/ixgbe_ethdev.c                 |  183 ++++
> drivers/net/ixgbe/ixgbe_regs.h                   |  357 ++++++++
> examples/l2fwd-ethtool/Makefile                  |   55 ++
> examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
> examples/l2fwd-ethtool/l2fwd-app/main.c          | 1030
>++++++++++++++++++++++
> examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  781 ++++++++++++++++
> examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  151 ++++
> examples/l2fwd-ethtool/lib/Makefile              |   55 ++
> examples/l2fwd-ethtool/lib/rte_ethtool.c         |  301 +++++++
> examples/l2fwd-ethtool/lib/rte_ethtool.h         |  378 ++++++++
> examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
> examples/l2fwd-ethtool/nic-control/nic_control.c |  412 +++++++++
> lib/librte_ether/Makefile                        |    1 +
> lib/librte_ether/rte_eth_dev_info.h              |   57 ++
> lib/librte_ether/rte_ethdev.c                    |  115 +++
> lib/librte_ether/rte_ethdev.h                    |  117 +++
> lib/librte_ether/rte_ether_version.map           |    6 +
> 19 files changed, 4515 insertions(+)
> create mode 100644 drivers/net/e1000/igb_regs.h
> create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
> create mode 100644 examples/l2fwd-ethtool/Makefile
> create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
> create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
> create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
> create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
> create mode 100644 examples/l2fwd-ethtool/lib/Makefile
> create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
> create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
> create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
> create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
> create mode 100644 lib/librte_ether/rte_eth_dev_info.h
>
>-- 
>2.1.4

Acked-by: Andrew Harvey (agh) <agh@cisco.com>

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v7 0/4] User-space Ethtool
  2015-06-17 22:22 ` [dpdk-dev] [PATCH v7 " Liang-Min Larry Wang
                     ` (5 preceding siblings ...)
  2015-06-24 13:55   ` Andrew Harvey (agh)
@ 2015-06-24 17:16   ` David Harton (dharton)
  6 siblings, 0 replies; 174+ messages in thread
From: David Harton (dharton) @ 2015-06-24 17:16 UTC (permalink / raw)
  To: Liang-Min Larry Wang, dev

Acked-by: David Harton <dharton@cisco.com>

> -----Original Message-----
> From: Liang-Min Larry Wang [mailto:liang-min.wang@intel.com]
> Sent: Wednesday, June 17, 2015 6:22 PM
> To: dev@dpdk.org
> Cc: Andrew Harvey (agh); David Harton (dharton); Roger Melton (rmelton);
> Liang-Min Larry Wang
> Subject: [PATCH v7 0/4] User-space Ethtool
> 
> This implementation is designed to provide a familar interface for
> applications that rely on kernel-space driver to support ethtool_op and
> net_device_op for device management. The initial implementation focuses on
> ops that can be implemented through existing netdev APIs. More ops will be
> supported in latter release.
> 
> v7 change:
> - Remove rte_eth_dev_get_ringparam implementation
> v6 change:
> - Rebase to match new changes over librte_ether
> v5 change:
> - Change API name from 'leng' to 'length'
> - Remove unused data structure rte_dev_vf_info
> - Remove placeholder API rte_eth_dev_set_ringparam
> - Clean up set_mac_addr implementation
> v4 change:
> - Add rte_eth_xxx apis and respective ops over igb and ixgbe
>   to support ethtool and net device alike ops
> - Add an example to demonstrate the use of ethtool library
> v3 change:
> - Fix a build issue
> v2 change:
> - Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set
> so it would support NIC devices other than ixgbe and igb
> 
> Liang-Min Larry Wang (4):
>   ethdev: add apis to support access device info
>   ixgbe: add ops to support ethtool ops
>   igb: add ops to support ethtool ops
>   examples: new example: l2fwd-ethtool
> 
>  drivers/net/e1000/igb_ethdev.c                   |  186 ++++
>  drivers/net/e1000/igb_regs.h                     |  217 +++++
>  drivers/net/ixgbe/ixgbe_ethdev.c                 |  183 ++++
>  drivers/net/ixgbe/ixgbe_regs.h                   |  357 ++++++++
>  examples/l2fwd-ethtool/Makefile                  |   55 ++
>  examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
>  examples/l2fwd-ethtool/l2fwd-app/main.c          | 1030
> ++++++++++++++++++++++
>  examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  781 ++++++++++++++++
>  examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  151 ++++
>  examples/l2fwd-ethtool/lib/Makefile              |   55 ++
>  examples/l2fwd-ethtool/lib/rte_ethtool.c         |  301 +++++++
>  examples/l2fwd-ethtool/lib/rte_ethtool.h         |  378 ++++++++
>  examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
>  examples/l2fwd-ethtool/nic-control/nic_control.c |  412 +++++++++
>  lib/librte_ether/Makefile                        |    1 +
>  lib/librte_ether/rte_eth_dev_info.h              |   57 ++
>  lib/librte_ether/rte_ethdev.c                    |  115 +++
>  lib/librte_ether/rte_ethdev.h                    |  117 +++
>  lib/librte_ether/rte_ether_version.map           |    6 +
>  19 files changed, 4515 insertions(+)
>  create mode 100644 drivers/net/e1000/igb_regs.h  create mode 100644
> drivers/net/ixgbe/ixgbe_regs.h  create mode 100644 examples/l2fwd-
> ethtool/Makefile  create mode 100644 examples/l2fwd-ethtool/l2fwd-
> app/Makefile
>  create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
>  create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
>  create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
>  create mode 100644 examples/l2fwd-ethtool/lib/Makefile
>  create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
>  create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
>  create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
>  create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
>  create mode 100644 lib/librte_ether/rte_eth_dev_info.h
> 
> --
> 2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access device info
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-25 13:39     ` Stephen Hemminger
  2015-06-25 20:58       ` Wang, Liang-min
  2015-06-25 13:44     ` Stephen Hemminger
  1 sibling, 1 reply; 174+ messages in thread
From: Stephen Hemminger @ 2015-06-25 13:39 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

On Wed, 17 Jun 2015 18:22:12 -0400
Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:

>  int
> +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if (!is_valid_assigned_ether_addr(addr))
> +		return -EINVAL;
> +
> +	dev = &rte_eth_devices[port_id];
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
> +
> +	/* Update default address in NIC data structure */
> +	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
> +
> +	(*dev->dev_ops->mac_addr_set)(dev, addr);

Would it be possible to directly set mac_addr[0] if device does not
provide a device driver specific override?

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access device info
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-06-25 13:39     ` Stephen Hemminger
@ 2015-06-25 13:44     ` Stephen Hemminger
  2015-06-25 21:05       ` Wang, Liang-min
  1 sibling, 1 reply; 174+ messages in thread
From: Stephen Hemminger @ 2015-06-25 13:44 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

On Wed, 17 Jun 2015 18:22:12 -0400
Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:

> +int
> +rte_eth_dev_reg_length(uint8_t port_id)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> +		PMD_DEBUG_TRACE("Invalid port device\n");
> +		return -ENODEV;
> +	}

Some minor nits:
  * for consistency you should add valid port check here.
  * style:
    - don't do assignment in if() unless it really helps readability
    - need whitespace

	if (!rte_eth_dev_is_valid_port(portid)) {
		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
		return -ENODEV;
	}

	dev = &rte_eth_devices[port_id];
	if (dev == NULL) {
		PMD_DEBUG("Invalid port device\n");
		return -ENODEV:
	}
...

This code pattern is so common it really should be a function.

	dev = rte_eth_dev_get(port_id);
	if (dev == NULL) {
		PMD_DEBUG("Invalid port device\n");
		return -ENODEV;
	}

And then add a macro to generate this??

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v7 2/4] ixgbe: add ops to support ethtool ops
  2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-06-25 13:45     ` Stephen Hemminger
  2015-06-26  6:26       ` Andrew Harvey (agh)
  0 siblings, 1 reply; 174+ messages in thread
From: Stephen Hemminger @ 2015-06-25 13:45 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

On Wed, 17 Jun 2015 18:22:13 -0400
Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:

> +
> +static reg_info ixgbe_regs_general[] = {
> +	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
> +	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
> +	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
> +	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
> +	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
> +	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
> +	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
> +	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
> +	{0, 0, 0, ""}
> +};
> +
> +static reg_info ixgbevf_regs_general[] = {
> +	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
> +	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
> +	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
> +	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
> +	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
> +	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
> +	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
> +	{0, 0, 0, ""}
> +};
> +

All these tables should be const
and API may need to change.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access device info
  2015-06-25 13:39     ` Stephen Hemminger
@ 2015-06-25 20:58       ` Wang, Liang-min
  0 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-25 20:58 UTC (permalink / raw)
  To: Stephen Hemminger, Ananyev, Konstantin; +Cc: dev



> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Thursday, June 25, 2015 9:40 AM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access
> device info
> 
> On Wed, 17 Jun 2015 18:22:12 -0400
> Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
> 
> >  int
> > +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr
> *addr)
> > +{
> > +	struct rte_eth_dev *dev;
> > +
> > +	if (!rte_eth_dev_is_valid_port(port_id)) {
> > +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> > +		return -ENODEV;
> > +	}
> > +
> > +	if (!is_valid_assigned_ether_addr(addr))
> > +		return -EINVAL;
> > +
> > +	dev = &rte_eth_devices[port_id];
> > +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -
> ENOTSUP);
> > +
> > +	/* Update default address in NIC data structure */
> > +	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
> > +
> > +	(*dev->dev_ops->mac_addr_set)(dev, addr);
> 
> Would it be possible to directly set mac_addr[0] if device does not
> provide a device driver specific override?

I would yield this question to Konstantin since this information is used by get mac addr API.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access device info
  2015-06-25 13:44     ` Stephen Hemminger
@ 2015-06-25 21:05       ` Wang, Liang-min
  0 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-25 21:05 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev



> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Thursday, June 25, 2015 9:44 AM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access
> device info
> 
> On Wed, 17 Jun 2015 18:22:12 -0400
> Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
> 
> > +int
> > +rte_eth_dev_reg_length(uint8_t port_id)
> > +{
> > +	struct rte_eth_dev *dev;
> > +
> > +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> > +		PMD_DEBUG_TRACE("Invalid port device\n");
> > +		return -ENODEV;
> > +	}
> 
> Some minor nits:
>   * for consistency you should add valid port check here.
>   * style:
>     - don't do assignment in if() unless it really helps readability
>     - need whitespace
> 
> 	if (!rte_eth_dev_is_valid_port(portid)) {
> 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> 		return -ENODEV;
> 	}
> 
> 	dev = &rte_eth_devices[port_id];
> 	if (dev == NULL) {
> 		PMD_DEBUG("Invalid port device\n");
> 		return -ENODEV:
> 	}
> ...
> 
> This code pattern is so common it really should be a function.
> 
> 	dev = rte_eth_dev_get(port_id);
> 	if (dev == NULL) {
> 		PMD_DEBUG("Invalid port device\n");
> 		return -ENODEV;
> 	}
> 
> And then add a macro to generate this??

This is used through-out the rte_ethdev.c, should it be done to the entire file?

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v7 2/4] ixgbe: add ops to support ethtool ops
  2015-06-25 13:45     ` Stephen Hemminger
@ 2015-06-26  6:26       ` Andrew Harvey (agh)
  0 siblings, 0 replies; 174+ messages in thread
From: Andrew Harvey (agh) @ 2015-06-26  6:26 UTC (permalink / raw)
  To: Stephen Hemminger, Liang-Min Larry Wang; +Cc: dev

On 6/25/15, 6:45 AM, "dev on behalf of Stephen Hemminger"
<dev-bounces@dpdk.org on behalf of stephen@networkplumber.org> wrote:

>On Wed, 17 Jun 2015 18:22:13 -0400
>Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
>
>> +
>> +static reg_info ixgbe_regs_general[] = {
>> +	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
>> +	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
>> +	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
>> +	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
>> +	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
>> +	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
>> +	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
>> +	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
>> +	{0, 0, 0, ""}
>> +};
>> +
>> +static reg_info ixgbevf_regs_general[] = {
>> +	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
>> +	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
>> +	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
>> +	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
>> +	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
>> +	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
>> +	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
>> +	{0, 0, 0, ""}
>> +};
>> +
>
>All these tables should be const
>and API may need to change.
Good point, I have sent a patch to Larry for inclusion in the next version.

Thanks ‹ Andy

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v8 0/5] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (5 preceding siblings ...)
  2015-06-17 22:22 ` [dpdk-dev] [PATCH v7 " Liang-Min Larry Wang
@ 2015-06-26 14:26 ` Liang-Min Larry Wang
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 1/5] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (5 more replies)
  2015-06-27  1:19 ` [dpdk-dev] [PATCH v9 " Liang-Min Larry Wang
                   ` (8 subsequent siblings)
  15 siblings, 6 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-26 14:26 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v8 changes:
- Changed register tables to const.
v7 change:
- Remove rte_eth_dev_get_ringparam implementation
v6 change:
- Rebase to match new changes over librte_ether
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Andrew G. Harvey (1):
  Changed register tables to const.

Liang-Min Larry Wang (4):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  186 ++++
 drivers/net/e1000/igb_regs.h                     |  217 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  183 ++++
 drivers/net/ixgbe/ixgbe_regs.h                   |  357 ++++++++
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1030 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  781 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  151 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  301 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  378 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  412 +++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   57 ++
 lib/librte_ether/rte_ethdev.c                    |  115 +++
 lib/librte_ether/rte_ethdev.h                    |  117 +++
 lib/librte_ether/rte_ether_version.map           |    6 +
 19 files changed, 4515 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v8 1/5] ethdev: add apis to support access device info
  2015-06-26 14:26 ` [dpdk-dev] [PATCH v8 0/5] " Liang-Min Larry Wang
@ 2015-06-26 14:26   ` Liang-Min Larry Wang
  2015-06-26 16:51     ` Stephen Hemminger
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 2/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-26 14:26 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add new apis:
- rte_eth_dev_default_mac_addr_set
- rte_eth_dev_reg_length
- rte_eth_dev_reg_info
- rte_eth_dev_eeprom_length
- rte_eth_dev_get_eeprom
- rte_eth_dev_set_eeprom

to enable reading device parameters (mac-addr, register,
eeprom) based upon ethtool alike
data parameter specification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  57 ++++++++++++++++
 lib/librte_ether/rte_ethdev.c          | 115 ++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 117 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   6 ++
 5 files changed, 296 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..6848051
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,57 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index e13fde5..3cd13cd 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2751,6 +2751,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3644,3 +3668,94 @@ rte_eth_dev_set_mc_addr_list(uint8_t port_id,
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_mc_addr_list, -ENOTSUP);
 	return dev->dev_ops->set_mc_addr_list(dev, mc_addr_set, nb_mc_addr);
 }
+
+int
+rte_eth_dev_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
+		PMD_DEBUG_TRACE("Invalid port device\n");
+		return -ENODEV;
+	}
+
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 04c192d..2418cde 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1233,6 +1234,24 @@ typedef int (*eth_set_mc_addr_list_t)(struct rte_eth_dev *dev,
 				      uint32_t nb_mc_addr);
 /**< @internal set the list of multicast addresses on an Ethernet device */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1372,6 +1391,17 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -2987,6 +3017,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3616,6 +3660,79 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 012a82e..40d025b 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,12 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v8 2/5] ixgbe: add ops to support ethtool ops
  2015-06-26 14:26 ` [dpdk-dev] [PATCH v8 0/5] " Liang-Min Larry Wang
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 1/5] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-26 14:26   ` Liang-Min Larry Wang
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 3/5] igb: " Liang-Min Larry Wang
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-26 14:26 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 183 ++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_regs.h   | 357 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 540 insertions(+)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 7414a2e..b1917ff 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -179,6 +183,7 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -223,6 +228,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+		struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -260,6 +267,15 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -359,6 +375,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -386,6 +403,11 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.rss_hash_conf_get    = ixgbe_dev_rss_hash_conf_get,
 	.filter_ctrl          = ixgbe_dev_filter_ctrl,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -412,6 +434,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2889,6 +2914,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3719,6 +3752,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4471,6 +4512,148 @@ ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 					 ixgbe_dev_addr_list_itr, TRUE);
 }
 
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+	reg_info **reg_set =
+		(hw->mac.type == ixgbe_mac_82598EB)?ixgbe_regs_mac_82598EB:ixgbe_regs_others;
+
+	reg_group = reg_set[g_ind++];
+	while(reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = reg_set[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = ixgbevf_regs[g_ind++];
+	while(reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = ixgbevf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+	reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB)?
+					ixgbe_regs_mac_82598EB:ixgbe_regs_others;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = reg_set[g_ind++];
+		while(reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = reg_set[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = ixgbevf_regs[g_ind++];
+		while(reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = ixgbevf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size*2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+		((first+leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+		((first+leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..7025ed8
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,357 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+typedef struct _reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_nvm [] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_interrupt [] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_interrupt [] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_rx [] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_tx [] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbevf_regs_tx [] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_wakeup [] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_dcb [] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_mac [] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info ixgbe_regs_diagnostic [] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static reg_info* ixgbe_regs_others[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+                                ixgbe_regs_fctl_others, ixgbe_regs_rxdma, ixgbe_regs_rx,
+                                ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
+                                ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
+
+static reg_info* ixgbe_regs_mac_82598EB[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+                                ixgbe_regs_fctl_mac_82598EB, ixgbe_regs_rxdma, ixgbe_regs_rx,
+                                ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
+                                ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
+
+/* VF registers */
+static reg_info* ixgbevf_regs[] = { ixgbevf_regs_general, ixgbevf_regs_interrupt,
+                                ixgbevf_regs_rxdma, ixgbevf_regs_tx, NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for(i = 0; i < reg->count; i++) {
+		reg_buf[i] = IXGBE_READ_REG(hw, reg->base_addr + i*reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += ixgbe_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif // _IXGBE_REGS_H_
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v8 3/5] igb: add ops to support ethtool ops
  2015-06-26 14:26 ` [dpdk-dev] [PATCH v8 0/5] " Liang-Min Larry Wang
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 1/5] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 2/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-06-26 14:26   ` Liang-Min Larry Wang
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 4/5] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-26 14:26 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 186 +++++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 217 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 403 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 24c7510..cde6840 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -129,6 +130,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -142,6 +145,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -193,6 +202,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -268,12 +285,18 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
 	.rss_hash_conf_get    = eth_igb_rss_hash_conf_get,
 	.filter_ctrl          = eth_igb_filter_ctrl,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -295,6 +318,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2113,6 +2139,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+	                     struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2347,6 +2381,16 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.rar_set(hw, (void *)addr, 0); /* index is not used by rar_set() */
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3660,6 +3704,148 @@ eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = igb_regs[g_ind++];
+	while(reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igb_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	reg_info *reg_group;
+
+	reg_group = igbvf_regs[g_ind++];
+	while(reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igbvf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igb_regs[g_ind++];
+		while(reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = igb_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	reg_info *reg_group;
+
+	/*
+	 * Support only full register dump
+	 */
+	if ((regs->leng == 0) ||
+		(regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igbvf_regs[g_ind++];
+		while(reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count], reg_group);
+			reg_group = igbvf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size*2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) || ((first+leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) || ((first+leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..14602e8
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,217 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+typedef struct _reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_nvm [] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_interrupt [] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_rx [] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_tx [] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_wakeup [] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static reg_info igb_regs_mac [] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static reg_info* igb_regs[] = { igb_regs_general, igb_regs_nvm,
+                                igb_regs_interrupt, igb_regs_fctl,
+                                igb_regs_rxdma, igb_regs_rx,
+                                igb_regs_tx, igb_regs_wakeup, igb_regs_mac,
+                                NULL};
+
+static reg_info* igbvf_regs[] = { igb_regs_general,
+	/*
+	 * FIXME: reading igb_regs_interrupt results side-effect which doesn't work with VFIO
+	 *
+	 * igb_regs_interrupt,
+	 */
+                                  igb_regs_rxdma, igb_regs_tx, NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for(i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw, reg->base_addr + i*reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += igb_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif // _IGB_REGS_H_
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v8 4/5] examples: new example: l2fwd-ethtool
  2015-06-26 14:26 ` [dpdk-dev] [PATCH v8 0/5] " Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 3/5] igb: " Liang-Min Larry Wang
@ 2015-06-26 14:26   ` Liang-Min Larry Wang
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 5/5] Changed register tables to const Liang-Min Larry Wang
  2015-06-26 19:15   ` [dpdk-dev] [PATCH v8 0/5] User-space Ethtool Ananyev, Konstantin
  5 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-26 14:26 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1030 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  781 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  151 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  301 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  378 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  412 +++++++++
 10 files changed, 3276 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..a753c33
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..3d31cb1
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -lrte_ethtool
+LDFLAGS += -L$(SRCDIR)/../lib/build
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..23df781
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1030 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id)            ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id)     ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask = 0;
+
+/* virtio setup enable */
+static int virtio_setup = 0;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+    return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done (void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ------------------------------"
+			   "\nPackets sent: %24"PRIu64
+			   "\nPackets received: %20"PRIu64
+			   "\nPackets dropped: %21"PRIu64,
+			   portid,
+			   port_statistics[portid].tx,
+			   port_statistics[portid].rx,
+			   port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ==============================="
+		   "\nTotal packets sent: %18"PRIu64
+		   "\nTotal packets received: %14"PRIu64
+		   "\nTotal packets dropped: %15"PRIu64,
+		   total_packets_tx,
+		   total_packets_rx,
+		   total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid =0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+    if(virtio_setup) {
+        while (is_ipc_done() == 0) usleep(50);
+    }
+	while (1) {
+
+		cur_tsc = rte_rdtsc();
+
+		/*
+		 * TX burst queue drain
+		 */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >= (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id == rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+	       "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+	       "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+           "  -V : setting rx/tx mode to enable virtio\n"
+		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n",
+	       prgname);
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+            virtio_setup = l2fwd_parse_virtio_setup(optarg);
+            if (virtio_setup) {
+			    port_conf.rxmode.hw_vlan_strip = 0;
+			    port_conf.rxmode.hw_vlan_extend = 0;
+            }
+            break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status)
+					printf("Port %d Link Up - speed %u "
+						"Mbps - %s\n", (uint8_t)portid,
+						(unsigned)link.link_speed,
+				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+					("full-duplex") : ("half-duplex\n"));
+				else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+inline static char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+    static char addr_string[MAC_STR_SIZE];
+
+    snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+        mac_addr[0], mac_addr[1], mac_addr[2],
+        mac_addr[3], mac_addr[4], mac_addr[5]);
+    return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+    uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for(port_id = 0; port_id < num_of_ports; port_id++){
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of rte_eth_promiscuous_enable */
+		/* to test rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data = (struct rte_eth_dev_data*)dev->data;
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is %s", port_id, mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))) {
+				if (rte_ethtool_net_set_mac_addr(port_id, (void *)new_mac_addr) == 0) {
+					printf(", and it's being re-assigned to %s\n", mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1, &param2_size, param2);
+		if (req_type != (req_t)ipc_begin) {
+			proc_invalid(req_id);
+		} else {
+			break;
+		}
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1, &param2_size, param2);
+		port_id = param1[0];
+
+		switch((req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id, first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0) {
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			}
+			if (reg_count) {
+				status = proc_ethtool_get_regs(port_id, req_id, first_param, reply1);
+			}
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0) {
+				eeprom_size = rte_ethtool_get_eeprom_len(port_id);
+			}
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id, first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id, first_param, param2);
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param = (void *)reply1;
+				status = proc_ethtool_get_pauseparam(port_id, req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param = (void *)reply1;
+				status = proc_ethtool_set_pauseparam(port_id, req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam (server) return status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id, req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id, req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id, req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id, req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id, req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id, req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id, req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id, req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type: %d\n",req_type);
+			break;
+		}
+		if ( status < 0)
+			printf("Service request with type (=%d) failed or not supported!!!\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+    init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		}
+		else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+		       lcore_queue_conf[rx_lcore_id].n_rx_port ==
+		       l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n", (unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					     rte_eth_dev_socket_id(portid),
+					     NULL,
+					     l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+    cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+			"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..91a4fcd
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,781 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE								6
+#define quad_aligned_size(x)						(x & 0x7)?((x+7)&0x7): x
+
+#define size16(data_type)							(uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED			-1
+#define NETDEV_INVALID				-1
+#define NETDEV_STATUS(data_size)	(GOOD_RETURN(data_size)?0:NETDEV_INVALID)
+#define UNUSED(x)					(void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id = 0;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY );
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close (fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY );
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close (fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	// block on read if reply is not available
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id) {
+		return -1;
+	}
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return leng;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs), param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size)){
+		return link_status;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return leng;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size)){
+		return valid;
+	}
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t* param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY );
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else {
+			*param2_size = 0;
+		}
+	}
+	close (fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(struct ethtool_drvinfo);
+	}
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	if ((reg_len = rte_ethtool_get_regs_len(port_id)) == 0) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(int);
+	}
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	}
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	if ((eeprom_leng = rte_ethtool_get_eeprom_len(port_id)) == 0) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(int);
+	}
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	}
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = MAC_ADDR_SIZE;
+	}
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = size16(struct rte_eth_stats);
+	}
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr)) {
+		data_size = STATUS_MASK;
+	} else {
+		data_size = 0;
+	}
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..e16410a
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,151 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE			"/tmp/nic_request"
+#define REP_PIPE			"/tmp/nic_reply"
+#define PAGE_SIZE			(4*1024)
+#define STACK_SIZE			(4*PAGE_SIZE)
+#define MAXI_DATA			(1024 *6)
+#define MAXI_PARA			1024
+#define STATUS_MASK			0x8000
+#define MULTIPLE_DATA_MASK	0x4000
+#define MAXI_REQ_TYPE		16
+#define FIRST_DATA_OFFSET	8
+#define to_ptr(new_ptr_type, data, offset)			(new_ptr_type)(&((unsigned char *)(void*)data)[offset])
+#define u8ptr(x)									(uint8_t*)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT						(sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye)	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size)	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes)		(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes)				(data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size)			(data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)						(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)					((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)						((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)				(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)				((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)						(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)				((dword_ptr[0] >> 16)& 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)				(dword_ptr[1])
+
+#define BAD_RETURN(data_size)					(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)					((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)				(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)					(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)						((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)					(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data,ptr_type)	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+typedef enum _REQ_TYPE {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+} req_t;
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif // _SHARED_FIFO_H_
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..b3b8c83
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..7dea10c
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,301 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	if ((n = rte_eth_dev_reg_length(port_id)) > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	if ((n = rte_eth_dev_eeprom_length(port_id)) > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	if ((status = rte_eth_dev_reg_info(port_id, &reg_info))
+		!= 0)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	if ((status = rte_eth_dev_get_eeprom(port_id, &eeprom_info)) != 0)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	if ((status = rte_eth_dev_set_eeprom(port_id, &eeprom_info)) != 0)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	if ((status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf)) != 0)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch(fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	if ((status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf)) != 0)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	if ((status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf)) != 0)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..a139859
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,378 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom, void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom, void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..d49ca98
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..ebacc26
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,412 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES/(after_ts - before_ts)
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES*8/(after_ts - before_ts)
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	(double)(after_value - before_value)*CPU_CYCLES*64*8/(after_ts - before_ts)
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
+}
+
+static uint32_t port_mask = 0;
+static uint32_t vf_port_mask = 0;
+static uint8_t num_of_ports = 0;
+static int keep_traffic = 1;
+
+inline static int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1<< port_id)) > 0;
+}
+
+inline static int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin, (FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports	= reply_data[0];
+	port_mask		= reply_data2[0];
+	vf_port_mask	= reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0) {
+				printf("setrlimit returned result = %d\n", result);
+			} else {
+				printf("setrlimit succeed!!!\n");
+			}
+		} else {
+			printf("default stack size is 0x%x\n", (int)(rl.rlim_cur));
+		}
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id)) {
+		port_id = rand() & 0x1F;
+	}
+	return port_id;
+}
+
+inline static char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1) {
+		keep_traffic = atoi(argv[1]);
+	}
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0) {
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+	}
+
+	for(port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0) {
+				netdev_net_set_rx_mode(port_id);
+			} else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id ++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port #%d!!!\n", port_id);
+			} else {
+				printf("\nPort #%d mac addr is %s \n", port_id,
+					mac_addr_str(mac_addr));
+			}
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s fw_version: %s bus_info=%s\n"
+					"reg-size(bytes)=%d eeprom-size=%d\n", drvinfo.driver,
+					drvinfo.version, drvinfo.fw_version, drvinfo.bus_info,
+					drvinfo.regdump_len, drvinfo.eedump_len);
+			}
+
+			if ((count =netdev_ethtool_get_regs_len(port_id)) <= 0) {
+				printf("There are no registers available from device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers for dump\n", count);
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF, sizeof(struct ethtool_regs));
+				if ((count =netdev_ethtool_get_regs(port_id, &regs, reply_data))) {
+					printf("failed to run ethtool_get_regs from port #%d (error-code=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x version=0x%x\n",
+						int_ptr[0], int_ptr[10], regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			if (!is_vf_port(port_id)) {
+				if((count = netdev_ethtool_get_eeprom_len(0)) == 0)
+					printf("fail to retrieve eeprom count from port #%d\n", port_id);
+				else {
+
+					printf("eeprom size is %d bytes\n", count);
+					eeprom.offset = 20;
+					eeprom.len = 80;
+					eeprom.magic = 0;
+					if (netdev_ethtool_get_eeprom(port_id, &eeprom, reply_data)) {
+						printf("Fail to read eeprom from port #%d\n", port_id);
+					} else {
+						int i;
+						uint16_t *word = (uint16_t *)((void*)reply_data);
+
+						printf("eeprom-magic: %x; read-back eeprom data ...\n", eeprom.magic);
+						for(i = 0; i < (int)(eeprom.len >> 1); i++) {
+							if (((i+1) %16) == 0)
+								printf("\n");
+							printf("%4x ", word[i]);
+						}
+						printf("\n");
+					}
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id ++) {
+		if (netdev_net_get_mac_addr(port_id, to_mac_type(mac_addr))) {
+			printf("Fail to get mac addr from port #%d!!!\n", port_id);
+		} else {
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+		}
+
+		if (!netdev_net_validate_addr(port_id, to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr, MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n", mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id, to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id, to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign, device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n", port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n", port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets, last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets, last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes, last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes, last_ts, ts));
+
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		for(port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for(port_id = 0; port_id < num_of_ports; port_id++) {
+			if (!is_vf_port(port_id)) {
+				link_up = netdev_ethtool_get_link(port_id);
+				if (!link_up) {
+					eeprom.offset = 20;
+					eeprom.len = 80;
+					if (netdev_ethtool_get_eeprom(port_id, &eeprom,
+						reply_data)) {
+						printf("failed to read eeprom break from post-run"
+							" testing!!!\n");
+						break;
+					}
+					if (netdev_ethtool_set_eeprom(port_id, &eeprom,
+						reply_data)) {
+						printf("Fail to write read-back data to eeprom!!!\n");
+						break;
+					}
+					/* checking mtu setting */
+					if (netdev_net_change_mtu(port_id, mtu))
+						printf("failed to set mtu to %d\n", mtu);
+
+					/* add/remove vlan to vid */
+					if (netdev_net_vlan_rx_add_vid(port_id, 0) == 0) {
+						if (netdev_net_vlan_rx_kill_vid(port_id, 0)) {
+							printf("fail to kill vid 0 vlan\n");
+							break;
+						}
+					} else {
+						printf("fail to add vid 0 vlan\n");
+						break;
+					}
+
+					/* testing pause parameter get/set functions */
+					if (netdev_ethtool_get_pauseparam(port_id, &pause_param)) {
+						printf("fail to get pause param\n");
+						break;
+					}
+					printf("pause setup: autoneg: %d tx_pause: "
+						"%d rx_pause: %d\n",
+						pause_param.autoneg, pause_param.tx_pause,
+						pause_param.rx_pause);
+
+					if (netdev_ethtool_set_pauseparam(port_id, &pause_param)) {
+						printf("fail to set pause param\n");
+						break;
+					}
+
+				}
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0);
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v8 5/5] Changed register tables to const.
  2015-06-26 14:26 ` [dpdk-dev] [PATCH v8 0/5] " Liang-Min Larry Wang
                     ` (3 preceding siblings ...)
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 4/5] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
@ 2015-06-26 14:26   ` Liang-Min Larry Wang
  2015-06-26 19:15   ` [dpdk-dev] [PATCH v8 0/5] User-space Ethtool Ananyev, Konstantin
  5 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-26 14:26 UTC (permalink / raw)
  To: dev

From: "Andrew G. Harvey" <agh@cisco.com>

Signed-off-by: Andrew G. Harvey <agh@cisco.com>
---
 drivers/net/e1000/igb_ethdev.c   |  8 ++++----
 drivers/net/e1000/igb_regs.h     | 28 ++++++++++++-------------
 drivers/net/ixgbe/ixgbe_ethdev.c | 12 +++++------
 drivers/net/ixgbe/ixgbe_regs.h   | 44 ++++++++++++++++++++--------------------
 4 files changed, 46 insertions(+), 46 deletions(-)

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index cde6840..1b1a596 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -3709,7 +3709,7 @@ eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
 {
 	int count = 0;
 	int g_ind = 0;
-	reg_info *reg_group;
+	const reg_info *reg_group;
 
 	reg_group = igb_regs[g_ind++];
 	while(reg_group) {
@@ -3725,7 +3725,7 @@ igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
 {
 	int count = 0;
 	int g_ind = 0;
-	reg_info *reg_group;
+	const reg_info *reg_group;
 
 	reg_group = igbvf_regs[g_ind++];
 	while(reg_group) {
@@ -3744,7 +3744,7 @@ eth_igb_get_regs(struct rte_eth_dev *dev,
 	uint32_t *regs_buff = regs->buf;
 	int g_ind = 0;
 	int count = 0;
-	reg_info *reg_group;
+	const reg_info *reg_group;
 
 	/*
 	 * Support only full register dump
@@ -3772,7 +3772,7 @@ igbvf_get_regs(struct rte_eth_dev *dev,
 	uint32_t *regs_buff = regs->buf;
 	int g_ind = 0;
 	int count = 0;
-	reg_info *reg_group;
+	const reg_info *reg_group;
 
 	/*
 	 * Support only full register dump
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
index 14602e8..c8adc49 100644
--- a/drivers/net/e1000/igb_regs.h
+++ b/drivers/net/e1000/igb_regs.h
@@ -42,7 +42,7 @@ typedef struct _reg_info {
 	const char *name;
 } reg_info;
 
-static reg_info igb_regs_general[] = {
+static const reg_info igb_regs_general[] = {
 	{E1000_CTRL, 1, 1, "E1000_CTRL"},
 	{E1000_STATUS, 1, 1, "E1000_STATUS"},
 	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
@@ -58,12 +58,12 @@ static reg_info igb_regs_general[] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info igb_regs_nvm [] = {
+static const reg_info igb_regs_nvm [] = {
 	{E1000_EECD, 1, 1, "E1000_EECD"},
 	{0, 0, 0, ""}
 };
 
-static reg_info igb_regs_interrupt [] = {
+static const reg_info igb_regs_interrupt [] = {
 	{E1000_EICS, 1, 1, "E1000_EICS"},
 	{E1000_EIMS, 1, 1, "E1000_EIMS"},
 	{E1000_EIMC, 1, 1, "E1000_EIMC"},
@@ -81,7 +81,7 @@ static reg_info igb_regs_interrupt [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info igb_regs_fctl[] = {
+static const reg_info igb_regs_fctl[] = {
 	{E1000_FCAL, 1, 1, "E1000_FCAL"},
 	{E1000_FCAH, 1, 1, "E1000_FCAH"},
 	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
@@ -91,7 +91,7 @@ static reg_info igb_regs_fctl[] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info igb_regs_rxdma[] = {
+static const reg_info igb_regs_rxdma[] = {
 	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
 	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
 	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
@@ -103,7 +103,7 @@ static reg_info igb_regs_rxdma[] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info igb_regs_rx [] = {
+static const reg_info igb_regs_rx [] = {
 	{E1000_RCTL, 1, 1, "E1000_RCTL"},
 	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
 	{E1000_RLPML, 1, 1, "E1000_RLPML"},
@@ -115,7 +115,7 @@ static reg_info igb_regs_rx [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info igb_regs_tx [] = {
+static const reg_info igb_regs_tx [] = {
 	{E1000_TCTL, 1, 1, "E1000_TCTL"},
 	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
 	{E1000_TIPG, 1, 1, "E1000_TIPG"},
@@ -136,7 +136,7 @@ static reg_info igb_regs_tx [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info igb_regs_wakeup [] = {
+static const reg_info igb_regs_wakeup [] = {
 	{E1000_WUC, 1, 1, "E1000_WUC"},
 	{E1000_WUFC, 1, 1, "E1000_WUFC"},
 	{E1000_WUS, 1, 1, "E1000_WUS"},
@@ -151,7 +151,7 @@ static reg_info igb_regs_wakeup [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info igb_regs_mac [] = {
+static const reg_info igb_regs_mac [] = {
 	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
 	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
 	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
@@ -162,13 +162,13 @@ static reg_info igb_regs_mac [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info* igb_regs[] = { igb_regs_general, igb_regs_nvm,
+static const reg_info* igb_regs[] = { igb_regs_general, igb_regs_nvm,
                                 igb_regs_interrupt, igb_regs_fctl,
                                 igb_regs_rxdma, igb_regs_rx,
                                 igb_regs_tx, igb_regs_wakeup, igb_regs_mac,
                                 NULL};
 
-static reg_info* igbvf_regs[] = { igb_regs_general,
+static const reg_info* igbvf_regs[] = { igb_regs_general,
 	/*
 	 * FIXME: reading igb_regs_interrupt results side-effect which doesn't work with VFIO
 	 *
@@ -177,7 +177,7 @@ static reg_info* igbvf_regs[] = { igb_regs_general,
                                   igb_regs_rxdma, igb_regs_tx, NULL};
 
 static inline int
-igb_read_regs(struct e1000_hw *hw, reg_info *reg, uint32_t *reg_buf)
+igb_read_regs(struct e1000_hw *hw, const reg_info *reg, uint32_t *reg_buf)
 {
 	unsigned int i;
 
@@ -188,7 +188,7 @@ igb_read_regs(struct e1000_hw *hw, reg_info *reg, uint32_t *reg_buf)
 };
 
 static inline int
-igb_reg_group_count(reg_info *regs)
+igb_reg_group_count(const reg_info *regs)
 {
 	int count = 0;
 	int i = 0;
@@ -201,7 +201,7 @@ igb_reg_group_count(reg_info *regs)
 };
 
 static inline int
-igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, const reg_info *regs)
 {
 	int count = 0;
 	int i = 0;
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index b1917ff..b4962a2 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -4518,8 +4518,8 @@ ixgbe_get_reg_length(struct rte_eth_dev *dev __rte_unused)
 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	int count = 0;
 	int g_ind = 0;
-	reg_info *reg_group;
-	reg_info **reg_set =
+	const reg_info *reg_group;
+	const reg_info **reg_set =
 		(hw->mac.type == ixgbe_mac_82598EB)?ixgbe_regs_mac_82598EB:ixgbe_regs_others;
 
 	reg_group = reg_set[g_ind++];
@@ -4536,7 +4536,7 @@ ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
 {
 	int count = 0;
 	int g_ind = 0;
-	reg_info *reg_group;
+	const reg_info *reg_group;
 
 	reg_group = ixgbevf_regs[g_ind++];
 	while(reg_group) {
@@ -4555,8 +4555,8 @@ ixgbe_get_regs(struct rte_eth_dev *dev,
 	uint32_t *regs_buff = regs->buf;
 	int g_ind = 0;
 	int count = 0;
-	reg_info *reg_group;
-	reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB)?
+	const reg_info *reg_group;
+	const reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB)?
 					ixgbe_regs_mac_82598EB:ixgbe_regs_others;
 
 	/*
@@ -4585,7 +4585,7 @@ ixgbevf_get_regs(struct rte_eth_dev *dev,
 	uint32_t *regs_buff = regs->buf;
 	int g_ind = 0;
 	int count = 0;
-	reg_info *reg_group;
+	const reg_info *reg_group;
 
 	/*
 	 * Support only full register dump
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
index 7025ed8..5f54b98 100644
--- a/drivers/net/ixgbe/ixgbe_regs.h
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -43,7 +43,7 @@ typedef struct _reg_info {
 	const char *name;
 } reg_info;
 
-static reg_info ixgbe_regs_general[] = {
+static const reg_info ixgbe_regs_general[] = {
 	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
 	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
 	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
@@ -55,7 +55,7 @@ static reg_info ixgbe_regs_general[] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbevf_regs_general[] = {
+static const reg_info ixgbevf_regs_general[] = {
 	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
 	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
 	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
@@ -66,7 +66,7 @@ static reg_info ixgbevf_regs_general[] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbe_regs_nvm [] = {
+static const reg_info ixgbe_regs_nvm [] = {
 	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
 	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
 	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
@@ -80,7 +80,7 @@ static reg_info ixgbe_regs_nvm [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbe_regs_interrupt [] = {
+static const reg_info ixgbe_regs_interrupt [] = {
 	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
 	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
 	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
@@ -95,7 +95,7 @@ static reg_info ixgbe_regs_interrupt [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbevf_regs_interrupt [] = {
+static const reg_info ixgbevf_regs_interrupt [] = {
 	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
 	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
 	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
@@ -108,7 +108,7 @@ static reg_info ixgbevf_regs_interrupt [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+static const reg_info ixgbe_regs_fctl_mac_82598EB[] = {
 	{IXGBE_PFCTOP, 1, 1, ""},
 	{IXGBE_FCTTV(0), 4, 4, ""},
 	{IXGBE_FCRTV, 1, 1, ""},
@@ -118,7 +118,7 @@ static reg_info ixgbe_regs_fctl_mac_82598EB[] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbe_regs_fctl_others[] = {
+static const reg_info ixgbe_regs_fctl_others[] = {
 	{IXGBE_PFCTOP, 1, 1, ""},
 	{IXGBE_FCTTV(0), 4, 4, ""},
 	{IXGBE_FCRTV, 1, 1, ""},
@@ -128,7 +128,7 @@ static reg_info ixgbe_regs_fctl_others[] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbe_regs_rxdma[] = {
+static const reg_info ixgbe_regs_rxdma[] = {
 	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
 	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
 	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
@@ -144,7 +144,7 @@ static reg_info ixgbe_regs_rxdma[] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbevf_regs_rxdma[] = {
+static const reg_info ixgbevf_regs_rxdma[] = {
 	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
 	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
 	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
@@ -159,7 +159,7 @@ static reg_info ixgbevf_regs_rxdma[] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbe_regs_rx [] = {
+static const reg_info ixgbe_regs_rx [] = {
 	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
 	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
 	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
@@ -176,7 +176,7 @@ static reg_info ixgbe_regs_rx [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbe_regs_tx [] = {
+static const reg_info ixgbe_regs_tx [] = {
 	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
 	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
 	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
@@ -192,7 +192,7 @@ static reg_info ixgbe_regs_tx [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbevf_regs_tx [] = {
+static const reg_info ixgbevf_regs_tx [] = {
 	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
 	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
 	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
@@ -204,7 +204,7 @@ static reg_info ixgbevf_regs_tx [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbe_regs_wakeup [] = {
+static const reg_info ixgbe_regs_wakeup [] = {
 	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
 	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
 	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
@@ -217,7 +217,7 @@ static reg_info ixgbe_regs_wakeup [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbe_regs_dcb [] = {
+static const reg_info ixgbe_regs_dcb [] = {
 	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
 	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
 	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
@@ -231,7 +231,7 @@ static reg_info ixgbe_regs_dcb [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbe_regs_mac [] = {
+static const reg_info ixgbe_regs_mac [] = {
 	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
 	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
 	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
@@ -268,7 +268,7 @@ static reg_info ixgbe_regs_mac [] = {
 	{0, 0, 0, ""}
 };
 
-static reg_info ixgbe_regs_diagnostic [] = {
+static const reg_info ixgbe_regs_diagnostic [] = {
 	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
 	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
 	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
@@ -302,22 +302,22 @@ static reg_info ixgbe_regs_diagnostic [] = {
 };
 
 /* PF registers */
-static reg_info* ixgbe_regs_others[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+static const reg_info* ixgbe_regs_others[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
                                 ixgbe_regs_fctl_others, ixgbe_regs_rxdma, ixgbe_regs_rx,
                                 ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
                                 ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
 
-static reg_info* ixgbe_regs_mac_82598EB[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
+static const reg_info* ixgbe_regs_mac_82598EB[] = { ixgbe_regs_general, ixgbe_regs_nvm, ixgbe_regs_interrupt,
                                 ixgbe_regs_fctl_mac_82598EB, ixgbe_regs_rxdma, ixgbe_regs_rx,
                                 ixgbe_regs_tx, ixgbe_regs_wakeup, ixgbe_regs_dcb,
                                 ixgbe_regs_mac, ixgbe_regs_diagnostic, NULL};
 
 /* VF registers */
-static reg_info* ixgbevf_regs[] = { ixgbevf_regs_general, ixgbevf_regs_interrupt,
+static const reg_info* ixgbevf_regs[] = { ixgbevf_regs_general, ixgbevf_regs_interrupt,
                                 ixgbevf_regs_rxdma, ixgbevf_regs_tx, NULL};
 
 static inline int
-ixgbe_read_regs(struct ixgbe_hw *hw, reg_info *reg, uint32_t *reg_buf)
+ixgbe_read_regs(struct ixgbe_hw *hw, const reg_info *reg, uint32_t *reg_buf)
 {
 	unsigned int i;
 
@@ -328,7 +328,7 @@ ixgbe_read_regs(struct ixgbe_hw *hw, reg_info *reg, uint32_t *reg_buf)
 };
 
 static inline int
-ixgbe_regs_group_count(reg_info *regs)
+ixgbe_regs_group_count(const reg_info *regs)
 {
 	int count = 0;
 	int i = 0;
@@ -341,7 +341,7 @@ ixgbe_regs_group_count(reg_info *regs)
 };
 
 static inline int
-ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, reg_info *regs)
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, const reg_info *regs)
 {
 	int count = 0;
 	int i = 0;
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v8 1/5] ethdev: add apis to support access device info
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 1/5] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-26 16:51     ` Stephen Hemminger
  2015-06-26 17:05       ` Wang, Liang-min
  2015-06-27  1:21       ` Wang, Liang-min
  0 siblings, 2 replies; 174+ messages in thread
From: Stephen Hemminger @ 2015-06-26 16:51 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

On Fri, 26 Jun 2015 10:26:43 -0400
Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:

> add new apis:
> - rte_eth_dev_default_mac_addr_set
> - rte_eth_dev_reg_length
> - rte_eth_dev_reg_info
> - rte_eth_dev_eeprom_length
> - rte_eth_dev_get_eeprom
> - rte_eth_dev_set_eeprom
> 
> to enable reading device parameters (mac-addr, register,
> eeprom) based upon ethtool alike
> data parameter specification.
> 
> Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>

I agree in principal, but has lots of style issues (see report from checkpatch).

ERROR: spaces required around that '=' (ctx:VxW)
#193: FILE: lib/librte_ether/rte_ethdev.c:3677:
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
 	        ^

ERROR: do not use assignment in if condition
#193: FILE: lib/librte_ether/rte_ethdev.c:3677:
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {

ERROR: spaces required around that '=' (ctx:VxW)
#213: FILE: lib/librte_ether/rte_ethdev.c:3697:
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
 	        ^

ERROR: do not use assignment in if condition
#213: FILE: lib/librte_ether/rte_ethdev.c:3697:
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {

ERROR: spaces required around that '=' (ctx:VxW)
#232: FILE: lib/librte_ether/rte_ethdev.c:3716:
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
 	        ^

ERROR: do not use assignment in if condition
#232: FILE: lib/librte_ether/rte_ethdev.c:3716:
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {

ERROR: spaces required around that '=' (ctx:VxW)
#251: FILE: lib/librte_ether/rte_ethdev.c:3735:
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
 	        ^

ERROR: do not use assignment in if condition
#251: FILE: lib/librte_ether/rte_ethdev.c:3735:
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {

ERROR: spaces required around that '=' (ctx:VxW)
#270: FILE: lib/librte_ether/rte_ethdev.c:3754:
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {
 	        ^

ERROR: do not use assignment in if condition
#270: FILE: lib/librte_ether/rte_ethdev.c:3754:
+	if ((dev= &rte_eth_devices[port_id]) == NULL) {

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v8 1/5] ethdev: add apis to support access device info
  2015-06-26 16:51     ` Stephen Hemminger
@ 2015-06-26 17:05       ` Wang, Liang-min
  2015-06-27  1:21       ` Wang, Liang-min
  1 sibling, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-26 17:05 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev



> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Friday, June 26, 2015 12:52 PM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v8 1/5] ethdev: add apis to support access
> device info
> 
> On Fri, 26 Jun 2015 10:26:43 -0400
> Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
> 
> > add new apis:
> > - rte_eth_dev_default_mac_addr_set
> > - rte_eth_dev_reg_length
> > - rte_eth_dev_reg_info
> > - rte_eth_dev_eeprom_length
> > - rte_eth_dev_get_eeprom
> > - rte_eth_dev_set_eeprom
> >
> > to enable reading device parameters (mac-addr, register,
> > eeprom) based upon ethtool alike
> > data parameter specification.
> >
> > Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> 
> I agree in principal, but has lots of style issues (see report from checkpatch).
> 
> ERROR: spaces required around that '=' (ctx:VxW)
> #193: FILE: lib/librte_ether/rte_ethdev.c:3677:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
>  	        ^
> 
> ERROR: do not use assignment in if condition
> #193: FILE: lib/librte_ether/rte_ethdev.c:3677:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> 
> ERROR: spaces required around that '=' (ctx:VxW)
> #213: FILE: lib/librte_ether/rte_ethdev.c:3697:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
>  	        ^
> 
> ERROR: do not use assignment in if condition
> #213: FILE: lib/librte_ether/rte_ethdev.c:3697:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> 
> ERROR: spaces required around that '=' (ctx:VxW)
> #232: FILE: lib/librte_ether/rte_ethdev.c:3716:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
>  	        ^
> 
> ERROR: do not use assignment in if condition
> #232: FILE: lib/librte_ether/rte_ethdev.c:3716:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> 
> ERROR: spaces required around that '=' (ctx:VxW)
> #251: FILE: lib/librte_ether/rte_ethdev.c:3735:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
>  	        ^
> 
> ERROR: do not use assignment in if condition
> #251: FILE: lib/librte_ether/rte_ethdev.c:3735:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> 
> ERROR: spaces required around that '=' (ctx:VxW)
> #270: FILE: lib/librte_ether/rte_ethdev.c:3754:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
>  	        ^
> 
> ERROR: do not use assignment in if condition
> #270: FILE: lib/librte_ether/rte_ethdev.c:3754:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {

This part of code is the same as coding in other part of the same file such as:

int
rte_eth_dev_bypass_wd_timeout_show(uint8_t port_id, uint32_t *wd_timeout)
{
	struct rte_eth_dev *dev;

	if (!rte_eth_dev_is_valid_port(port_id)) {
		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
		return -ENODEV;
	}

	if ((dev= &rte_eth_devices[port_id]) == NULL) {
		PMD_DEBUG_TRACE("Invalid port device\n");
		return -ENODEV;
	}

	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->bypass_wd_timeout_show, -ENOTSUP);
	(*dev->dev_ops->bypass_wd_timeout_show)(dev, wd_timeout);
	return 0;
}
I would suggest that someone (either you or me) to do a code cleaning after all patches for DPDK 2.1 have been decided. Does that sound good to you?

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v8 0/5] User-space Ethtool
  2015-06-26 14:26 ` [dpdk-dev] [PATCH v8 0/5] " Liang-Min Larry Wang
                     ` (4 preceding siblings ...)
  2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 5/5] Changed register tables to const Liang-Min Larry Wang
@ 2015-06-26 19:15   ` Ananyev, Konstantin
  5 siblings, 0 replies; 174+ messages in thread
From: Ananyev, Konstantin @ 2015-06-26 19:15 UTC (permalink / raw)
  To: Wang, Liang-min, dev; +Cc: Wang, Liang-min



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Liang-Min Larry Wang
> Sent: Friday, June 26, 2015 3:27 PM
> To: dev@dpdk.org
> Cc: Wang, Liang-min
> Subject: [dpdk-dev] [PATCH v8 0/5] User-space Ethtool
> 
> This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op
> and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing
> netdev APIs. More ops will be supported in latter release.
> 
> v8 changes:
> - Changed register tables to const.
> v7 change:
> - Remove rte_eth_dev_get_ringparam implementation
> v6 change:
> - Rebase to match new changes over librte_ether
> v5 change:
> - Change API name from 'leng' to 'length'
> - Remove unused data structure rte_dev_vf_info
> - Remove placeholder API rte_eth_dev_set_ringparam
> - Clean up set_mac_addr implementation
> v4 change:
> - Add rte_eth_xxx apis and respective ops over igb and ixgbe
>   to support ethtool and net device alike ops
> - Add an example to demonstrate the use of ethtool library
> v3 change:
> - Fix a build issue
> v2 change:
> - Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe
> and igb
> 
> Andrew G. Harvey (1):
>   Changed register tables to const.
> 
> Liang-Min Larry Wang (4):
>   ethdev: add apis to support access device info
>   ixgbe: add ops to support ethtool ops
>   igb: add ops to support ethtool ops
>   examples: new example: l2fwd-ethtool
> 
>  drivers/net/e1000/igb_ethdev.c                   |  186 ++++
>  drivers/net/e1000/igb_regs.h                     |  217 +++++
>  drivers/net/ixgbe/ixgbe_ethdev.c                 |  183 ++++
>  drivers/net/ixgbe/ixgbe_regs.h                   |  357 ++++++++
>  examples/l2fwd-ethtool/Makefile                  |   55 ++
>  examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
>  examples/l2fwd-ethtool/l2fwd-app/main.c          | 1030 ++++++++++++++++++++++
>  examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  781 ++++++++++++++++
>  examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  151 ++++
>  examples/l2fwd-ethtool/lib/Makefile              |   55 ++
>  examples/l2fwd-ethtool/lib/rte_ethtool.c         |  301 +++++++
>  examples/l2fwd-ethtool/lib/rte_ethtool.h         |  378 ++++++++
>  examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
>  examples/l2fwd-ethtool/nic-control/nic_control.c |  412 +++++++++
>  lib/librte_ether/Makefile                        |    1 +
>  lib/librte_ether/rte_eth_dev_info.h              |   57 ++
>  lib/librte_ether/rte_ethdev.c                    |  115 +++
>  lib/librte_ether/rte_ethdev.h                    |  117 +++
>  lib/librte_ether/rte_ether_version.map           |    6 +
>  19 files changed, 4515 insertions(+)
>  create mode 100644 drivers/net/e1000/igb_regs.h
>  create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
>  create mode 100644 examples/l2fwd-ethtool/Makefile
>  create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
>  create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
>  create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
>  create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
>  create mode 100644 examples/l2fwd-ethtool/lib/Makefile
>  create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
>  create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
>  create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
>  create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
>  create mode 100644 lib/librte_ether/rte_eth_dev_info.h
> 
> --

Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
Please fix checkpatch.pl issues.

> 2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v9 0/5] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (6 preceding siblings ...)
  2015-06-26 14:26 ` [dpdk-dev] [PATCH v8 0/5] " Liang-Min Larry Wang
@ 2015-06-27  1:19 ` Liang-Min Larry Wang
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 1/5] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (4 more replies)
  2015-06-27  2:36 ` [dpdk-dev] [PATCH v10 0/4] User-space Ethtool Liang-Min Larry Wang
                   ` (7 subsequent siblings)
  15 siblings, 5 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27  1:19 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v9 changes:
- Fixed checkpatch errors.
v8 changes:
- Changed register tables to const.
v7 change:
- Remove rte_eth_dev_get_ringparam implementation
v6 change:
- Rebase to match new changes over librte_ether
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (5):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool
  ixgbe/igb: changed register tables to const

 drivers/net/e1000/igb_ethdev.c                   |  187 ++++
 drivers/net/e1000/igb_regs.h                     |  226 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  190 +++-
 drivers/net/ixgbe/ixgbe_regs.h                   |  379 ++++++++
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   57 ++
 lib/librte_ether/rte_ethdev.c                    |   99 ++
 lib/librte_ether/rte_ethdev.h                    |  117 +++
 lib/librte_ether/rte_ether_version.map           |    6 +
 19 files changed, 4639 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v9 1/5] ethdev: add apis to support access device info
  2015-06-27  1:19 ` [dpdk-dev] [PATCH v9 " Liang-Min Larry Wang
@ 2015-06-27  1:19   ` Liang-Min Larry Wang
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27  1:19 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add new apis:
- rte_eth_dev_default_mac_addr_set
- rte_eth_dev_reg_length
- rte_eth_dev_reg_info
- rte_eth_dev_eeprom_length
- rte_eth_dev_get_eeprom
- rte_eth_dev_set_eeprom

to enable reading device parameters (mac-addr, register,
eeprom) based upon ethtool alike
data parameter specification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  57 ++++++++++++++++
 lib/librte_ether/rte_ethdev.c          |  99 ++++++++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 117 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   6 ++
 5 files changed, 280 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..6848051
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,57 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 02cd07f..9a33330 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2751,6 +2751,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3644,3 +3668,78 @@ rte_eth_dev_set_mc_addr_list(uint8_t port_id,
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_mc_addr_list, -ENOTSUP);
 	return dev->dev_ops->set_mc_addr_list(dev, mc_addr_set, nb_mc_addr);
 }
+
+int
+rte_eth_dev_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index f1219ac..94d7be0 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1233,6 +1234,24 @@ typedef int (*eth_set_mc_addr_list_t)(struct rte_eth_dev *dev,
 				      uint32_t nb_mc_addr);
 /**< @internal set the list of multicast addresses on an Ethernet device */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1372,6 +1391,17 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -2987,6 +3017,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3616,6 +3660,79 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 012a82e..40d025b 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,12 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops
  2015-06-27  1:19 ` [dpdk-dev] [PATCH v9 " Liang-Min Larry Wang
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 1/5] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-27  1:19   ` Liang-Min Larry Wang
  2015-06-27  1:32     ` Stephen Hemminger
                       ` (2 more replies)
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 3/5] igb: " Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  4 siblings, 3 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27  1:19 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 190 +++++++++++++++++++-
 drivers/net/ixgbe/ixgbe_regs.h   | 379 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 567 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index f18550c..e2be855 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -179,6 +183,8 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev,
+					   struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -223,6 +229,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+					     struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -260,6 +268,19 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev,
+			    struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *regs);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -359,6 +380,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -386,6 +408,11 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.rss_hash_conf_get    = ixgbe_dev_rss_hash_conf_get,
 	.filter_ctrl          = ixgbe_dev_filter_ctrl,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -412,6 +439,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2902,6 +2932,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3741,6 +3779,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4481,8 +4527,8 @@ ixgbe_dev_addr_list_itr(__attribute__((unused)) struct ixgbe_hw *hw,
 
 static int
 ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
-			   struct ether_addr *mc_addr_set,
-			   uint32_t nb_mc_addr)
+			  struct ether_addr *mc_addr_set,
+			  uint32_t nb_mc_addr)
 {
 	struct ixgbe_hw *hw;
 	u8 *mc_addr_list;
@@ -4493,6 +4539,146 @@ ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 					 ixgbe_dev_addr_list_itr, TRUE);
 }
 
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	struct reg_info *reg_group;
+	struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	reg_group = reg_set[g_ind++];
+	while (reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = reg_set[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	struct reg_info *reg_group;
+
+	reg_group = ixgbevf_regs[g_ind++];
+	while (reg_group) {
+		count += ixgbe_regs_group_count(reg_group);
+		reg_group = ixgbevf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	      struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	struct reg_info *reg_group;
+	struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = reg_set[g_ind++];
+		while (reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+				reg_group);
+			reg_group = reg_set[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = ixgbevf_regs[g_ind++];
+		while (reg_group) {
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+						      reg_group);
+			reg_group = ixgbevf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size * 2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..67d6439
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,379 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static struct reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_nvm[] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_interrupt[] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbevf_regs_interrupt[] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_rx[] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_tx[] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbevf_regs_tx[] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_wakeup[] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_dcb[] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_mac[] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_diagnostic[] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static struct reg_info *ixgbe_regs_others[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm, ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_others,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+static struct reg_info *ixgbe_regs_mac_82598EB[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm,
+				ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_mac_82598EB,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+/* VF registers */
+static struct reg_info *ixgbevf_regs[] = {
+				ixgbevf_regs_general,
+				ixgbevf_regs_interrupt,
+				ixgbevf_regs_rxdma,
+				ixgbevf_regs_tx,
+				NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, struct reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++)
+		reg_buf[i] = IXGBE_READ_REG(hw,
+					reg->base_addr + i * reg->stride);
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+					  struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += ixgbe_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif /* _IXGBE_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v9 3/5] igb: add ops to support ethtool ops
  2015-06-27  1:19 ` [dpdk-dev] [PATCH v9 " Liang-Min Larry Wang
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 1/5] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-06-27  1:19   ` Liang-Min Larry Wang
  2015-06-27  1:35     ` Stephen Hemminger
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 4/5] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to const Liang-Min Larry Wang
  4 siblings, 1 reply; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27  1:19 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 187 ++++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 226 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 413 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 24c7510..895d91d 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -129,6 +130,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -142,6 +145,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -193,6 +202,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -268,12 +285,18 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
 	.rss_hash_conf_get    = eth_igb_rss_hash_conf_get,
 	.filter_ctrl          = eth_igb_filter_ctrl,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -295,6 +318,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2113,6 +2139,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+				struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2347,6 +2381,17 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* index is not used by rar_set() */
+	hw->mac.ops.rar_set(hw, (void *)addr, 0);
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3660,6 +3705,148 @@ eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	struct reg_info *reg_group;
+
+	reg_group = igb_regs[g_ind++];
+	while (reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igb_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	struct reg_info *reg_group;
+
+	reg_group = igbvf_regs[g_ind++];
+	while (reg_group) {
+		count += igb_reg_group_count(reg_group);
+		reg_group = igbvf_regs[g_ind++];
+	}
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igb_regs[g_ind++];
+		while (reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+			reg_group = igb_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = igbvf_regs[g_ind++];
+		while (reg_group) {
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+			reg_group = igbvf_regs[g_ind++];
+		}
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size * 2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..ac66f8b
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,226 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+};
+
+static struct reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info igb_regs_nvm[] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info igb_regs_interrupt[] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info igb_regs_rx[] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info igb_regs_tx[] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info igb_regs_wakeup[] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info igb_regs_mac[] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info *igb_regs[] = {
+				igb_regs_general,
+				igb_regs_nvm,
+				igb_regs_interrupt,
+				igb_regs_fctl,
+				igb_regs_rxdma,
+				igb_regs_rx,
+				igb_regs_tx,
+				igb_regs_wakeup,
+				igb_regs_mac,
+				NULL};
+
+/* FIXME: reading igb_regs_interrupt results side-effect which doesn't
+ * work with VFIO; re-install igb_regs_interrupt once issue is resolved.
+ */
+static struct reg_info *igbvf_regs[] = {
+				igb_regs_general,
+				igb_regs_rxdma,
+				igb_regs_tx,
+				NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, struct reg_info *reg, uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw,
+				reg->base_addr + i * reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+		struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += igb_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif /* _IGB_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v9 4/5] examples: new example: l2fwd-ethtool
  2015-06-27  1:19 ` [dpdk-dev] [PATCH v9 " Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 3/5] igb: " Liang-Min Larry Wang
@ 2015-06-27  1:19   ` Liang-Min Larry Wang
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to const Liang-Min Larry Wang
  4 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27  1:19 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 10 files changed, 3379 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..a753c33
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..3d31cb1
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -lrte_ethtool
+LDFLAGS += -L$(SRCDIR)/../lib/build
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..19dd58c
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1066 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id) ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id) ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask;
+
+/* virtio setup enable */
+static int virtio_setup;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* default period is 10 seconds */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+	return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done(void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ----------------------------",
+			portid);
+		printf("\nPackets sent: %24"PRIu64, port_statistics[portid].tx);
+		printf("\nPackets received: %20"PRIu64,
+			port_statistics[portid].rx);
+		printf("\nPackets dropped: %21"PRIu64,
+			port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ===============================");
+	printf("\nTotal packets sent: %18"PRIu64, total_packets_tx);
+	printf("\nTotal packets received: %14"PRIu64, total_packets_rx);
+	printf("\nTotal packets dropped: %15"PRIu64, total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid = 0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+					US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+	if (virtio_setup) {
+		while (is_ipc_done() == 0)
+			usleep(50);
+	}
+
+	while (1) {
+		cur_tsc = rte_rdtsc();
+
+		/* TX burst queue drain */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >=
+				    (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id ==
+					    rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+		"  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+		"  -V : setting rx/tx mode to enable virtio\n"
+		"  -T PERIOD: statistics will be refreshed each PERIOD seconds",
+		prgname);
+	printf("(0 to disable, 10 default, 86400 maximum)\n");
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) *
+				1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+			virtio_setup = l2fwd_parse_virtio_setup(optarg);
+			if (virtio_setup) {
+				port_conf.rxmode.hw_vlan_strip = 0;
+				port_conf.rxmode.hw_vlan_extend = 0;
+			}
+			break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status) {
+					printf("Port %d Link Up - speed %u "
+						, (uint8_t)portid,
+						(unsigned)link.link_speed);
+					printf("Mbps - %s\n", (link.link_duplex
+						== ETH_LINK_FULL_DUPLEX) ?
+						("full-duplex") :
+						("half-duplex\n"));
+				} else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+	uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of */
+		/* rte_eth_promiscuous_enable to test */
+		/* rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data =
+				(struct rte_eth_dev_data *)dev->data;
+
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is", port_id);
+		printf(" %s", mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))
+				) {
+				if (rte_ethtool_net_set_mac_addr(port_id,
+					(void *)new_mac_addr) == 0) {
+					printf(", and re-assigned to ");
+					printf("%s\n",
+					mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		if (req_type != (enum req_t)ipc_begin)
+			proc_invalid(req_id);
+		else
+			break;
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		port_id = param1[0];
+
+		switch ((enum req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id,
+				first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(
+				port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0)
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			if (reg_count)
+				status = proc_ethtool_get_regs(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0)
+				eeprom_size = rte_ethtool_get_eeprom_len(
+				port_id);
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id,
+				first_param, param2);
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_get_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_set_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id,
+				req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id,
+				req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id,
+				req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type:");
+			printf(" %d\n", req_type);
+			break;
+		}
+		if (status < 0)
+			printf("Request type (=%d) failed\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+	init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		} else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+			lcore_queue_conf[rx_lcore_id].n_rx_port ==
+			l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id,
+			(unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n",
+				(unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"Cannot configure device: err=%d, port=%u\n",
+				ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					rte_eth_dev_socket_id(portid),
+					NULL,
+					l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+	cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+		"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..0964bea
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,769 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE 6
+#define quad_aligned_size(x) ((x & 0x7) ? ((x+7)&0x7) : x)
+
+#define size16(data_type) (uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED -1
+#define NETDEV_INVALID -1
+#define NETDEV_STATUS(data_size) (GOOD_RETURN(data_size) \
+				? 0 : NETDEV_INVALID)
+#define UNUSED(x) (void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close(fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	/* block on read if reply is not available */
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id)
+		return -1;
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs),
+		param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size))
+		return link_status;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return valid;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t *param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else
+			*param2_size = 0;
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct ethtool_drvinfo);
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	reg_len = rte_ethtool_get_regs_len(port_id);
+	if (reg_len == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf))
+		data_size = STATUS_MASK;
+	else
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	eeprom_leng = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_leng == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = MAC_ADDR_SIZE;
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct rte_eth_stats);
+
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..82dd962
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,158 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE "/tmp/nic_request"
+#define REP_PIPE "/tmp/nic_reply"
+#define PAGE_SIZE (4*1024)
+#define STACK_SIZE (4*PAGE_SIZE)
+#define MAXI_DATA (1024*6)
+#define MAXI_PARA 1024
+#define STATUS_MASK 0x8000
+#define MULTIPLE_DATA_MASK 0x4000
+#define MAXI_REQ_TYPE 16
+#define FIRST_DATA_OFFSET 8
+#define to_ptr(new_ptr_type, data, offset) \
+	(new_ptr_type)(&((unsigned char *)(void *)data)[offset])
+#define u8ptr(x) (uint8_t *)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT (sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye) \
+	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size) \
+	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes) \
+	(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes) (data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size) (data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)	((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)		((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)	(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)	((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)	((dword_ptr[0] >> 16) & 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)	(dword_ptr[1])
+
+#define BAD_RETURN(data_size)	(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)	((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)	(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)	\
+	(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)		\
+	((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)	(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data, ptr_type)	\
+	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+enum req_t {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+};
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif /* _SHARED_FIFO_H_ */
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..b3b8c83
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..744cb0c
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,308 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	n = rte_eth_dev_reg_length(port_id);
+	if (n > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	n = rte_eth_dev_eeprom_length(port_id);
+	if (n > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	status = rte_eth_dev_reg_info(port_id, &reg_info);
+	if (status)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch (fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..dc234be
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,384 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to
+ * parameter attributes desribed by ethtool data structure,
+ * ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame
+ *	 configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..d49ca98
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..f99af58
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,471 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES/(after_ts - before_ts))
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*8/(after_ts - before_ts))
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*64*8/(after_ts - before_ts))
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+}
+
+static uint32_t port_mask;
+static uint32_t vf_port_mask;
+static uint8_t num_of_ports;
+static int keep_traffic = 1;
+
+static inline int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1 << port_id)) > 0;
+}
+
+static inline int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports = reply_data[0];
+	port_mask = reply_data2[0];
+	vf_port_mask = reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0)
+				printf("setrlimit returned result = %d\n",
+					result);
+			else
+				printf("setrlimit succeed!!!\n");
+		} else
+			printf("default stack size is 0x%x\n",
+				(int)(rl.rlim_cur));
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id))
+		port_id = rand() & 0x1F;
+
+	return port_id;
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1)
+		keep_traffic = atoi(argv[1]);
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0)
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0)
+				netdev_net_set_rx_mode(port_id);
+			else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port");
+				printf(" #%d!!!\n", port_id);
+			} else
+				printf("\nPort #%d mac addr is %s\n",
+					port_id, mac_addr_str(mac_addr));
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s ",
+					drvinfo.driver, drvinfo.version);
+				printf("fw_version: %s bus_info=%s\n",
+					drvinfo.fw_version, drvinfo.bus_info);
+				printf("reg-size(bytes)=%d eeprom-size=%d\n",
+					drvinfo.regdump_len,
+					drvinfo.eedump_len);
+			}
+
+			count = netdev_ethtool_get_regs_len(port_id);
+			if (count <= 0) {
+				printf("There are no registers available from");
+				printf(" device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers ",
+					count);
+				printf("for dump\n");
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF,
+					sizeof(struct ethtool_regs));
+				count = netdev_ethtool_get_regs(port_id,
+					&regs, reply_data);
+				if (count) {
+					printf("failed to run");
+					printf(" ethtool_get_regs ");
+					printf("from port #%d (err=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x ",
+						int_ptr[0], int_ptr[10]);
+					printf("version=0x%x\n",
+						regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			count = 0;
+			if (!is_vf_port(port_id)) {
+				count = netdev_ethtool_get_eeprom_len(0);
+				if (count == 0) {
+					printf("fail to retrieve eeprom");
+					printf("count from port #%d\n",
+						port_id);
+				}
+			}
+
+			if (count) {
+				printf("eeprom size is %d bytes\n", count);
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				eeprom.magic = 0;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to read eeprom");
+					printf(" from port #%d\n",
+						port_id);
+				} else {
+					int i;
+					uint16_t *word = (uint16_t *)
+						((void *)reply_data);
+
+					printf("eeprom-magic: %x;",
+						eeprom.magic);
+					printf("eeprom data ...\n");
+					count = 80;
+					for (i = 0; i < (int)(eeprom.len
+						>> 1); i++) {
+						if (((i+1) % 16) == 0)
+							printf("\n");
+						printf("%4x ", word[i]);
+					}
+					printf("\n");
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (netdev_net_get_mac_addr(port_id,
+			to_mac_type(mac_addr)))
+			printf("Fail to get mac addr from port #%d!!!\n",
+				port_id);
+		else
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+
+		if (!netdev_net_validate_addr(port_id,
+			to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr,
+				MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n",
+				mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id,
+				to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id,
+				to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr");
+					printf(" @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign");
+				printf(" device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets,
+			last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets,
+			last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes,
+			last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes,
+			last_ts, ts));
+
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		int status;
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (!is_vf_port(port_id) && !link_up) {
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("failed to read eeprom");
+					printf(" break from post-run");
+					printf(" testing!!!\n");
+					break;
+				}
+				if (netdev_ethtool_set_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to write read-back");
+					printf(" data to eeprom!!!\n");
+					break;
+				}
+				/* checking mtu setting */
+				if (netdev_net_change_mtu(port_id, mtu)) {
+					printf("failed to set mtu");
+					printf("to %d\n", mtu);
+				}
+
+				/* add/remove vlan to vid */
+				status = netdev_net_vlan_rx_add_vid(
+					port_id, 0);
+				if (status == 0) {
+					status = netdev_net_vlan_rx_kill_vid(
+						port_id, 0);
+
+					if (status) {
+						printf("fail kill vlan-vid\n");
+						break;
+					}
+				} else {
+					printf("fail adding vlan/vid 0\n");
+					break;
+				}
+
+				/* testing pause parameter get/set functions */
+				status = netdev_ethtool_get_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("get pauseparam fail\n");
+					break;
+				}
+				printf("pause setup: autoneg: %d ",
+					pause_param.autoneg);
+				printf("tx_pause: %d ",
+					pause_param.tx_pause);
+				printf("rx_pause: %d\n",
+					pause_param.rx_pause);
+				status = netdev_ethtool_set_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("set pause param fail\n");
+					break;
+				}
+
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0)
+		;
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to const
  2015-06-27  1:19 ` [dpdk-dev] [PATCH v9 " Liang-Min Larry Wang
                     ` (3 preceding siblings ...)
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 4/5] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
@ 2015-06-27  1:19   ` Liang-Min Larry Wang
  2015-06-27  1:36     ` Stephen Hemminger
  4 siblings, 1 reply; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27  1:19 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

Changed registers tables in ixgbe and igb to const type.

Signed-off-by: Andrew G. Harvey <agh@cisco.com>
Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c   |  8 ++++----
 drivers/net/e1000/igb_regs.h     | 28 ++++++++++++-------------
 drivers/net/ixgbe/ixgbe_ethdev.c | 12 +++++------
 drivers/net/ixgbe/ixgbe_regs.h   | 44 ++++++++++++++++++++--------------------
 4 files changed, 46 insertions(+), 46 deletions(-)

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 895d91d..745940e 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -3710,7 +3710,7 @@ eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
 {
 	int count = 0;
 	int g_ind = 0;
-	struct reg_info *reg_group;
+	const struct reg_info *reg_group;
 
 	reg_group = igb_regs[g_ind++];
 	while (reg_group) {
@@ -3726,7 +3726,7 @@ igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
 {
 	int count = 0;
 	int g_ind = 0;
-	struct reg_info *reg_group;
+	const struct reg_info *reg_group;
 
 	reg_group = igbvf_regs[g_ind++];
 	while (reg_group) {
@@ -3745,7 +3745,7 @@ eth_igb_get_regs(struct rte_eth_dev *dev,
 	uint32_t *regs_buff = regs->buf;
 	int g_ind = 0;
 	int count = 0;
-	struct reg_info *reg_group;
+	const struct reg_info *reg_group;
 
 	/* Support only full register dump */
 	if ((regs->leng == 0) ||
@@ -3772,7 +3772,7 @@ igbvf_get_regs(struct rte_eth_dev *dev,
 	uint32_t *regs_buff = regs->buf;
 	int g_ind = 0;
 	int count = 0;
-	struct reg_info *reg_group;
+	const struct reg_info *reg_group;
 
 	/* Support only full register dump */
 	if ((regs->leng == 0) ||
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
index ac66f8b..338575a 100644
--- a/drivers/net/e1000/igb_regs.h
+++ b/drivers/net/e1000/igb_regs.h
@@ -42,7 +42,7 @@ struct reg_info {
 	const char *name;
 };
 
-static struct reg_info igb_regs_general[] = {
+static const struct reg_info igb_regs_general[] = {
 	{E1000_CTRL, 1, 1, "E1000_CTRL"},
 	{E1000_STATUS, 1, 1, "E1000_STATUS"},
 	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
@@ -58,12 +58,12 @@ static struct reg_info igb_regs_general[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info igb_regs_nvm[] = {
+static const struct reg_info igb_regs_nvm[] = {
 	{E1000_EECD, 1, 1, "E1000_EECD"},
 	{0, 0, 0, ""}
 };
 
-static struct reg_info igb_regs_interrupt[] = {
+static const struct reg_info igb_regs_interrupt[] = {
 	{E1000_EICS, 1, 1, "E1000_EICS"},
 	{E1000_EIMS, 1, 1, "E1000_EIMS"},
 	{E1000_EIMC, 1, 1, "E1000_EIMC"},
@@ -81,7 +81,7 @@ static struct reg_info igb_regs_interrupt[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info igb_regs_fctl[] = {
+static const struct reg_info igb_regs_fctl[] = {
 	{E1000_FCAL, 1, 1, "E1000_FCAL"},
 	{E1000_FCAH, 1, 1, "E1000_FCAH"},
 	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
@@ -91,7 +91,7 @@ static struct reg_info igb_regs_fctl[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info igb_regs_rxdma[] = {
+static const struct reg_info igb_regs_rxdma[] = {
 	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
 	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
 	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
@@ -103,7 +103,7 @@ static struct reg_info igb_regs_rxdma[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info igb_regs_rx[] = {
+static const struct reg_info igb_regs_rx[] = {
 	{E1000_RCTL, 1, 1, "E1000_RCTL"},
 	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
 	{E1000_RLPML, 1, 1, "E1000_RLPML"},
@@ -115,7 +115,7 @@ static struct reg_info igb_regs_rx[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info igb_regs_tx[] = {
+static const struct reg_info igb_regs_tx[] = {
 	{E1000_TCTL, 1, 1, "E1000_TCTL"},
 	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
 	{E1000_TIPG, 1, 1, "E1000_TIPG"},
@@ -136,7 +136,7 @@ static struct reg_info igb_regs_tx[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info igb_regs_wakeup[] = {
+static const struct reg_info igb_regs_wakeup[] = {
 	{E1000_WUC, 1, 1, "E1000_WUC"},
 	{E1000_WUFC, 1, 1, "E1000_WUFC"},
 	{E1000_WUS, 1, 1, "E1000_WUS"},
@@ -151,7 +151,7 @@ static struct reg_info igb_regs_wakeup[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info igb_regs_mac[] = {
+static const struct reg_info igb_regs_mac[] = {
 	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
 	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
 	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
@@ -162,7 +162,7 @@ static struct reg_info igb_regs_mac[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info *igb_regs[] = {
+static const struct reg_info *igb_regs[] = {
 				igb_regs_general,
 				igb_regs_nvm,
 				igb_regs_interrupt,
@@ -177,14 +177,14 @@ static struct reg_info *igb_regs[] = {
 /* FIXME: reading igb_regs_interrupt results side-effect which doesn't
  * work with VFIO; re-install igb_regs_interrupt once issue is resolved.
  */
-static struct reg_info *igbvf_regs[] = {
+static const struct reg_info *igbvf_regs[] = {
 				igb_regs_general,
 				igb_regs_rxdma,
 				igb_regs_tx,
 				NULL};
 
 static inline int
-igb_read_regs(struct e1000_hw *hw, struct reg_info *reg, uint32_t *reg_buf)
+igb_read_regs(struct e1000_hw *hw, const struct reg_info *reg, uint32_t *reg_buf)
 {
 	unsigned int i;
 
@@ -196,7 +196,7 @@ igb_read_regs(struct e1000_hw *hw, struct reg_info *reg, uint32_t *reg_buf)
 };
 
 static inline int
-igb_reg_group_count(struct reg_info *regs)
+igb_reg_group_count(const struct reg_info *regs)
 {
 	int count = 0;
 	int i = 0;
@@ -210,7 +210,7 @@ igb_reg_group_count(struct reg_info *regs)
 
 static inline int
 igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
-		struct reg_info *regs)
+		const struct reg_info *regs)
 {
 	int count = 0;
 	int i = 0;
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index e2be855..4be8e07 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -4545,8 +4545,8 @@ ixgbe_get_reg_length(struct rte_eth_dev *dev __rte_unused)
 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	int count = 0;
 	int g_ind = 0;
-	struct reg_info *reg_group;
-	struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
 				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
 
 	reg_group = reg_set[g_ind++];
@@ -4563,7 +4563,7 @@ ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
 {
 	int count = 0;
 	int g_ind = 0;
-	struct reg_info *reg_group;
+	const struct reg_info *reg_group;
 
 	reg_group = ixgbevf_regs[g_ind++];
 	while (reg_group) {
@@ -4582,8 +4582,8 @@ ixgbe_get_regs(struct rte_eth_dev *dev,
 	uint32_t *regs_buff = regs->buf;
 	int g_ind = 0;
 	int count = 0;
-	struct reg_info *reg_group;
-	struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
 				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
 
 	/* Support only full register dump */
@@ -4611,7 +4611,7 @@ ixgbevf_get_regs(struct rte_eth_dev *dev,
 	uint32_t *regs_buff = regs->buf;
 	int g_ind = 0;
 	int count = 0;
-	struct reg_info *reg_group;
+	const struct reg_info *reg_group;
 
 	/* Support only full register dump */
 	if ((regs->leng == 0) ||
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
index 67d6439..58fd25f 100644
--- a/drivers/net/ixgbe/ixgbe_regs.h
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -43,7 +43,7 @@ struct reg_info {
 	const char *name;
 } reg_info;
 
-static struct reg_info ixgbe_regs_general[] = {
+static const struct reg_info ixgbe_regs_general[] = {
 	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
 	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
 	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
@@ -55,7 +55,7 @@ static struct reg_info ixgbe_regs_general[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbevf_regs_general[] = {
+static const struct reg_info ixgbevf_regs_general[] = {
 	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
 	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
 	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
@@ -66,7 +66,7 @@ static struct reg_info ixgbevf_regs_general[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbe_regs_nvm[] = {
+static const struct reg_info ixgbe_regs_nvm[] = {
 	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
 	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
 	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
@@ -80,7 +80,7 @@ static struct reg_info ixgbe_regs_nvm[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbe_regs_interrupt[] = {
+static const struct reg_info ixgbe_regs_interrupt[] = {
 	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
 	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
 	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
@@ -95,7 +95,7 @@ static struct reg_info ixgbe_regs_interrupt[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbevf_regs_interrupt[] = {
+static const struct reg_info ixgbevf_regs_interrupt[] = {
 	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
 	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
 	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
@@ -108,7 +108,7 @@ static struct reg_info ixgbevf_regs_interrupt[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+static const struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
 	{IXGBE_PFCTOP, 1, 1, ""},
 	{IXGBE_FCTTV(0), 4, 4, ""},
 	{IXGBE_FCRTV, 1, 1, ""},
@@ -118,7 +118,7 @@ static struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbe_regs_fctl_others[] = {
+static const struct reg_info ixgbe_regs_fctl_others[] = {
 	{IXGBE_PFCTOP, 1, 1, ""},
 	{IXGBE_FCTTV(0), 4, 4, ""},
 	{IXGBE_FCRTV, 1, 1, ""},
@@ -128,7 +128,7 @@ static struct reg_info ixgbe_regs_fctl_others[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbe_regs_rxdma[] = {
+static const struct reg_info ixgbe_regs_rxdma[] = {
 	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
 	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
 	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
@@ -144,7 +144,7 @@ static struct reg_info ixgbe_regs_rxdma[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbevf_regs_rxdma[] = {
+static const struct reg_info ixgbevf_regs_rxdma[] = {
 	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
 	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
 	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
@@ -159,7 +159,7 @@ static struct reg_info ixgbevf_regs_rxdma[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbe_regs_rx[] = {
+static const struct reg_info ixgbe_regs_rx[] = {
 	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
 	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
 	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
@@ -176,7 +176,7 @@ static struct reg_info ixgbe_regs_rx[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbe_regs_tx[] = {
+static const struct reg_info ixgbe_regs_tx[] = {
 	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
 	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
 	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
@@ -192,7 +192,7 @@ static struct reg_info ixgbe_regs_tx[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbevf_regs_tx[] = {
+static const struct reg_info ixgbevf_regs_tx[] = {
 	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
 	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
 	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
@@ -204,7 +204,7 @@ static struct reg_info ixgbevf_regs_tx[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbe_regs_wakeup[] = {
+static const struct reg_info ixgbe_regs_wakeup[] = {
 	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
 	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
 	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
@@ -217,7 +217,7 @@ static struct reg_info ixgbe_regs_wakeup[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbe_regs_dcb[] = {
+static const struct reg_info ixgbe_regs_dcb[] = {
 	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
 	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
 	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
@@ -231,7 +231,7 @@ static struct reg_info ixgbe_regs_dcb[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbe_regs_mac[] = {
+static const struct reg_info ixgbe_regs_mac[] = {
 	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
 	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
 	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
@@ -268,7 +268,7 @@ static struct reg_info ixgbe_regs_mac[] = {
 	{0, 0, 0, ""}
 };
 
-static struct reg_info ixgbe_regs_diagnostic[] = {
+static const struct reg_info ixgbe_regs_diagnostic[] = {
 	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
 	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
 	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
@@ -302,7 +302,7 @@ static struct reg_info ixgbe_regs_diagnostic[] = {
 };
 
 /* PF registers */
-static struct reg_info *ixgbe_regs_others[] = {
+static const struct reg_info *ixgbe_regs_others[] = {
 				ixgbe_regs_general,
 				ixgbe_regs_nvm, ixgbe_regs_interrupt,
 				ixgbe_regs_fctl_others,
@@ -315,7 +315,7 @@ static struct reg_info *ixgbe_regs_others[] = {
 				ixgbe_regs_diagnostic,
 				NULL};
 
-static struct reg_info *ixgbe_regs_mac_82598EB[] = {
+static const struct reg_info *ixgbe_regs_mac_82598EB[] = {
 				ixgbe_regs_general,
 				ixgbe_regs_nvm,
 				ixgbe_regs_interrupt,
@@ -330,7 +330,7 @@ static struct reg_info *ixgbe_regs_mac_82598EB[] = {
 				NULL};
 
 /* VF registers */
-static struct reg_info *ixgbevf_regs[] = {
+static const struct reg_info *ixgbevf_regs[] = {
 				ixgbevf_regs_general,
 				ixgbevf_regs_interrupt,
 				ixgbevf_regs_rxdma,
@@ -338,7 +338,7 @@ static struct reg_info *ixgbevf_regs[] = {
 				NULL};
 
 static inline int
-ixgbe_read_regs(struct ixgbe_hw *hw, struct reg_info *reg, uint32_t *reg_buf)
+ixgbe_read_regs(struct ixgbe_hw *hw, const struct reg_info *reg, uint32_t *reg_buf)
 {
 	unsigned int i;
 
@@ -349,7 +349,7 @@ ixgbe_read_regs(struct ixgbe_hw *hw, struct reg_info *reg, uint32_t *reg_buf)
 };
 
 static inline int
-ixgbe_regs_group_count(struct reg_info *regs)
+ixgbe_regs_group_count(const struct reg_info *regs)
 {
 	int count = 0;
 	int i = 0;
@@ -363,7 +363,7 @@ ixgbe_regs_group_count(struct reg_info *regs)
 
 static inline int
 ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
-					  struct reg_info *regs)
+					  const struct reg_info *regs)
 {
 	int count = 0;
 	int i = 0;
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v8 1/5] ethdev: add apis to support access device info
  2015-06-26 16:51     ` Stephen Hemminger
  2015-06-26 17:05       ` Wang, Liang-min
@ 2015-06-27  1:21       ` Wang, Liang-min
  1 sibling, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-27  1:21 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev



> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Friday, June 26, 2015 12:52 PM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v8 1/5] ethdev: add apis to support access
> device info
> 
> On Fri, 26 Jun 2015 10:26:43 -0400
> Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
> 
> > add new apis:
> > - rte_eth_dev_default_mac_addr_set
> > - rte_eth_dev_reg_length
> > - rte_eth_dev_reg_info
> > - rte_eth_dev_eeprom_length
> > - rte_eth_dev_get_eeprom
> > - rte_eth_dev_set_eeprom
> >
> > to enable reading device parameters (mac-addr, register,
> > eeprom) based upon ethtool alike
> > data parameter specification.
> >
> > Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> 
> I agree in principal, but has lots of style issues (see report from checkpatch).
> 
> ERROR: spaces required around that '=' (ctx:VxW)
> #193: FILE: lib/librte_ether/rte_ethdev.c:3677:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
>  	        ^
> 
> ERROR: do not use assignment in if condition
> #193: FILE: lib/librte_ether/rte_ethdev.c:3677:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> 
> ERROR: spaces required around that '=' (ctx:VxW)
> #213: FILE: lib/librte_ether/rte_ethdev.c:3697:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
>  	        ^
> 
> ERROR: do not use assignment in if condition
> #213: FILE: lib/librte_ether/rte_ethdev.c:3697:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> 
> ERROR: spaces required around that '=' (ctx:VxW)
> #232: FILE: lib/librte_ether/rte_ethdev.c:3716:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
>  	        ^
> 
> ERROR: do not use assignment in if condition
> #232: FILE: lib/librte_ether/rte_ethdev.c:3716:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> 
> ERROR: spaces required around that '=' (ctx:VxW)
> #251: FILE: lib/librte_ether/rte_ethdev.c:3735:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
>  	        ^
> 
> ERROR: do not use assignment in if condition
> #251: FILE: lib/librte_ether/rte_ethdev.c:3735:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
> 
> ERROR: spaces required around that '=' (ctx:VxW)
> #270: FILE: lib/librte_ether/rte_ethdev.c:3754:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {
>  	        ^
> 
> ERROR: do not use assignment in if condition
> #270: FILE: lib/librte_ether/rte_ethdev.c:3754:
> +	if ((dev= &rte_eth_devices[port_id]) == NULL) {

Issues addressed over v9.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-06-27  1:32     ` Stephen Hemminger
  2015-06-27  2:37       ` Wang, Liang-min
  2015-06-27  1:34     ` Stephen Hemminger
  2015-06-27  1:34     ` Stephen Hemminger
  2 siblings, 1 reply; 174+ messages in thread
From: Stephen Hemminger @ 2015-06-27  1:32 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

On Fri, 26 Jun 2015 21:19:05 -0400
Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:

> +static int
> +ixgbe_get_reg_length(struct rte_eth_dev *dev __rte_unused)
> +{
> +	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private)

The dev arg is used, and therefore should not be marked __rte_unused.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
  2015-06-27  1:32     ` Stephen Hemminger
@ 2015-06-27  1:34     ` Stephen Hemminger
  2015-06-27  2:39       ` Wang, Liang-min
  2015-06-27  1:34     ` Stephen Hemminger
  2 siblings, 1 reply; 174+ messages in thread
From: Stephen Hemminger @ 2015-06-27  1:34 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

On Fri, 26 Jun 2015 21:19:05 -0400
Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:

> +	reg_group = reg_set[g_ind++];
> +	while (reg_group) {
> +		count += ixgbe_regs_group_count(reg_group);
> +		reg_group = reg_set[g_ind++];
> +	}

I don't care what checkpatch says, this an example of a loop
which reads better as:

        while ((reg_group = reg_set[g_ind++]))
               count += ixgbe_regs_group_count(reg_group);

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
  2015-06-27  1:32     ` Stephen Hemminger
  2015-06-27  1:34     ` Stephen Hemminger
@ 2015-06-27  1:34     ` Stephen Hemminger
  2 siblings, 0 replies; 174+ messages in thread
From: Stephen Hemminger @ 2015-06-27  1:34 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

On Fri, 26 Jun 2015 21:19:05 -0400
Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:

> +static struct reg_info ixgbe_regs_general[] = {
> +	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
> +	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
> +	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
> +	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
> +	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
> +	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
> +	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
> +	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
> +	{0, 0, 0, ""}
> +};
> +

All these fixed data structures should be marked as const.
You may have to fixup some other code that is assuming otherwise.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v9 3/5] igb: add ops to support ethtool ops
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 3/5] igb: " Liang-Min Larry Wang
@ 2015-06-27  1:35     ` Stephen Hemminger
  0 siblings, 0 replies; 174+ messages in thread
From: Stephen Hemminger @ 2015-06-27  1:35 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

On Fri, 26 Jun 2015 21:19:06 -0400
Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:

> +static struct reg_info igb_regs_general[] = {
> +	{E1000_CTRL, 1, 1, "E1000_CTRL"},
> +	{E1000_STATUS, 1, 1, "E1000_STATUS"},
> +	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
> +	{E1000_MDIC, 1, 1, "E1000_MDIC"},
> +	{E1000_SCTL, 1, 1, "E1000_SCTL"},
> +	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
> +	{E1000_VET, 1, 1, "E1000_VET"},
> +	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
> +	{E1000_PBA, 1, 1, "E1000_PBA"},
> +	{E1000_PBS, 1, 1, "E1000_PBS"},
> +	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
> +	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
> +	{0, 0, 0, ""}
> +};
> +

All pre-set reg_info should be const.

And this as well:

> +static struct reg_info *igb_regs[] = {
> +				igb_regs_general,
> +				igb_regs_nvm,
> +				igb_regs_interrupt,
> +				igb_regs_fctl,
> +				igb_regs_rxdma,
> +				igb_regs_rx,
> +				igb_regs_tx,
> +				igb_regs_wakeup,
> +				igb_regs_mac,
> +				NULL};
> +

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to const
  2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to const Liang-Min Larry Wang
@ 2015-06-27  1:36     ` Stephen Hemminger
  2015-06-27  1:50       ` Wang, Liang-min
                         ` (2 more replies)
  0 siblings, 3 replies; 174+ messages in thread
From: Stephen Hemminger @ 2015-06-27  1:36 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

On Fri, 26 Jun 2015 21:19:08 -0400
Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:

> Changed registers tables in ixgbe and igb to const type.
> 
> Signed-off-by: Andrew G. Harvey <agh@cisco.com>
> Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>

Since code is not yet accepted, all these changes should be rolled back into
next (v10) of the original patch. 

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to const
  2015-06-27  1:36     ` Stephen Hemminger
@ 2015-06-27  1:50       ` Wang, Liang-min
  2015-06-27  2:40       ` Wang, Liang-min
  2015-07-10 12:55       ` Wang, Liang-min
  2 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-27  1:50 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev



> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Friday, June 26, 2015 9:37 PM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to
> const
> 
> On Fri, 26 Jun 2015 21:19:08 -0400
> Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
> 
> > Changed registers tables in ixgbe and igb to const type.
> >
> > Signed-off-by: Andrew G. Harvey <agh@cisco.com>
> > Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> 
> Since code is not yet accepted, all these changes should be rolled back into
> next (v10) of the original patch.

Are you saying that we could not have a 5/5 needs to be applied to 2/5 and 3/5

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v10 0/4] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (7 preceding siblings ...)
  2015-06-27  1:19 ` [dpdk-dev] [PATCH v9 " Liang-Min Larry Wang
@ 2015-06-27  2:36 ` Liang-Min Larry Wang
  2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (3 more replies)
  2015-06-27 12:25 ` [dpdk-dev] [PATCH v11 0/4] User-space Ethtool Liang-Min Larry Wang
                   ` (6 subsequent siblings)
  15 siblings, 4 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27  2:36 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v10 changes:
- Merged const fix back to igb/ixgbe.
v9 changes:
- Fixed checkpatch errors.
v8 changes:
- Changed register tables to const.
v7 change:
- Remove rte_eth_dev_get_ringparam implementation
v6 change:
- Rebase to match new changes over librte_ether
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (4):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  175 ++++
 drivers/net/e1000/igb_regs.h                     |  227 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  179 +++-
 drivers/net/ixgbe/ixgbe_regs.h                   |  380 ++++++++
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   57 ++
 lib/librte_ether/rte_ethdev.c                    |   99 ++
 lib/librte_ether/rte_ethdev.h                    |  117 +++
 lib/librte_ether/rte_ether_version.map           |    6 +
 19 files changed, 4618 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v10 1/4] ethdev: add apis to support access device info
  2015-06-27  2:36 ` [dpdk-dev] [PATCH v10 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-06-27  2:36   ` Liang-Min Larry Wang
  2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27  2:36 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add new apis:
- rte_eth_dev_default_mac_addr_set
- rte_eth_dev_reg_length
- rte_eth_dev_reg_info
- rte_eth_dev_eeprom_length
- rte_eth_dev_get_eeprom
- rte_eth_dev_set_eeprom

to enable reading device parameters (mac-addr, register,
eeprom) based upon ethtool alike
data parameter specification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  57 ++++++++++++++++
 lib/librte_ether/rte_ethdev.c          |  99 ++++++++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 117 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   6 ++
 5 files changed, 280 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..6848051
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,57 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 02cd07f..9a33330 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2751,6 +2751,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3644,3 +3668,78 @@ rte_eth_dev_set_mc_addr_list(uint8_t port_id,
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_mc_addr_list, -ENOTSUP);
 	return dev->dev_ops->set_mc_addr_list(dev, mc_addr_set, nb_mc_addr);
 }
+
+int
+rte_eth_dev_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index f1219ac..94d7be0 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1233,6 +1234,24 @@ typedef int (*eth_set_mc_addr_list_t)(struct rte_eth_dev *dev,
 				      uint32_t nb_mc_addr);
 /**< @internal set the list of multicast addresses on an Ethernet device */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1372,6 +1391,17 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -2987,6 +3017,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3616,6 +3660,79 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 012a82e..40d025b 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,12 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v10 2/4] ixgbe: add ops to support ethtool ops
  2015-06-27  2:36 ` [dpdk-dev] [PATCH v10 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-27  2:36   ` Liang-Min Larry Wang
  2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 3/4] igb: " Liang-Min Larry Wang
  2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27  2:36 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 179 +++++++++++++++++-
 drivers/net/ixgbe/ixgbe_regs.h   | 380 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 557 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index f18550c..d40d8b9 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -179,6 +183,8 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev,
+					   struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -223,6 +229,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+					     struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -260,6 +268,19 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev,
+			    struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *regs);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -359,6 +380,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -386,6 +408,11 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.rss_hash_conf_get    = ixgbe_dev_rss_hash_conf_get,
 	.filter_ctrl          = ixgbe_dev_filter_ctrl,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -412,6 +439,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2902,6 +2932,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3741,6 +3779,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4481,8 +4527,8 @@ ixgbe_dev_addr_list_itr(__attribute__((unused)) struct ixgbe_hw *hw,
 
 static int
 ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
-			   struct ether_addr *mc_addr_set,
-			   uint32_t nb_mc_addr)
+			  struct ether_addr *mc_addr_set,
+			  uint32_t nb_mc_addr)
 {
 	struct ixgbe_hw *hw;
 	u8 *mc_addr_list;
@@ -4493,6 +4539,135 @@ ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 					 ixgbe_dev_addr_list_itr, TRUE);
 }
 
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	while ((reg_group = reg_set[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = ixgbevf_regs[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	      struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = reg_set[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+				reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		reg_group = ixgbevf_regs[g_ind++];
+		while ((reg_group = ixgbevf_regs[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+						      reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size * 2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..3298dd3
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,380 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static const struct reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_nvm[] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_interrupt[] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_interrupt[] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rx[] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_tx[] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_tx[] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_wakeup[] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_dcb[] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_mac[] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_diagnostic[] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static const struct reg_info *ixgbe_regs_others[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm, ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_others,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+static const struct reg_info *ixgbe_regs_mac_82598EB[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm,
+				ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_mac_82598EB,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+/* VF registers */
+static const struct reg_info *ixgbevf_regs[] = {
+				ixgbevf_regs_general,
+				ixgbevf_regs_interrupt,
+				ixgbevf_regs_rxdma,
+				ixgbevf_regs_tx,
+				NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++)
+		reg_buf[i] = IXGBE_READ_REG(hw,
+					reg->base_addr + i * reg->stride);
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+					  const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += ixgbe_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif /* _IXGBE_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v10 3/4] igb: add ops to support ethtool ops
  2015-06-27  2:36 ` [dpdk-dev] [PATCH v10 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-06-27  2:36   ` Liang-Min Larry Wang
  2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27  2:36 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 175 +++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 227 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 402 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 24c7510..c422b2d 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -129,6 +130,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -142,6 +145,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -193,6 +202,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -268,12 +285,18 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
 	.rss_hash_conf_get    = eth_igb_rss_hash_conf_get,
 	.filter_ctrl          = eth_igb_filter_ctrl,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -295,6 +318,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2113,6 +2139,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+				struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2347,6 +2381,17 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* index is not used by rar_set() */
+	hw->mac.ops.rar_set(hw, (void *)addr, 0);
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3660,6 +3705,136 @@ eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igb_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igbvf_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igb_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igbvf_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size * 2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..9f3146f
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,227 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+};
+
+static const struct reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_nvm[] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_interrupt[] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rx[] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_tx[] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_wakeup[] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_mac[] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info *igb_regs[] = {
+				igb_regs_general,
+				igb_regs_nvm,
+				igb_regs_interrupt,
+				igb_regs_fctl,
+				igb_regs_rxdma,
+				igb_regs_rx,
+				igb_regs_tx,
+				igb_regs_wakeup,
+				igb_regs_mac,
+				NULL};
+
+/* FIXME: reading igb_regs_interrupt results side-effect which doesn't
+ * work with VFIO; re-install igb_regs_interrupt once issue is resolved.
+ */
+static const struct reg_info *igbvf_regs[] = {
+				igb_regs_general,
+				igb_regs_rxdma,
+				igb_regs_tx,
+				NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw,
+				reg->base_addr + i * reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count) {
+		count += regs[i].count;
+		i++;
+	}
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+		const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count) {
+		count += igb_read_regs(hw, &regs[i], &reg_buf[count]);
+		i++;
+	}
+	return count;
+};
+
+#endif /* _IGB_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v10 4/4] examples: new example: l2fwd-ethtool
  2015-06-27  2:36 ` [dpdk-dev] [PATCH v10 0/4] User-space Ethtool Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 3/4] igb: " Liang-Min Larry Wang
@ 2015-06-27  2:36   ` Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27  2:36 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 10 files changed, 3379 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..80d257e
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..6f0d6d9
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -lrte_ethtool
+LDFLAGS += -L$(SRCDIR)/../lib/build
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..19dd58c
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1066 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id) ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id) ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask;
+
+/* virtio setup enable */
+static int virtio_setup;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* default period is 10 seconds */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+	return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done(void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ----------------------------",
+			portid);
+		printf("\nPackets sent: %24"PRIu64, port_statistics[portid].tx);
+		printf("\nPackets received: %20"PRIu64,
+			port_statistics[portid].rx);
+		printf("\nPackets dropped: %21"PRIu64,
+			port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ===============================");
+	printf("\nTotal packets sent: %18"PRIu64, total_packets_tx);
+	printf("\nTotal packets received: %14"PRIu64, total_packets_rx);
+	printf("\nTotal packets dropped: %15"PRIu64, total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid = 0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+					US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+	if (virtio_setup) {
+		while (is_ipc_done() == 0)
+			usleep(50);
+	}
+
+	while (1) {
+		cur_tsc = rte_rdtsc();
+
+		/* TX burst queue drain */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >=
+				    (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id ==
+					    rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+		"  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+		"  -V : setting rx/tx mode to enable virtio\n"
+		"  -T PERIOD: statistics will be refreshed each PERIOD seconds",
+		prgname);
+	printf("(0 to disable, 10 default, 86400 maximum)\n");
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) *
+				1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+			virtio_setup = l2fwd_parse_virtio_setup(optarg);
+			if (virtio_setup) {
+				port_conf.rxmode.hw_vlan_strip = 0;
+				port_conf.rxmode.hw_vlan_extend = 0;
+			}
+			break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status) {
+					printf("Port %d Link Up - speed %u "
+						, (uint8_t)portid,
+						(unsigned)link.link_speed);
+					printf("Mbps - %s\n", (link.link_duplex
+						== ETH_LINK_FULL_DUPLEX) ?
+						("full-duplex") :
+						("half-duplex\n"));
+				} else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+	uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of */
+		/* rte_eth_promiscuous_enable to test */
+		/* rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data =
+				(struct rte_eth_dev_data *)dev->data;
+
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is", port_id);
+		printf(" %s", mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))
+				) {
+				if (rte_ethtool_net_set_mac_addr(port_id,
+					(void *)new_mac_addr) == 0) {
+					printf(", and re-assigned to ");
+					printf("%s\n",
+					mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		if (req_type != (enum req_t)ipc_begin)
+			proc_invalid(req_id);
+		else
+			break;
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		port_id = param1[0];
+
+		switch ((enum req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id,
+				first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(
+				port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0)
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			if (reg_count)
+				status = proc_ethtool_get_regs(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0)
+				eeprom_size = rte_ethtool_get_eeprom_len(
+				port_id);
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id,
+				first_param, param2);
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_get_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_set_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id,
+				req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id,
+				req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id,
+				req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type:");
+			printf(" %d\n", req_type);
+			break;
+		}
+		if (status < 0)
+			printf("Request type (=%d) failed\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+	init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		} else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+			lcore_queue_conf[rx_lcore_id].n_rx_port ==
+			l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id,
+			(unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n",
+				(unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"Cannot configure device: err=%d, port=%u\n",
+				ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					rte_eth_dev_socket_id(portid),
+					NULL,
+					l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+	cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+		"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..0964bea
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,769 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE 6
+#define quad_aligned_size(x) ((x & 0x7) ? ((x+7)&0x7) : x)
+
+#define size16(data_type) (uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED -1
+#define NETDEV_INVALID -1
+#define NETDEV_STATUS(data_size) (GOOD_RETURN(data_size) \
+				? 0 : NETDEV_INVALID)
+#define UNUSED(x) (void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close(fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	/* block on read if reply is not available */
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id)
+		return -1;
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs),
+		param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size))
+		return link_status;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return valid;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t *param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else
+			*param2_size = 0;
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct ethtool_drvinfo);
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	reg_len = rte_ethtool_get_regs_len(port_id);
+	if (reg_len == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf))
+		data_size = STATUS_MASK;
+	else
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	eeprom_leng = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_leng == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = MAC_ADDR_SIZE;
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct rte_eth_stats);
+
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..82dd962
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,158 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE "/tmp/nic_request"
+#define REP_PIPE "/tmp/nic_reply"
+#define PAGE_SIZE (4*1024)
+#define STACK_SIZE (4*PAGE_SIZE)
+#define MAXI_DATA (1024*6)
+#define MAXI_PARA 1024
+#define STATUS_MASK 0x8000
+#define MULTIPLE_DATA_MASK 0x4000
+#define MAXI_REQ_TYPE 16
+#define FIRST_DATA_OFFSET 8
+#define to_ptr(new_ptr_type, data, offset) \
+	(new_ptr_type)(&((unsigned char *)(void *)data)[offset])
+#define u8ptr(x) (uint8_t *)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT (sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye) \
+	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size) \
+	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes) \
+	(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes) (data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size) (data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)	((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)		((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)	(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)	((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)	((dword_ptr[0] >> 16) & 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)	(dword_ptr[1])
+
+#define BAD_RETURN(data_size)	(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)	((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)	(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)	\
+	(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)		\
+	((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)	(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data, ptr_type)	\
+	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+enum req_t {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+};
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif /* _SHARED_FIFO_H_ */
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..be33a81
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..744cb0c
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,308 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	n = rte_eth_dev_reg_length(port_id);
+	if (n > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	n = rte_eth_dev_eeprom_length(port_id);
+	if (n > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	status = rte_eth_dev_reg_info(port_id, &reg_info);
+	if (status)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch (fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..dc234be
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,384 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to
+ * parameter attributes desribed by ethtool data structure,
+ * ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame
+ *	 configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..17ab4a3
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..f99af58
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,471 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES/(after_ts - before_ts))
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*8/(after_ts - before_ts))
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*64*8/(after_ts - before_ts))
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+}
+
+static uint32_t port_mask;
+static uint32_t vf_port_mask;
+static uint8_t num_of_ports;
+static int keep_traffic = 1;
+
+static inline int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1 << port_id)) > 0;
+}
+
+static inline int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports = reply_data[0];
+	port_mask = reply_data2[0];
+	vf_port_mask = reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0)
+				printf("setrlimit returned result = %d\n",
+					result);
+			else
+				printf("setrlimit succeed!!!\n");
+		} else
+			printf("default stack size is 0x%x\n",
+				(int)(rl.rlim_cur));
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id))
+		port_id = rand() & 0x1F;
+
+	return port_id;
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1)
+		keep_traffic = atoi(argv[1]);
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0)
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0)
+				netdev_net_set_rx_mode(port_id);
+			else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port");
+				printf(" #%d!!!\n", port_id);
+			} else
+				printf("\nPort #%d mac addr is %s\n",
+					port_id, mac_addr_str(mac_addr));
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s ",
+					drvinfo.driver, drvinfo.version);
+				printf("fw_version: %s bus_info=%s\n",
+					drvinfo.fw_version, drvinfo.bus_info);
+				printf("reg-size(bytes)=%d eeprom-size=%d\n",
+					drvinfo.regdump_len,
+					drvinfo.eedump_len);
+			}
+
+			count = netdev_ethtool_get_regs_len(port_id);
+			if (count <= 0) {
+				printf("There are no registers available from");
+				printf(" device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers ",
+					count);
+				printf("for dump\n");
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF,
+					sizeof(struct ethtool_regs));
+				count = netdev_ethtool_get_regs(port_id,
+					&regs, reply_data);
+				if (count) {
+					printf("failed to run");
+					printf(" ethtool_get_regs ");
+					printf("from port #%d (err=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x ",
+						int_ptr[0], int_ptr[10]);
+					printf("version=0x%x\n",
+						regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			count = 0;
+			if (!is_vf_port(port_id)) {
+				count = netdev_ethtool_get_eeprom_len(0);
+				if (count == 0) {
+					printf("fail to retrieve eeprom");
+					printf("count from port #%d\n",
+						port_id);
+				}
+			}
+
+			if (count) {
+				printf("eeprom size is %d bytes\n", count);
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				eeprom.magic = 0;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to read eeprom");
+					printf(" from port #%d\n",
+						port_id);
+				} else {
+					int i;
+					uint16_t *word = (uint16_t *)
+						((void *)reply_data);
+
+					printf("eeprom-magic: %x;",
+						eeprom.magic);
+					printf("eeprom data ...\n");
+					count = 80;
+					for (i = 0; i < (int)(eeprom.len
+						>> 1); i++) {
+						if (((i+1) % 16) == 0)
+							printf("\n");
+						printf("%4x ", word[i]);
+					}
+					printf("\n");
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (netdev_net_get_mac_addr(port_id,
+			to_mac_type(mac_addr)))
+			printf("Fail to get mac addr from port #%d!!!\n",
+				port_id);
+		else
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+
+		if (!netdev_net_validate_addr(port_id,
+			to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr,
+				MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n",
+				mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id,
+				to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id,
+				to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr");
+					printf(" @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign");
+				printf(" device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets,
+			last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets,
+			last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes,
+			last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes,
+			last_ts, ts));
+
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		int status;
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (!is_vf_port(port_id) && !link_up) {
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("failed to read eeprom");
+					printf(" break from post-run");
+					printf(" testing!!!\n");
+					break;
+				}
+				if (netdev_ethtool_set_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to write read-back");
+					printf(" data to eeprom!!!\n");
+					break;
+				}
+				/* checking mtu setting */
+				if (netdev_net_change_mtu(port_id, mtu)) {
+					printf("failed to set mtu");
+					printf("to %d\n", mtu);
+				}
+
+				/* add/remove vlan to vid */
+				status = netdev_net_vlan_rx_add_vid(
+					port_id, 0);
+				if (status == 0) {
+					status = netdev_net_vlan_rx_kill_vid(
+						port_id, 0);
+
+					if (status) {
+						printf("fail kill vlan-vid\n");
+						break;
+					}
+				} else {
+					printf("fail adding vlan/vid 0\n");
+					break;
+				}
+
+				/* testing pause parameter get/set functions */
+				status = netdev_ethtool_get_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("get pauseparam fail\n");
+					break;
+				}
+				printf("pause setup: autoneg: %d ",
+					pause_param.autoneg);
+				printf("tx_pause: %d ",
+					pause_param.tx_pause);
+				printf("rx_pause: %d\n",
+					pause_param.rx_pause);
+				status = netdev_ethtool_set_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("set pause param fail\n");
+					break;
+				}
+
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0)
+		;
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops
  2015-06-27  1:32     ` Stephen Hemminger
@ 2015-06-27  2:37       ` Wang, Liang-min
  0 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-27  2:37 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev



> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Friday, June 26, 2015 9:33 PM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops
> 
> On Fri, 26 Jun 2015 21:19:05 -0400
> Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
> 
> > +static int
> > +ixgbe_get_reg_length(struct rte_eth_dev *dev __rte_unused)
> > +{
> > +	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data-
> >dev_private)
> 
> The dev arg is used, and therefore should not be marked __rte_unused.

Fixed at v10.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops
  2015-06-27  1:34     ` Stephen Hemminger
@ 2015-06-27  2:39       ` Wang, Liang-min
  0 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-27  2:39 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev



> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Friday, June 26, 2015 9:34 PM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops
> 
> On Fri, 26 Jun 2015 21:19:05 -0400
> Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
> 
> > +	reg_group = reg_set[g_ind++];
> > +	while (reg_group) {
> > +		count += ixgbe_regs_group_count(reg_group);
> > +		reg_group = reg_set[g_ind++];
> > +	}
> 
> I don't care what checkpatch says, this an example of a loop
> which reads better as:
> 
>         while ((reg_group = reg_set[g_ind++]))
>                count += ixgbe_regs_group_count(reg_group);

There is no specific guideline on which to follow besides running checkpatch.
Maybe this type of exception should be listed on dpdk web-link.
This suggestion is taken on v10.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to const
  2015-06-27  1:36     ` Stephen Hemminger
  2015-06-27  1:50       ` Wang, Liang-min
@ 2015-06-27  2:40       ` Wang, Liang-min
  2015-07-10 12:55       ` Wang, Liang-min
  2 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-27  2:40 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev



> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Friday, June 26, 2015 9:37 PM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to
> const
> 
> On Fri, 26 Jun 2015 21:19:08 -0400
> Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
> 
> > Changed registers tables in ixgbe and igb to const type.
> >
> > Signed-off-by: Andrew G. Harvey <agh@cisco.com>
> > Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> 
> Since code is not yet accepted, all these changes should be rolled back into
> next (v10) of the original patch.

All the const changes are moved to the same patches on igb or ixgbe.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v11 0/4] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (8 preceding siblings ...)
  2015-06-27  2:36 ` [dpdk-dev] [PATCH v10 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-06-27 12:25 ` Liang-Min Larry Wang
  2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (3 more replies)
  2015-07-07 17:39 ` [dpdk-dev] [PATCH v12 0/4] User-space Ethtool Liang-Min Larry Wang
                   ` (5 subsequent siblings)
  15 siblings, 4 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27 12:25 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v11 changes:
- Fixed a typo and clean coding style.
v10 changes:
- Merged const fix back to igb/ixgbe.
v9 changes:
- Fixed checkpatch errors.
v8 changes:
- Changed register tables to const.
v7 change:
- Remove rte_eth_dev_get_ringparam implementation
v6 change:
- Rebase to match new changes over librte_ether
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (4):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  175 ++++
 drivers/net/e1000/igb_regs.h                     |  223 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  178 +++-
 drivers/net/ixgbe/ixgbe_regs.h                   |  376 ++++++++
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   57 ++
 lib/librte_ether/rte_ethdev.c                    |   99 ++
 lib/librte_ether/rte_ethdev.h                    |  117 +++
 lib/librte_ether/rte_ether_version.map           |    6 +
 19 files changed, 4609 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v11 1/4] ethdev: add apis to support access device info
  2015-06-27 12:25 ` [dpdk-dev] [PATCH v11 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-06-27 12:25   ` Liang-Min Larry Wang
  2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27 12:25 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add new apis:
- rte_eth_dev_default_mac_addr_set
- rte_eth_dev_reg_length
- rte_eth_dev_reg_info
- rte_eth_dev_eeprom_length
- rte_eth_dev_get_eeprom
- rte_eth_dev_set_eeprom

to enable reading device parameters (mac-addr, register,
eeprom) based upon ethtool alike
data parameter specification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  57 ++++++++++++++++
 lib/librte_ether/rte_ethdev.c          |  99 ++++++++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 117 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   6 ++
 5 files changed, 280 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..6848051
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,57 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 02cd07f..9a33330 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2751,6 +2751,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3644,3 +3668,78 @@ rte_eth_dev_set_mc_addr_list(uint8_t port_id,
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_mc_addr_list, -ENOTSUP);
 	return dev->dev_ops->set_mc_addr_list(dev, mc_addr_set, nb_mc_addr);
 }
+
+int
+rte_eth_dev_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index f1219ac..94d7be0 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1233,6 +1234,24 @@ typedef int (*eth_set_mc_addr_list_t)(struct rte_eth_dev *dev,
 				      uint32_t nb_mc_addr);
 /**< @internal set the list of multicast addresses on an Ethernet device */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1372,6 +1391,17 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -2987,6 +3017,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3616,6 +3660,79 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 012a82e..40d025b 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,12 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v11 2/4] ixgbe: add ops to support ethtool ops
  2015-06-27 12:25 ` [dpdk-dev] [PATCH v11 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-06-27 12:25   ` Liang-Min Larry Wang
  2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 3/4] igb: " Liang-Min Larry Wang
  2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27 12:25 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 178 +++++++++++++++++-
 drivers/net/ixgbe/ixgbe_regs.h   | 376 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 552 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index f18550c..05d96b7 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -179,6 +183,8 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev,
+					   struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -223,6 +229,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+					     struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -260,6 +268,19 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev,
+			    struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *regs);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -359,6 +380,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -386,6 +408,11 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.rss_hash_conf_get    = ixgbe_dev_rss_hash_conf_get,
 	.filter_ctrl          = ixgbe_dev_filter_ctrl,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -412,6 +439,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2902,6 +2932,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3741,6 +3779,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4481,8 +4527,8 @@ ixgbe_dev_addr_list_itr(__attribute__((unused)) struct ixgbe_hw *hw,
 
 static int
 ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
-			   struct ether_addr *mc_addr_set,
-			   uint32_t nb_mc_addr)
+			  struct ether_addr *mc_addr_set,
+			  uint32_t nb_mc_addr)
 {
 	struct ixgbe_hw *hw;
 	u8 *mc_addr_list;
@@ -4493,6 +4539,134 @@ ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 					 ixgbe_dev_addr_list_itr, TRUE);
 }
 
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	while ((reg_group = reg_set[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = ixgbevf_regs[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	      struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = reg_set[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+				reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = ixgbevf_regs[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+						      reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size * 2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..c7457a6
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,376 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static const struct reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_nvm[] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_interrupt[] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_interrupt[] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rx[] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_tx[] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_tx[] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_wakeup[] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_dcb[] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_mac[] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_diagnostic[] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static const struct reg_info *ixgbe_regs_others[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm, ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_others,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+static const struct reg_info *ixgbe_regs_mac_82598EB[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm,
+				ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_mac_82598EB,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+/* VF registers */
+static const struct reg_info *ixgbevf_regs[] = {
+				ixgbevf_regs_general,
+				ixgbevf_regs_interrupt,
+				ixgbevf_regs_rxdma,
+				ixgbevf_regs_tx,
+				NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++)
+		reg_buf[i] = IXGBE_READ_REG(hw,
+					reg->base_addr + i * reg->stride);
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+					  const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += ixgbe_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IXGBE_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v11 3/4] igb: add ops to support ethtool ops
  2015-06-27 12:25 ` [dpdk-dev] [PATCH v11 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-06-27 12:25   ` Liang-Min Larry Wang
  2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27 12:25 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 175 ++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 223 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 398 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 24c7510..c422b2d 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -129,6 +130,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -142,6 +145,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -193,6 +202,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -268,12 +285,18 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
 	.rss_hash_conf_get    = eth_igb_rss_hash_conf_get,
 	.filter_ctrl          = eth_igb_filter_ctrl,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -295,6 +318,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2113,6 +2139,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+				struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2347,6 +2381,17 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* index is not used by rar_set() */
+	hw->mac.ops.rar_set(hw, (void *)addr, 0);
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3660,6 +3705,136 @@ eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igb_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igbvf_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igb_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igbvf_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size * 2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..0b5e5e5
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,223 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+};
+
+static const struct reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_nvm[] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_interrupt[] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rx[] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_tx[] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_wakeup[] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_mac[] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info *igb_regs[] = {
+				igb_regs_general,
+				igb_regs_nvm,
+				igb_regs_interrupt,
+				igb_regs_fctl,
+				igb_regs_rxdma,
+				igb_regs_rx,
+				igb_regs_tx,
+				igb_regs_wakeup,
+				igb_regs_mac,
+				NULL};
+
+/* FIXME: reading igb_regs_interrupt results side-effect which doesn't
+ * work with VFIO; re-install igb_regs_interrupt once issue is resolved.
+ */
+static const struct reg_info *igbvf_regs[] = {
+				igb_regs_general,
+				igb_regs_rxdma,
+				igb_regs_tx,
+				NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw,
+				reg->base_addr + i * reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+		const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += igb_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IGB_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v11 4/4] examples: new example: l2fwd-ethtool
  2015-06-27 12:25 ` [dpdk-dev] [PATCH v11 0/4] User-space Ethtool Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 3/4] igb: " Liang-Min Larry Wang
@ 2015-06-27 12:25   ` Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-06-27 12:25 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   58 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 10 files changed, 3379 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..80d257e
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..6f0d6d9
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -lrte_ethtool
+LDFLAGS += -L$(SRCDIR)/../lib/build
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..19dd58c
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1066 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id) ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id) ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask;
+
+/* virtio setup enable */
+static int virtio_setup;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* default period is 10 seconds */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+	return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done(void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ----------------------------",
+			portid);
+		printf("\nPackets sent: %24"PRIu64, port_statistics[portid].tx);
+		printf("\nPackets received: %20"PRIu64,
+			port_statistics[portid].rx);
+		printf("\nPackets dropped: %21"PRIu64,
+			port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ===============================");
+	printf("\nTotal packets sent: %18"PRIu64, total_packets_tx);
+	printf("\nTotal packets received: %14"PRIu64, total_packets_rx);
+	printf("\nTotal packets dropped: %15"PRIu64, total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid = 0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+					US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+	if (virtio_setup) {
+		while (is_ipc_done() == 0)
+			usleep(50);
+	}
+
+	while (1) {
+		cur_tsc = rte_rdtsc();
+
+		/* TX burst queue drain */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >=
+				    (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id ==
+					    rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+		"  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+		"  -V : setting rx/tx mode to enable virtio\n"
+		"  -T PERIOD: statistics will be refreshed each PERIOD seconds",
+		prgname);
+	printf("(0 to disable, 10 default, 86400 maximum)\n");
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) *
+				1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+			virtio_setup = l2fwd_parse_virtio_setup(optarg);
+			if (virtio_setup) {
+				port_conf.rxmode.hw_vlan_strip = 0;
+				port_conf.rxmode.hw_vlan_extend = 0;
+			}
+			break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status) {
+					printf("Port %d Link Up - speed %u "
+						, (uint8_t)portid,
+						(unsigned)link.link_speed);
+					printf("Mbps - %s\n", (link.link_duplex
+						== ETH_LINK_FULL_DUPLEX) ?
+						("full-duplex") :
+						("half-duplex\n"));
+				} else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+	uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of */
+		/* rte_eth_promiscuous_enable to test */
+		/* rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data =
+				(struct rte_eth_dev_data *)dev->data;
+
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is", port_id);
+		printf(" %s", mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))
+				) {
+				if (rte_ethtool_net_set_mac_addr(port_id,
+					(void *)new_mac_addr) == 0) {
+					printf(", and re-assigned to ");
+					printf("%s\n",
+					mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		if (req_type != (enum req_t)ipc_begin)
+			proc_invalid(req_id);
+		else
+			break;
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		port_id = param1[0];
+
+		switch ((enum req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id,
+				first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(
+				port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0)
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			if (reg_count)
+				status = proc_ethtool_get_regs(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0)
+				eeprom_size = rte_ethtool_get_eeprom_len(
+				port_id);
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id,
+				first_param, param2);
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_get_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_set_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id,
+				req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id,
+				req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id,
+				req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type:");
+			printf(" %d\n", req_type);
+			break;
+		}
+		if (status < 0)
+			printf("Request type (=%d) failed\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+	init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		} else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+			lcore_queue_conf[rx_lcore_id].n_rx_port ==
+			l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id,
+			(unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n",
+				(unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"Cannot configure device: err=%d, port=%u\n",
+				ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					rte_eth_dev_socket_id(portid),
+					NULL,
+					l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+	cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+		"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..0964bea
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,769 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE 6
+#define quad_aligned_size(x) ((x & 0x7) ? ((x+7)&0x7) : x)
+
+#define size16(data_type) (uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED -1
+#define NETDEV_INVALID -1
+#define NETDEV_STATUS(data_size) (GOOD_RETURN(data_size) \
+				? 0 : NETDEV_INVALID)
+#define UNUSED(x) (void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close(fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	/* block on read if reply is not available */
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id)
+		return -1;
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs),
+		param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size))
+		return link_status;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return valid;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t *param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else
+			*param2_size = 0;
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct ethtool_drvinfo);
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	reg_len = rte_ethtool_get_regs_len(port_id);
+	if (reg_len == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf))
+		data_size = STATUS_MASK;
+	else
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	eeprom_leng = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_leng == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = MAC_ADDR_SIZE;
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct rte_eth_stats);
+
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..82dd962
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,158 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE "/tmp/nic_request"
+#define REP_PIPE "/tmp/nic_reply"
+#define PAGE_SIZE (4*1024)
+#define STACK_SIZE (4*PAGE_SIZE)
+#define MAXI_DATA (1024*6)
+#define MAXI_PARA 1024
+#define STATUS_MASK 0x8000
+#define MULTIPLE_DATA_MASK 0x4000
+#define MAXI_REQ_TYPE 16
+#define FIRST_DATA_OFFSET 8
+#define to_ptr(new_ptr_type, data, offset) \
+	(new_ptr_type)(&((unsigned char *)(void *)data)[offset])
+#define u8ptr(x) (uint8_t *)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT (sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye) \
+	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size) \
+	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes) \
+	(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes) (data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size) (data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)	((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)		((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)	(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)	((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)	((dword_ptr[0] >> 16) & 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)	(dword_ptr[1])
+
+#define BAD_RETURN(data_size)	(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)	((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)	(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)	\
+	(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)		\
+	((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)	(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data, ptr_type)	\
+	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+enum req_t {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+};
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif /* _SHARED_FIFO_H_ */
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..be33a81
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..744cb0c
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,308 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	n = rte_eth_dev_reg_length(port_id);
+	if (n > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	n = rte_eth_dev_eeprom_length(port_id);
+	if (n > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	status = rte_eth_dev_reg_info(port_id, &reg_info);
+	if (status)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch (fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..dc234be
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,384 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to
+ * parameter attributes desribed by ethtool data structure,
+ * ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame
+ *	 configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..17ab4a3
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..f99af58
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,471 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES/(after_ts - before_ts))
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*8/(after_ts - before_ts))
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*64*8/(after_ts - before_ts))
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+}
+
+static uint32_t port_mask;
+static uint32_t vf_port_mask;
+static uint8_t num_of_ports;
+static int keep_traffic = 1;
+
+static inline int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1 << port_id)) > 0;
+}
+
+static inline int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports = reply_data[0];
+	port_mask = reply_data2[0];
+	vf_port_mask = reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0)
+				printf("setrlimit returned result = %d\n",
+					result);
+			else
+				printf("setrlimit succeed!!!\n");
+		} else
+			printf("default stack size is 0x%x\n",
+				(int)(rl.rlim_cur));
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id))
+		port_id = rand() & 0x1F;
+
+	return port_id;
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1)
+		keep_traffic = atoi(argv[1]);
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0)
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0)
+				netdev_net_set_rx_mode(port_id);
+			else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port");
+				printf(" #%d!!!\n", port_id);
+			} else
+				printf("\nPort #%d mac addr is %s\n",
+					port_id, mac_addr_str(mac_addr));
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s ",
+					drvinfo.driver, drvinfo.version);
+				printf("fw_version: %s bus_info=%s\n",
+					drvinfo.fw_version, drvinfo.bus_info);
+				printf("reg-size(bytes)=%d eeprom-size=%d\n",
+					drvinfo.regdump_len,
+					drvinfo.eedump_len);
+			}
+
+			count = netdev_ethtool_get_regs_len(port_id);
+			if (count <= 0) {
+				printf("There are no registers available from");
+				printf(" device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers ",
+					count);
+				printf("for dump\n");
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF,
+					sizeof(struct ethtool_regs));
+				count = netdev_ethtool_get_regs(port_id,
+					&regs, reply_data);
+				if (count) {
+					printf("failed to run");
+					printf(" ethtool_get_regs ");
+					printf("from port #%d (err=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x ",
+						int_ptr[0], int_ptr[10]);
+					printf("version=0x%x\n",
+						regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			count = 0;
+			if (!is_vf_port(port_id)) {
+				count = netdev_ethtool_get_eeprom_len(0);
+				if (count == 0) {
+					printf("fail to retrieve eeprom");
+					printf("count from port #%d\n",
+						port_id);
+				}
+			}
+
+			if (count) {
+				printf("eeprom size is %d bytes\n", count);
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				eeprom.magic = 0;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to read eeprom");
+					printf(" from port #%d\n",
+						port_id);
+				} else {
+					int i;
+					uint16_t *word = (uint16_t *)
+						((void *)reply_data);
+
+					printf("eeprom-magic: %x;",
+						eeprom.magic);
+					printf("eeprom data ...\n");
+					count = 80;
+					for (i = 0; i < (int)(eeprom.len
+						>> 1); i++) {
+						if (((i+1) % 16) == 0)
+							printf("\n");
+						printf("%4x ", word[i]);
+					}
+					printf("\n");
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (netdev_net_get_mac_addr(port_id,
+			to_mac_type(mac_addr)))
+			printf("Fail to get mac addr from port #%d!!!\n",
+				port_id);
+		else
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+
+		if (!netdev_net_validate_addr(port_id,
+			to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr,
+				MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n",
+				mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id,
+				to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id,
+				to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr");
+					printf(" @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign");
+				printf(" device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets,
+			last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets,
+			last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes,
+			last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes,
+			last_ts, ts));
+
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		int status;
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (!is_vf_port(port_id) && !link_up) {
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("failed to read eeprom");
+					printf(" break from post-run");
+					printf(" testing!!!\n");
+					break;
+				}
+				if (netdev_ethtool_set_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to write read-back");
+					printf(" data to eeprom!!!\n");
+					break;
+				}
+				/* checking mtu setting */
+				if (netdev_net_change_mtu(port_id, mtu)) {
+					printf("failed to set mtu");
+					printf("to %d\n", mtu);
+				}
+
+				/* add/remove vlan to vid */
+				status = netdev_net_vlan_rx_add_vid(
+					port_id, 0);
+				if (status == 0) {
+					status = netdev_net_vlan_rx_kill_vid(
+						port_id, 0);
+
+					if (status) {
+						printf("fail kill vlan-vid\n");
+						break;
+					}
+				} else {
+					printf("fail adding vlan/vid 0\n");
+					break;
+				}
+
+				/* testing pause parameter get/set functions */
+				status = netdev_ethtool_get_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("get pauseparam fail\n");
+					break;
+				}
+				printf("pause setup: autoneg: %d ",
+					pause_param.autoneg);
+				printf("tx_pause: %d ",
+					pause_param.tx_pause);
+				printf("rx_pause: %d\n",
+					pause_param.rx_pause);
+				status = netdev_ethtool_set_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("set pause param fail\n");
+					break;
+				}
+
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0)
+		;
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v12 0/4] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (9 preceding siblings ...)
  2015-06-27 12:25 ` [dpdk-dev] [PATCH v11 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-07-07 17:39 ` Liang-Min Larry Wang
  2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (3 more replies)
  2015-07-10 12:48 ` [dpdk-dev] [PATCH v13 0/4] User-space Ethtool Liang-Min Larry Wang
                   ` (4 subsequent siblings)
  15 siblings, 4 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-07 17:39 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang, shemming

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v12 changes:
- Update coding style to match latest change over rte_ethdev.c (by shemming@brocade.com)
v11 changes:
- Fixed a typo and clean coding style.
v10 changes:
- Merged const fix back to igb/ixgbe.
v9 changes:
- Fixed checkpatch errors.
v8 changes:
- Changed register tables to const.
v7 change:
- Remove rte_eth_dev_get_ringparam implementation
v6 change:
- Rebase to match new changes over librte_ether
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (4):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  175 ++++
 drivers/net/e1000/igb_regs.h                     |  223 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  178 +++-
 drivers/net/ixgbe/ixgbe_regs.h                   |  376 ++++++++
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   59 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   57 ++
 lib/librte_ether/rte_ethdev.c                    |   84 ++
 lib/librte_ether/rte_ethdev.h                    |  117 +++
 lib/librte_ether/rte_ether_version.map           |    6 +
 20 files changed, 4598 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v12 1/4] ethdev: add apis to support access device info
  2015-07-07 17:39 ` [dpdk-dev] [PATCH v12 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-07-07 17:39   ` Liang-Min Larry Wang
  2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-07 17:39 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang, shemming

add two new apis: rte_eth_dev_default_mac_addr_set
and rte_eth_ethtool_dev_info to enable
reading device parameters (mac, register, eeprom,
pause, ring) based upon ethtool alike
data parameter sepcification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  57 ++++++++++++++++
 lib/librte_ether/rte_ethdev.c          |  84 +++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 117 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   6 ++
 5 files changed, 265 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..6848051
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,57 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 34ac677..9675dd4 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2562,6 +2562,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3324,3 +3348,63 @@ rte_eth_dev_set_mc_addr_list(uint8_t port_id,
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_mc_addr_list, -ENOTSUP);
 	return dev->dev_ops->set_mc_addr_list(dev, mc_addr_set, nb_mc_addr);
 }
+
+int
+rte_eth_dev_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 37d9a2b..751d998 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1239,6 +1240,24 @@ typedef int (*eth_set_mc_addr_list_t)(struct rte_eth_dev *dev,
 				      uint32_t nb_mc_addr);
 /**< @internal set the list of multicast addresses on an Ethernet device */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1378,6 +1397,17 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -2992,6 +3022,20 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3621,6 +3665,79 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index e3c8fa1..403387c 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,12 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v12 2/4] ixgbe: add ops to support ethtool ops
  2015-07-07 17:39 ` [dpdk-dev] [PATCH v12 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-07-07 17:39   ` Liang-Min Larry Wang
  2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 3/4] igb: " Liang-Min Larry Wang
  2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-07 17:39 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang, shemming

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 178 +++++++++++++++++-
 drivers/net/ixgbe/ixgbe_regs.h   | 376 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 552 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 0638302..1ba507a 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -179,6 +183,8 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev,
+					   struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -223,6 +229,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+					     struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -260,6 +268,19 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev,
+			    struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *regs);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -359,6 +380,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -386,6 +408,11 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.rss_hash_conf_get    = ixgbe_dev_rss_hash_conf_get,
 	.filter_ctrl          = ixgbe_dev_filter_ctrl,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -412,6 +439,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2902,6 +2932,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3759,6 +3797,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4499,8 +4545,8 @@ ixgbe_dev_addr_list_itr(__attribute__((unused)) struct ixgbe_hw *hw,
 
 static int
 ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
-			   struct ether_addr *mc_addr_set,
-			   uint32_t nb_mc_addr)
+			  struct ether_addr *mc_addr_set,
+			  uint32_t nb_mc_addr)
 {
 	struct ixgbe_hw *hw;
 	u8 *mc_addr_list;
@@ -4511,6 +4557,134 @@ ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 					 ixgbe_dev_addr_list_itr, TRUE);
 }
 
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	while ((reg_group = reg_set[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = ixgbevf_regs[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	      struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = reg_set[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+				reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = ixgbevf_regs[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+						      reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size * 2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..c7457a6
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,376 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static const struct reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_nvm[] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_interrupt[] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_interrupt[] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rx[] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_tx[] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_tx[] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_wakeup[] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_dcb[] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_mac[] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_diagnostic[] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static const struct reg_info *ixgbe_regs_others[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm, ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_others,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+static const struct reg_info *ixgbe_regs_mac_82598EB[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm,
+				ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_mac_82598EB,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+/* VF registers */
+static const struct reg_info *ixgbevf_regs[] = {
+				ixgbevf_regs_general,
+				ixgbevf_regs_interrupt,
+				ixgbevf_regs_rxdma,
+				ixgbevf_regs_tx,
+				NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++)
+		reg_buf[i] = IXGBE_READ_REG(hw,
+					reg->base_addr + i * reg->stride);
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+					  const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += ixgbe_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IXGBE_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v12 3/4] igb: add ops to support ethtool ops
  2015-07-07 17:39 ` [dpdk-dev] [PATCH v12 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-07-07 17:39   ` Liang-Min Larry Wang
  2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-07 17:39 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang, shemming

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 175 ++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 223 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 398 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 24c7510..c422b2d 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -129,6 +130,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -142,6 +145,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -193,6 +202,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -268,12 +285,18 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
 	.rss_hash_conf_get    = eth_igb_rss_hash_conf_get,
 	.filter_ctrl          = eth_igb_filter_ctrl,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -295,6 +318,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2113,6 +2139,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+				struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2347,6 +2381,17 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* index is not used by rar_set() */
+	hw->mac.ops.rar_set(hw, (void *)addr, 0);
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3660,6 +3705,136 @@ eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igb_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igbvf_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igb_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igbvf_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size * 2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..0b5e5e5
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,223 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+};
+
+static const struct reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_nvm[] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_interrupt[] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rx[] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_tx[] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_wakeup[] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_mac[] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info *igb_regs[] = {
+				igb_regs_general,
+				igb_regs_nvm,
+				igb_regs_interrupt,
+				igb_regs_fctl,
+				igb_regs_rxdma,
+				igb_regs_rx,
+				igb_regs_tx,
+				igb_regs_wakeup,
+				igb_regs_mac,
+				NULL};
+
+/* FIXME: reading igb_regs_interrupt results side-effect which doesn't
+ * work with VFIO; re-install igb_regs_interrupt once issue is resolved.
+ */
+static const struct reg_info *igbvf_regs[] = {
+				igb_regs_general,
+				igb_regs_rxdma,
+				igb_regs_tx,
+				NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw,
+				reg->base_addr + i * reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+		const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += igb_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IGB_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v12 4/4] examples: new example: l2fwd-ethtool
  2015-07-07 17:39 ` [dpdk-dev] [PATCH v12 0/4] User-space Ethtool Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 3/4] igb: " Liang-Min Larry Wang
@ 2015-07-07 17:39   ` Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-07 17:39 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang, shemming

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   59 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 11 files changed, 3383 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/Makefile b/examples/Makefile
index b4eddbd..cd1c4b0 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -50,6 +50,9 @@ DIRS-y += ip_reassembly
 DIRS-$(CONFIG_RTE_IP_FRAG) += ip_fragmentation
 DIRS-y += ipv4_multicast
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
+DIRS-y += l2fwd-ethtool/lib
+DIRS-y += l2fwd-ethtool/nic-control
+DIRS-y += l2fwd-ethtool/l2fwd-app
 DIRS-y += l2fwd
 DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
 DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..80d257e
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..e64d561
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,59 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -lrte_ethtool
+LDFLAGS += -L$(SRCDIR)/../build/lib
+LDFLAGS += -L$(SRCDIR)/../lib/l2fwd-ethtool/lib/$(RTE_TARGET)/lib
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..19dd58c
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1066 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id) ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id) ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask;
+
+/* virtio setup enable */
+static int virtio_setup;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* default period is 10 seconds */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+	return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done(void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ----------------------------",
+			portid);
+		printf("\nPackets sent: %24"PRIu64, port_statistics[portid].tx);
+		printf("\nPackets received: %20"PRIu64,
+			port_statistics[portid].rx);
+		printf("\nPackets dropped: %21"PRIu64,
+			port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ===============================");
+	printf("\nTotal packets sent: %18"PRIu64, total_packets_tx);
+	printf("\nTotal packets received: %14"PRIu64, total_packets_rx);
+	printf("\nTotal packets dropped: %15"PRIu64, total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid = 0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+					US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+	if (virtio_setup) {
+		while (is_ipc_done() == 0)
+			usleep(50);
+	}
+
+	while (1) {
+		cur_tsc = rte_rdtsc();
+
+		/* TX burst queue drain */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >=
+				    (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id ==
+					    rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+		"  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+		"  -V : setting rx/tx mode to enable virtio\n"
+		"  -T PERIOD: statistics will be refreshed each PERIOD seconds",
+		prgname);
+	printf("(0 to disable, 10 default, 86400 maximum)\n");
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) *
+				1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+			virtio_setup = l2fwd_parse_virtio_setup(optarg);
+			if (virtio_setup) {
+				port_conf.rxmode.hw_vlan_strip = 0;
+				port_conf.rxmode.hw_vlan_extend = 0;
+			}
+			break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status) {
+					printf("Port %d Link Up - speed %u "
+						, (uint8_t)portid,
+						(unsigned)link.link_speed);
+					printf("Mbps - %s\n", (link.link_duplex
+						== ETH_LINK_FULL_DUPLEX) ?
+						("full-duplex") :
+						("half-duplex\n"));
+				} else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+	uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of */
+		/* rte_eth_promiscuous_enable to test */
+		/* rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data =
+				(struct rte_eth_dev_data *)dev->data;
+
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is", port_id);
+		printf(" %s", mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))
+				) {
+				if (rte_ethtool_net_set_mac_addr(port_id,
+					(void *)new_mac_addr) == 0) {
+					printf(", and re-assigned to ");
+					printf("%s\n",
+					mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		if (req_type != (enum req_t)ipc_begin)
+			proc_invalid(req_id);
+		else
+			break;
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		port_id = param1[0];
+
+		switch ((enum req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id,
+				first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(
+				port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0)
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			if (reg_count)
+				status = proc_ethtool_get_regs(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0)
+				eeprom_size = rte_ethtool_get_eeprom_len(
+				port_id);
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id,
+				first_param, param2);
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_get_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_set_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id,
+				req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id,
+				req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id,
+				req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type:");
+			printf(" %d\n", req_type);
+			break;
+		}
+		if (status < 0)
+			printf("Request type (=%d) failed\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+	init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		} else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+			lcore_queue_conf[rx_lcore_id].n_rx_port ==
+			l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id,
+			(unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n",
+				(unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"Cannot configure device: err=%d, port=%u\n",
+				ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					rte_eth_dev_socket_id(portid),
+					NULL,
+					l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+	cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+		"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..0964bea
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,769 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE 6
+#define quad_aligned_size(x) ((x & 0x7) ? ((x+7)&0x7) : x)
+
+#define size16(data_type) (uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED -1
+#define NETDEV_INVALID -1
+#define NETDEV_STATUS(data_size) (GOOD_RETURN(data_size) \
+				? 0 : NETDEV_INVALID)
+#define UNUSED(x) (void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close(fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	/* block on read if reply is not available */
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id)
+		return -1;
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs),
+		param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size))
+		return link_status;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return valid;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t *param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else
+			*param2_size = 0;
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct ethtool_drvinfo);
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	reg_len = rte_ethtool_get_regs_len(port_id);
+	if (reg_len == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf))
+		data_size = STATUS_MASK;
+	else
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	eeprom_leng = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_leng == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = MAC_ADDR_SIZE;
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct rte_eth_stats);
+
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..82dd962
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,158 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE "/tmp/nic_request"
+#define REP_PIPE "/tmp/nic_reply"
+#define PAGE_SIZE (4*1024)
+#define STACK_SIZE (4*PAGE_SIZE)
+#define MAXI_DATA (1024*6)
+#define MAXI_PARA 1024
+#define STATUS_MASK 0x8000
+#define MULTIPLE_DATA_MASK 0x4000
+#define MAXI_REQ_TYPE 16
+#define FIRST_DATA_OFFSET 8
+#define to_ptr(new_ptr_type, data, offset) \
+	(new_ptr_type)(&((unsigned char *)(void *)data)[offset])
+#define u8ptr(x) (uint8_t *)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT (sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye) \
+	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size) \
+	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes) \
+	(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes) (data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size) (data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)	((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)		((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)	(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)	((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)	((dword_ptr[0] >> 16) & 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)	(dword_ptr[1])
+
+#define BAD_RETURN(data_size)	(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)	((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)	(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)	\
+	(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)		\
+	((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)	(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data, ptr_type)	\
+	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+enum req_t {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+};
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif /* _SHARED_FIFO_H_ */
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..be33a81
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..744cb0c
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,308 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	n = rte_eth_dev_reg_length(port_id);
+	if (n > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	n = rte_eth_dev_eeprom_length(port_id);
+	if (n > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	status = rte_eth_dev_reg_info(port_id, &reg_info);
+	if (status)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch (fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..dc234be
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,384 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to
+ * parameter attributes desribed by ethtool data structure,
+ * ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame
+ *	 configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..17ab4a3
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..f99af58
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,471 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES/(after_ts - before_ts))
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*8/(after_ts - before_ts))
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*64*8/(after_ts - before_ts))
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+}
+
+static uint32_t port_mask;
+static uint32_t vf_port_mask;
+static uint8_t num_of_ports;
+static int keep_traffic = 1;
+
+static inline int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1 << port_id)) > 0;
+}
+
+static inline int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports = reply_data[0];
+	port_mask = reply_data2[0];
+	vf_port_mask = reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0)
+				printf("setrlimit returned result = %d\n",
+					result);
+			else
+				printf("setrlimit succeed!!!\n");
+		} else
+			printf("default stack size is 0x%x\n",
+				(int)(rl.rlim_cur));
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id))
+		port_id = rand() & 0x1F;
+
+	return port_id;
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1)
+		keep_traffic = atoi(argv[1]);
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0)
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0)
+				netdev_net_set_rx_mode(port_id);
+			else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port");
+				printf(" #%d!!!\n", port_id);
+			} else
+				printf("\nPort #%d mac addr is %s\n",
+					port_id, mac_addr_str(mac_addr));
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s ",
+					drvinfo.driver, drvinfo.version);
+				printf("fw_version: %s bus_info=%s\n",
+					drvinfo.fw_version, drvinfo.bus_info);
+				printf("reg-size(bytes)=%d eeprom-size=%d\n",
+					drvinfo.regdump_len,
+					drvinfo.eedump_len);
+			}
+
+			count = netdev_ethtool_get_regs_len(port_id);
+			if (count <= 0) {
+				printf("There are no registers available from");
+				printf(" device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers ",
+					count);
+				printf("for dump\n");
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF,
+					sizeof(struct ethtool_regs));
+				count = netdev_ethtool_get_regs(port_id,
+					&regs, reply_data);
+				if (count) {
+					printf("failed to run");
+					printf(" ethtool_get_regs ");
+					printf("from port #%d (err=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x ",
+						int_ptr[0], int_ptr[10]);
+					printf("version=0x%x\n",
+						regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			count = 0;
+			if (!is_vf_port(port_id)) {
+				count = netdev_ethtool_get_eeprom_len(0);
+				if (count == 0) {
+					printf("fail to retrieve eeprom");
+					printf("count from port #%d\n",
+						port_id);
+				}
+			}
+
+			if (count) {
+				printf("eeprom size is %d bytes\n", count);
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				eeprom.magic = 0;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to read eeprom");
+					printf(" from port #%d\n",
+						port_id);
+				} else {
+					int i;
+					uint16_t *word = (uint16_t *)
+						((void *)reply_data);
+
+					printf("eeprom-magic: %x;",
+						eeprom.magic);
+					printf("eeprom data ...\n");
+					count = 80;
+					for (i = 0; i < (int)(eeprom.len
+						>> 1); i++) {
+						if (((i+1) % 16) == 0)
+							printf("\n");
+						printf("%4x ", word[i]);
+					}
+					printf("\n");
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (netdev_net_get_mac_addr(port_id,
+			to_mac_type(mac_addr)))
+			printf("Fail to get mac addr from port #%d!!!\n",
+				port_id);
+		else
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+
+		if (!netdev_net_validate_addr(port_id,
+			to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr,
+				MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n",
+				mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id,
+				to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id,
+				to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr");
+					printf(" @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign");
+				printf(" device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets,
+			last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets,
+			last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes,
+			last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes,
+			last_ts, ts));
+
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		int status;
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (!is_vf_port(port_id) && !link_up) {
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("failed to read eeprom");
+					printf(" break from post-run");
+					printf(" testing!!!\n");
+					break;
+				}
+				if (netdev_ethtool_set_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to write read-back");
+					printf(" data to eeprom!!!\n");
+					break;
+				}
+				/* checking mtu setting */
+				if (netdev_net_change_mtu(port_id, mtu)) {
+					printf("failed to set mtu");
+					printf("to %d\n", mtu);
+				}
+
+				/* add/remove vlan to vid */
+				status = netdev_net_vlan_rx_add_vid(
+					port_id, 0);
+				if (status == 0) {
+					status = netdev_net_vlan_rx_kill_vid(
+						port_id, 0);
+
+					if (status) {
+						printf("fail kill vlan-vid\n");
+						break;
+					}
+				} else {
+					printf("fail adding vlan/vid 0\n");
+					break;
+				}
+
+				/* testing pause parameter get/set functions */
+				status = netdev_ethtool_get_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("get pauseparam fail\n");
+					break;
+				}
+				printf("pause setup: autoneg: %d ",
+					pause_param.autoneg);
+				printf("tx_pause: %d ",
+					pause_param.tx_pause);
+				printf("rx_pause: %d\n",
+					pause_param.rx_pause);
+				status = netdev_ethtool_set_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("set pause param fail\n");
+					break;
+				}
+
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0)
+		;
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v13 0/4] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (10 preceding siblings ...)
  2015-07-07 17:39 ` [dpdk-dev] [PATCH v12 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-07-10 12:48 ` Liang-Min Larry Wang
  2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (3 more replies)
  2015-07-12 21:22 ` [dpdk-dev] [PATCH v14 0/4] User-space Ethtool Liang-Min Larry Wang
                   ` (3 subsequent siblings)
  15 siblings, 4 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-10 12:48 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang, shemming

v13 changes:
- Rebase beause patch 1588
v12 changes:
- Update coding style to match latest change over rte_ethdev.c (by shemming@brocade.com)
v11 changes:
- Fixed a typo and clean coding style.
v10 changes:
- Merged const fix back to igb/ixgbe.
v9 changes:
- Fixed checkpatch errors.
v8 changes:
- Changed register tables to const.
v7 change:
- Remove rte_eth_dev_get_ringparam implementation
v6 change:
- Rebase to match new changes over librte_ether
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (4):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  175 ++++
 drivers/net/e1000/igb_regs.h                     |  223 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  178 +++-
 drivers/net/ixgbe/ixgbe_regs.h                   |  376 ++++++++
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   59 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   57 ++
 lib/librte_ether/rte_ethdev.c                    |   84 ++
 lib/librte_ether/rte_ethdev.h                    |  118 +++
 lib/librte_ether/rte_ether_version.map           |    6 +
 20 files changed, 4599 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v13 1/4] ethdev: add apis to support access device info
  2015-07-10 12:48 ` [dpdk-dev] [PATCH v13 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-07-10 12:48   ` Liang-Min Larry Wang
  2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-10 12:48 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang, shemming

add two new apis: rte_eth_dev_default_mac_addr_set
and rte_eth_ethtool_dev_info to enable
reading device parameters (mac, register, eeprom,
pause, ring) based upon ethtool alike
data parameter sepcification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  57 ++++++++++++++++
 lib/librte_ether/rte_ethdev.c          |  84 +++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 118 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   6 ++
 5 files changed, 266 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..6848051
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,57 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index b79e5f7..6c1da9e 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2542,6 +2542,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3353,3 +3377,63 @@ rte_eth_timesync_read_tx_timestamp(uint8_t port_id, struct timespec *timestamp)
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->timesync_read_tx_timestamp, -ENOTSUP);
 	return (*dev->dev_ops->timesync_read_tx_timestamp)(dev, timestamp);
 }
+
+int
+rte_eth_dev_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 79bde89..c8583bb 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1255,6 +1256,24 @@ typedef int (*eth_timesync_read_tx_timestamp_t)(struct rte_eth_dev *dev,
 						struct timespec *timestamp);
 /**< @internal Function used to read a TX IEEE1588/802.1AS timestamp. */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1394,6 +1413,17 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -3017,6 +3047,21 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   M
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3646,6 +3691,79 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 39baf11..290b206 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,12 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v13 2/4] ixgbe: add ops to support ethtool ops
  2015-07-10 12:48 ` [dpdk-dev] [PATCH v13 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-07-10 12:48   ` Liang-Min Larry Wang
  2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 3/4] igb: " Liang-Min Larry Wang
  2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-10 12:48 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang, shemming

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 178 +++++++++++++++++-
 drivers/net/ixgbe/ixgbe_regs.h   | 376 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 552 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 4015feb..6676e71 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -187,6 +191,8 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev,
+					   struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -231,6 +237,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+					     struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -268,6 +276,19 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev,
+			    struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *regs);
 
 static int ixgbe_timesync_enable(struct rte_eth_dev *dev);
 static int ixgbe_timesync_disable(struct rte_eth_dev *dev);
@@ -375,6 +396,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -406,6 +428,11 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.timesync_disable     = ixgbe_timesync_disable,
 	.timesync_read_rx_timestamp = ixgbe_timesync_read_rx_timestamp,
 	.timesync_read_tx_timestamp = ixgbe_timesync_read_tx_timestamp,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -432,6 +459,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2923,6 +2953,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3780,6 +3818,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4520,8 +4566,8 @@ ixgbe_dev_addr_list_itr(__attribute__((unused)) struct ixgbe_hw *hw,
 
 static int
 ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
-			   struct ether_addr *mc_addr_set,
-			   uint32_t nb_mc_addr)
+			  struct ether_addr *mc_addr_set,
+			  uint32_t nb_mc_addr)
 {
 	struct ixgbe_hw *hw;
 	u8 *mc_addr_list;
@@ -4636,6 +4682,134 @@ ixgbe_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
 	return  0;
 }
 
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	while ((reg_group = reg_set[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = ixgbevf_regs[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	      struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = reg_set[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+				reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = ixgbevf_regs[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+						      reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size * 2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..c7457a6
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,376 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static const struct reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_nvm[] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_interrupt[] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_interrupt[] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rx[] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_tx[] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_tx[] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_wakeup[] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_dcb[] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_mac[] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_diagnostic[] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static const struct reg_info *ixgbe_regs_others[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm, ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_others,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+static const struct reg_info *ixgbe_regs_mac_82598EB[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm,
+				ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_mac_82598EB,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+/* VF registers */
+static const struct reg_info *ixgbevf_regs[] = {
+				ixgbevf_regs_general,
+				ixgbevf_regs_interrupt,
+				ixgbevf_regs_rxdma,
+				ixgbevf_regs_tx,
+				NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++)
+		reg_buf[i] = IXGBE_READ_REG(hw,
+					reg->base_addr + i * reg->stride);
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+					  const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += ixgbe_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IXGBE_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v13 3/4] igb: add ops to support ethtool ops
  2015-07-10 12:48 ` [dpdk-dev] [PATCH v13 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-07-10 12:48   ` Liang-Min Larry Wang
  2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-10 12:48 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang, shemming

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 175 ++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 223 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 398 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index eb97218..c6d057f 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -137,6 +138,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -150,6 +153,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -201,6 +210,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -283,6 +300,7 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
@@ -293,6 +311,11 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.timesync_disable     = igb_timesync_disable,
 	.timesync_read_rx_timestamp = igb_timesync_read_rx_timestamp,
 	.timesync_read_tx_timestamp = igb_timesync_read_tx_timestamp,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -314,6 +337,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2133,6 +2159,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+				struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2367,6 +2401,17 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* index is not used by rar_set() */
+	hw->mac.ops.rar_set(hw, (void *)addr, 0);
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3778,6 +3823,136 @@ igb_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
 	return  0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igb_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igbvf_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igb_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igbvf_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size * 2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..0b5e5e5
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,223 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+};
+
+static const struct reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_nvm[] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_interrupt[] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rx[] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_tx[] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_wakeup[] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_mac[] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info *igb_regs[] = {
+				igb_regs_general,
+				igb_regs_nvm,
+				igb_regs_interrupt,
+				igb_regs_fctl,
+				igb_regs_rxdma,
+				igb_regs_rx,
+				igb_regs_tx,
+				igb_regs_wakeup,
+				igb_regs_mac,
+				NULL};
+
+/* FIXME: reading igb_regs_interrupt results side-effect which doesn't
+ * work with VFIO; re-install igb_regs_interrupt once issue is resolved.
+ */
+static const struct reg_info *igbvf_regs[] = {
+				igb_regs_general,
+				igb_regs_rxdma,
+				igb_regs_tx,
+				NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw,
+				reg->base_addr + i * reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+		const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += igb_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IGB_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v13 4/4] examples: new example: l2fwd-ethtool
  2015-07-10 12:48 ` [dpdk-dev] [PATCH v13 0/4] User-space Ethtool Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 3/4] igb: " Liang-Min Larry Wang
@ 2015-07-10 12:48   ` Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-10 12:48 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang, shemming

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   59 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 11 files changed, 3383 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/Makefile b/examples/Makefile
index b4eddbd..cd1c4b0 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -50,6 +50,9 @@ DIRS-y += ip_reassembly
 DIRS-$(CONFIG_RTE_IP_FRAG) += ip_fragmentation
 DIRS-y += ipv4_multicast
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
+DIRS-y += l2fwd-ethtool/lib
+DIRS-y += l2fwd-ethtool/nic-control
+DIRS-y += l2fwd-ethtool/l2fwd-app
 DIRS-y += l2fwd
 DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
 DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..80d257e
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..e64d561
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,59 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -lrte_ethtool
+LDFLAGS += -L$(SRCDIR)/../build/lib
+LDFLAGS += -L$(SRCDIR)/../lib/l2fwd-ethtool/lib/$(RTE_TARGET)/lib
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..19dd58c
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1066 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id) ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id) ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask;
+
+/* virtio setup enable */
+static int virtio_setup;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* default period is 10 seconds */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+	return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done(void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ----------------------------",
+			portid);
+		printf("\nPackets sent: %24"PRIu64, port_statistics[portid].tx);
+		printf("\nPackets received: %20"PRIu64,
+			port_statistics[portid].rx);
+		printf("\nPackets dropped: %21"PRIu64,
+			port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ===============================");
+	printf("\nTotal packets sent: %18"PRIu64, total_packets_tx);
+	printf("\nTotal packets received: %14"PRIu64, total_packets_rx);
+	printf("\nTotal packets dropped: %15"PRIu64, total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid = 0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+					US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+	if (virtio_setup) {
+		while (is_ipc_done() == 0)
+			usleep(50);
+	}
+
+	while (1) {
+		cur_tsc = rte_rdtsc();
+
+		/* TX burst queue drain */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >=
+				    (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id ==
+					    rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+		"  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+		"  -V : setting rx/tx mode to enable virtio\n"
+		"  -T PERIOD: statistics will be refreshed each PERIOD seconds",
+		prgname);
+	printf("(0 to disable, 10 default, 86400 maximum)\n");
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) *
+				1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+			virtio_setup = l2fwd_parse_virtio_setup(optarg);
+			if (virtio_setup) {
+				port_conf.rxmode.hw_vlan_strip = 0;
+				port_conf.rxmode.hw_vlan_extend = 0;
+			}
+			break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status) {
+					printf("Port %d Link Up - speed %u "
+						, (uint8_t)portid,
+						(unsigned)link.link_speed);
+					printf("Mbps - %s\n", (link.link_duplex
+						== ETH_LINK_FULL_DUPLEX) ?
+						("full-duplex") :
+						("half-duplex\n"));
+				} else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+	uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of */
+		/* rte_eth_promiscuous_enable to test */
+		/* rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data =
+				(struct rte_eth_dev_data *)dev->data;
+
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is", port_id);
+		printf(" %s", mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))
+				) {
+				if (rte_ethtool_net_set_mac_addr(port_id,
+					(void *)new_mac_addr) == 0) {
+					printf(", and re-assigned to ");
+					printf("%s\n",
+					mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		if (req_type != (enum req_t)ipc_begin)
+			proc_invalid(req_id);
+		else
+			break;
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		port_id = param1[0];
+
+		switch ((enum req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id,
+				first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(
+				port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0)
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			if (reg_count)
+				status = proc_ethtool_get_regs(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0)
+				eeprom_size = rte_ethtool_get_eeprom_len(
+				port_id);
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id,
+				first_param, param2);
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_get_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_set_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id,
+				req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id,
+				req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id,
+				req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type:");
+			printf(" %d\n", req_type);
+			break;
+		}
+		if (status < 0)
+			printf("Request type (=%d) failed\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+	init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		} else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+			lcore_queue_conf[rx_lcore_id].n_rx_port ==
+			l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id,
+			(unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n",
+				(unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"Cannot configure device: err=%d, port=%u\n",
+				ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					rte_eth_dev_socket_id(portid),
+					NULL,
+					l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+	cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+		"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..0964bea
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,769 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE 6
+#define quad_aligned_size(x) ((x & 0x7) ? ((x+7)&0x7) : x)
+
+#define size16(data_type) (uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED -1
+#define NETDEV_INVALID -1
+#define NETDEV_STATUS(data_size) (GOOD_RETURN(data_size) \
+				? 0 : NETDEV_INVALID)
+#define UNUSED(x) (void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close(fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	/* block on read if reply is not available */
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id)
+		return -1;
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs),
+		param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size))
+		return link_status;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return valid;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t *param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else
+			*param2_size = 0;
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct ethtool_drvinfo);
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	reg_len = rte_ethtool_get_regs_len(port_id);
+	if (reg_len == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf))
+		data_size = STATUS_MASK;
+	else
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	eeprom_leng = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_leng == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = MAC_ADDR_SIZE;
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct rte_eth_stats);
+
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..82dd962
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,158 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE "/tmp/nic_request"
+#define REP_PIPE "/tmp/nic_reply"
+#define PAGE_SIZE (4*1024)
+#define STACK_SIZE (4*PAGE_SIZE)
+#define MAXI_DATA (1024*6)
+#define MAXI_PARA 1024
+#define STATUS_MASK 0x8000
+#define MULTIPLE_DATA_MASK 0x4000
+#define MAXI_REQ_TYPE 16
+#define FIRST_DATA_OFFSET 8
+#define to_ptr(new_ptr_type, data, offset) \
+	(new_ptr_type)(&((unsigned char *)(void *)data)[offset])
+#define u8ptr(x) (uint8_t *)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT (sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye) \
+	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size) \
+	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes) \
+	(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes) (data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size) (data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)	((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)		((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)	(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)	((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)	((dword_ptr[0] >> 16) & 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)	(dword_ptr[1])
+
+#define BAD_RETURN(data_size)	(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)	((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)	(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)	\
+	(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)		\
+	((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)	(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data, ptr_type)	\
+	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+enum req_t {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+};
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif /* _SHARED_FIFO_H_ */
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..be33a81
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..744cb0c
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,308 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	n = rte_eth_dev_reg_length(port_id);
+	if (n > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	n = rte_eth_dev_eeprom_length(port_id);
+	if (n > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	status = rte_eth_dev_reg_info(port_id, &reg_info);
+	if (status)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch (fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..dc234be
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,384 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to
+ * parameter attributes desribed by ethtool data structure,
+ * ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame
+ *	 configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..17ab4a3
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..f99af58
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,471 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES/(after_ts - before_ts))
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*8/(after_ts - before_ts))
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*64*8/(after_ts - before_ts))
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+}
+
+static uint32_t port_mask;
+static uint32_t vf_port_mask;
+static uint8_t num_of_ports;
+static int keep_traffic = 1;
+
+static inline int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1 << port_id)) > 0;
+}
+
+static inline int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports = reply_data[0];
+	port_mask = reply_data2[0];
+	vf_port_mask = reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0)
+				printf("setrlimit returned result = %d\n",
+					result);
+			else
+				printf("setrlimit succeed!!!\n");
+		} else
+			printf("default stack size is 0x%x\n",
+				(int)(rl.rlim_cur));
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id))
+		port_id = rand() & 0x1F;
+
+	return port_id;
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1)
+		keep_traffic = atoi(argv[1]);
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0)
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0)
+				netdev_net_set_rx_mode(port_id);
+			else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port");
+				printf(" #%d!!!\n", port_id);
+			} else
+				printf("\nPort #%d mac addr is %s\n",
+					port_id, mac_addr_str(mac_addr));
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s ",
+					drvinfo.driver, drvinfo.version);
+				printf("fw_version: %s bus_info=%s\n",
+					drvinfo.fw_version, drvinfo.bus_info);
+				printf("reg-size(bytes)=%d eeprom-size=%d\n",
+					drvinfo.regdump_len,
+					drvinfo.eedump_len);
+			}
+
+			count = netdev_ethtool_get_regs_len(port_id);
+			if (count <= 0) {
+				printf("There are no registers available from");
+				printf(" device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers ",
+					count);
+				printf("for dump\n");
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF,
+					sizeof(struct ethtool_regs));
+				count = netdev_ethtool_get_regs(port_id,
+					&regs, reply_data);
+				if (count) {
+					printf("failed to run");
+					printf(" ethtool_get_regs ");
+					printf("from port #%d (err=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x ",
+						int_ptr[0], int_ptr[10]);
+					printf("version=0x%x\n",
+						regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			count = 0;
+			if (!is_vf_port(port_id)) {
+				count = netdev_ethtool_get_eeprom_len(0);
+				if (count == 0) {
+					printf("fail to retrieve eeprom");
+					printf("count from port #%d\n",
+						port_id);
+				}
+			}
+
+			if (count) {
+				printf("eeprom size is %d bytes\n", count);
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				eeprom.magic = 0;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to read eeprom");
+					printf(" from port #%d\n",
+						port_id);
+				} else {
+					int i;
+					uint16_t *word = (uint16_t *)
+						((void *)reply_data);
+
+					printf("eeprom-magic: %x;",
+						eeprom.magic);
+					printf("eeprom data ...\n");
+					count = 80;
+					for (i = 0; i < (int)(eeprom.len
+						>> 1); i++) {
+						if (((i+1) % 16) == 0)
+							printf("\n");
+						printf("%4x ", word[i]);
+					}
+					printf("\n");
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (netdev_net_get_mac_addr(port_id,
+			to_mac_type(mac_addr)))
+			printf("Fail to get mac addr from port #%d!!!\n",
+				port_id);
+		else
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+
+		if (!netdev_net_validate_addr(port_id,
+			to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr,
+				MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n",
+				mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id,
+				to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id,
+				to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr");
+					printf(" @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign");
+				printf(" device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets,
+			last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets,
+			last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes,
+			last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes,
+			last_ts, ts));
+
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		int status;
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (!is_vf_port(port_id) && !link_up) {
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("failed to read eeprom");
+					printf(" break from post-run");
+					printf(" testing!!!\n");
+					break;
+				}
+				if (netdev_ethtool_set_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to write read-back");
+					printf(" data to eeprom!!!\n");
+					break;
+				}
+				/* checking mtu setting */
+				if (netdev_net_change_mtu(port_id, mtu)) {
+					printf("failed to set mtu");
+					printf("to %d\n", mtu);
+				}
+
+				/* add/remove vlan to vid */
+				status = netdev_net_vlan_rx_add_vid(
+					port_id, 0);
+				if (status == 0) {
+					status = netdev_net_vlan_rx_kill_vid(
+						port_id, 0);
+
+					if (status) {
+						printf("fail kill vlan-vid\n");
+						break;
+					}
+				} else {
+					printf("fail adding vlan/vid 0\n");
+					break;
+				}
+
+				/* testing pause parameter get/set functions */
+				status = netdev_ethtool_get_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("get pauseparam fail\n");
+					break;
+				}
+				printf("pause setup: autoneg: %d ",
+					pause_param.autoneg);
+				printf("tx_pause: %d ",
+					pause_param.tx_pause);
+				printf("rx_pause: %d\n",
+					pause_param.rx_pause);
+				status = netdev_ethtool_set_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("set pause param fail\n");
+					break;
+				}
+
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0)
+		;
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to const
  2015-06-27  1:36     ` Stephen Hemminger
  2015-06-27  1:50       ` Wang, Liang-min
  2015-06-27  2:40       ` Wang, Liang-min
@ 2015-07-10 12:55       ` Wang, Liang-min
  2 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-07-10 12:55 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

Stephen,

> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Friday, June 26, 2015 9:37 PM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to
> const
> 
> On Fri, 26 Jun 2015 21:19:08 -0400
> Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
> 
> > Changed registers tables in ixgbe and igb to const type.
> >
> > Signed-off-by: Andrew G. Harvey <agh@cisco.com>
> > Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> 
> Since code is not yet accepted, all these changes should be rolled back into
> next (v10) of the original patch.

On v10, I had made changes according to your feedback. I did more changes on v11/v12/v13 based upon incremental changes on master repository. Are there any pending issue on this patch?

Thanks,
Larry

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v14 0/4] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (11 preceding siblings ...)
  2015-07-10 12:48 ` [dpdk-dev] [PATCH v13 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-07-12 21:22 ` Liang-Min Larry Wang
  2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (3 more replies)
  2015-07-14  2:18 ` [dpdk-dev] [PATCH v15 0/4] User-space Ethtool Liang-Min Larry Wang
                   ` (2 subsequent siblings)
  15 siblings, 4 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-12 21:22 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v14 changes:
- Add library path to fix top-level, $RTE_TARGET, example/l2fwd-ethtool build
v13 changes:
- Rebase beause patch 1588
v12 changes:
- Update coding style to match latest change over rte_ethdev.c (by shemming@brocade.com)
v11 changes:
- Fixed a typo and clean coding style.
v10 changes:
- Merged const fix back to igb/ixgbe.
v9 changes:
- Fixed checkpatch errors.
v8 changes:
- Changed register tables to const.
v7 change:
- Remove rte_eth_dev_get_ringparam implementation
v6 change:
- Rebase to match new changes over librte_ether
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (4):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  175 ++++
 drivers/net/e1000/igb_regs.h                     |  223 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  178 +++-
 drivers/net/ixgbe/ixgbe_regs.h                   |  376 ++++++++
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   60 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   57 ++
 lib/librte_ether/rte_ethdev.c                    |   84 ++
 lib/librte_ether/rte_ethdev.h                    |  118 +++
 lib/librte_ether/rte_ether_version.map           |    6 +
 20 files changed, 4600 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v14 1/4] ethdev: add apis to support access device info
  2015-07-12 21:22 ` [dpdk-dev] [PATCH v14 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-07-12 21:22   ` Liang-Min Larry Wang
  2015-07-13 22:26     ` Thomas Monjalon
  2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-12 21:22 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add two new apis: rte_eth_dev_default_mac_addr_set
and rte_eth_ethtool_dev_info to enable
reading device parameters (mac, register, eeprom,
pause, ring) based upon ethtool alike
data parameter sepcification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  57 ++++++++++++++++
 lib/librte_ether/rte_ethdev.c          |  84 +++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 118 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   6 ++
 5 files changed, 266 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..6848051
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,57 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index b79e5f7..6c1da9e 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2542,6 +2542,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3353,3 +3377,63 @@ rte_eth_timesync_read_tx_timestamp(uint8_t port_id, struct timespec *timestamp)
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->timesync_read_tx_timestamp, -ENOTSUP);
 	return (*dev->dev_ops->timesync_read_tx_timestamp)(dev, timestamp);
 }
+
+int
+rte_eth_dev_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 79bde89..c8583bb 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1255,6 +1256,24 @@ typedef int (*eth_timesync_read_tx_timestamp_t)(struct rte_eth_dev *dev,
 						struct timespec *timestamp);
 /**< @internal Function used to read a TX IEEE1588/802.1AS timestamp. */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1394,6 +1413,17 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -3017,6 +3047,21 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   M
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3646,6 +3691,79 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 39baf11..290b206 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,12 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v14 2/4] ixgbe: add ops to support ethtool ops
  2015-07-12 21:22 ` [dpdk-dev] [PATCH v14 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-07-12 21:22   ` Liang-Min Larry Wang
  2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 3/4] igb: " Liang-Min Larry Wang
  2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-12 21:22 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 178 +++++++++++++++++-
 drivers/net/ixgbe/ixgbe_regs.h   | 376 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 552 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 4015feb..6676e71 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -187,6 +191,8 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev,
+					   struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -231,6 +237,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+					     struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -268,6 +276,19 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev,
+			    struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *regs);
 
 static int ixgbe_timesync_enable(struct rte_eth_dev *dev);
 static int ixgbe_timesync_disable(struct rte_eth_dev *dev);
@@ -375,6 +396,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -406,6 +428,11 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.timesync_disable     = ixgbe_timesync_disable,
 	.timesync_read_rx_timestamp = ixgbe_timesync_read_rx_timestamp,
 	.timesync_read_tx_timestamp = ixgbe_timesync_read_tx_timestamp,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -432,6 +459,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2923,6 +2953,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3780,6 +3818,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4520,8 +4566,8 @@ ixgbe_dev_addr_list_itr(__attribute__((unused)) struct ixgbe_hw *hw,
 
 static int
 ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
-			   struct ether_addr *mc_addr_set,
-			   uint32_t nb_mc_addr)
+			  struct ether_addr *mc_addr_set,
+			  uint32_t nb_mc_addr)
 {
 	struct ixgbe_hw *hw;
 	u8 *mc_addr_list;
@@ -4636,6 +4682,134 @@ ixgbe_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
 	return  0;
 }
 
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	while ((reg_group = reg_set[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = ixgbevf_regs[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	      struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = reg_set[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+				reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = ixgbevf_regs[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+						      reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size * 2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..c7457a6
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,376 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static const struct reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_nvm[] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_interrupt[] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_interrupt[] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rx[] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_tx[] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_tx[] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_wakeup[] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_dcb[] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_mac[] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_diagnostic[] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static const struct reg_info *ixgbe_regs_others[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm, ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_others,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+static const struct reg_info *ixgbe_regs_mac_82598EB[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm,
+				ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_mac_82598EB,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+/* VF registers */
+static const struct reg_info *ixgbevf_regs[] = {
+				ixgbevf_regs_general,
+				ixgbevf_regs_interrupt,
+				ixgbevf_regs_rxdma,
+				ixgbevf_regs_tx,
+				NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++)
+		reg_buf[i] = IXGBE_READ_REG(hw,
+					reg->base_addr + i * reg->stride);
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+					  const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += ixgbe_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IXGBE_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v14 3/4] igb: add ops to support ethtool ops
  2015-07-12 21:22 ` [dpdk-dev] [PATCH v14 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-07-12 21:22   ` Liang-Min Larry Wang
  2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-12 21:22 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 175 ++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 223 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 398 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index eb97218..c6d057f 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -137,6 +138,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -150,6 +153,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -201,6 +210,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -283,6 +300,7 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
@@ -293,6 +311,11 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.timesync_disable     = igb_timesync_disable,
 	.timesync_read_rx_timestamp = igb_timesync_read_rx_timestamp,
 	.timesync_read_tx_timestamp = igb_timesync_read_tx_timestamp,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -314,6 +337,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2133,6 +2159,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+				struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2367,6 +2401,17 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* index is not used by rar_set() */
+	hw->mac.ops.rar_set(hw, (void *)addr, 0);
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3778,6 +3823,136 @@ igb_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
 	return  0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igb_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igbvf_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igb_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igbvf_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size * 2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..0b5e5e5
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,223 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+};
+
+static const struct reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_nvm[] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_interrupt[] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rx[] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_tx[] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_wakeup[] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_mac[] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info *igb_regs[] = {
+				igb_regs_general,
+				igb_regs_nvm,
+				igb_regs_interrupt,
+				igb_regs_fctl,
+				igb_regs_rxdma,
+				igb_regs_rx,
+				igb_regs_tx,
+				igb_regs_wakeup,
+				igb_regs_mac,
+				NULL};
+
+/* FIXME: reading igb_regs_interrupt results side-effect which doesn't
+ * work with VFIO; re-install igb_regs_interrupt once issue is resolved.
+ */
+static const struct reg_info *igbvf_regs[] = {
+				igb_regs_general,
+				igb_regs_rxdma,
+				igb_regs_tx,
+				NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw,
+				reg->base_addr + i * reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+		const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += igb_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IGB_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v14 4/4] examples: new example: l2fwd-ethtool
  2015-07-12 21:22 ` [dpdk-dev] [PATCH v14 0/4] User-space Ethtool Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 3/4] igb: " Liang-Min Larry Wang
@ 2015-07-12 21:22   ` Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-12 21:22 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   60 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 11 files changed, 3384 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/Makefile b/examples/Makefile
index b4eddbd..cd1c4b0 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -50,6 +50,9 @@ DIRS-y += ip_reassembly
 DIRS-$(CONFIG_RTE_IP_FRAG) += ip_fragmentation
 DIRS-y += ipv4_multicast
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
+DIRS-y += l2fwd-ethtool/lib
+DIRS-y += l2fwd-ethtool/nic-control
+DIRS-y += l2fwd-ethtool/l2fwd-app
 DIRS-y += l2fwd
 DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
 DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..80d257e
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..fd0b9a7
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,60 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LIBDIRS += -L$(S)/../lib/l2fwd-ethtool/lib/$(RTE_TARGET)/lib
+LIBDIRS += -L$(S)/../lib/$(RTE_TARGET)/lib
+LIBDIRS += -L$(S)/../build/lib
+LDLIBS += $(LIBDIRS) -lrte_ethtool
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..19dd58c
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1066 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id) ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id) ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask;
+
+/* virtio setup enable */
+static int virtio_setup;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* default period is 10 seconds */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+	return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done(void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ----------------------------",
+			portid);
+		printf("\nPackets sent: %24"PRIu64, port_statistics[portid].tx);
+		printf("\nPackets received: %20"PRIu64,
+			port_statistics[portid].rx);
+		printf("\nPackets dropped: %21"PRIu64,
+			port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ===============================");
+	printf("\nTotal packets sent: %18"PRIu64, total_packets_tx);
+	printf("\nTotal packets received: %14"PRIu64, total_packets_rx);
+	printf("\nTotal packets dropped: %15"PRIu64, total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid = 0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+					US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+	if (virtio_setup) {
+		while (is_ipc_done() == 0)
+			usleep(50);
+	}
+
+	while (1) {
+		cur_tsc = rte_rdtsc();
+
+		/* TX burst queue drain */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >=
+				    (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id ==
+					    rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+		"  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+		"  -V : setting rx/tx mode to enable virtio\n"
+		"  -T PERIOD: statistics will be refreshed each PERIOD seconds",
+		prgname);
+	printf("(0 to disable, 10 default, 86400 maximum)\n");
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) *
+				1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+			virtio_setup = l2fwd_parse_virtio_setup(optarg);
+			if (virtio_setup) {
+				port_conf.rxmode.hw_vlan_strip = 0;
+				port_conf.rxmode.hw_vlan_extend = 0;
+			}
+			break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status) {
+					printf("Port %d Link Up - speed %u "
+						, (uint8_t)portid,
+						(unsigned)link.link_speed);
+					printf("Mbps - %s\n", (link.link_duplex
+						== ETH_LINK_FULL_DUPLEX) ?
+						("full-duplex") :
+						("half-duplex\n"));
+				} else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+	uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of */
+		/* rte_eth_promiscuous_enable to test */
+		/* rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data =
+				(struct rte_eth_dev_data *)dev->data;
+
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is", port_id);
+		printf(" %s", mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))
+				) {
+				if (rte_ethtool_net_set_mac_addr(port_id,
+					(void *)new_mac_addr) == 0) {
+					printf(", and re-assigned to ");
+					printf("%s\n",
+					mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		if (req_type != (enum req_t)ipc_begin)
+			proc_invalid(req_id);
+		else
+			break;
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		port_id = param1[0];
+
+		switch ((enum req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id,
+				first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(
+				port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0)
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			if (reg_count)
+				status = proc_ethtool_get_regs(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0)
+				eeprom_size = rte_ethtool_get_eeprom_len(
+				port_id);
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id,
+				first_param, param2);
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_get_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_set_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id,
+				req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id,
+				req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id,
+				req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type:");
+			printf(" %d\n", req_type);
+			break;
+		}
+		if (status < 0)
+			printf("Request type (=%d) failed\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+	init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		} else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+			lcore_queue_conf[rx_lcore_id].n_rx_port ==
+			l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id,
+			(unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n",
+				(unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"Cannot configure device: err=%d, port=%u\n",
+				ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					rte_eth_dev_socket_id(portid),
+					NULL,
+					l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+	cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+		"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..0964bea
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,769 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE 6
+#define quad_aligned_size(x) ((x & 0x7) ? ((x+7)&0x7) : x)
+
+#define size16(data_type) (uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED -1
+#define NETDEV_INVALID -1
+#define NETDEV_STATUS(data_size) (GOOD_RETURN(data_size) \
+				? 0 : NETDEV_INVALID)
+#define UNUSED(x) (void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close(fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	/* block on read if reply is not available */
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id)
+		return -1;
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs),
+		param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size))
+		return link_status;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return valid;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t *param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else
+			*param2_size = 0;
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct ethtool_drvinfo);
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	reg_len = rte_ethtool_get_regs_len(port_id);
+	if (reg_len == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf))
+		data_size = STATUS_MASK;
+	else
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	eeprom_leng = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_leng == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = MAC_ADDR_SIZE;
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct rte_eth_stats);
+
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..82dd962
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,158 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE "/tmp/nic_request"
+#define REP_PIPE "/tmp/nic_reply"
+#define PAGE_SIZE (4*1024)
+#define STACK_SIZE (4*PAGE_SIZE)
+#define MAXI_DATA (1024*6)
+#define MAXI_PARA 1024
+#define STATUS_MASK 0x8000
+#define MULTIPLE_DATA_MASK 0x4000
+#define MAXI_REQ_TYPE 16
+#define FIRST_DATA_OFFSET 8
+#define to_ptr(new_ptr_type, data, offset) \
+	(new_ptr_type)(&((unsigned char *)(void *)data)[offset])
+#define u8ptr(x) (uint8_t *)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT (sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye) \
+	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size) \
+	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes) \
+	(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes) (data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size) (data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)	((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)		((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)	(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)	((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)	((dword_ptr[0] >> 16) & 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)	(dword_ptr[1])
+
+#define BAD_RETURN(data_size)	(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)	((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)	(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)	\
+	(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)		\
+	((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)	(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data, ptr_type)	\
+	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+enum req_t {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+};
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif /* _SHARED_FIFO_H_ */
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..be33a81
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..744cb0c
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,308 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	n = rte_eth_dev_reg_length(port_id);
+	if (n > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	n = rte_eth_dev_eeprom_length(port_id);
+	if (n > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	status = rte_eth_dev_reg_info(port_id, &reg_info);
+	if (status)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch (fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..dc234be
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,384 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to
+ * parameter attributes desribed by ethtool data structure,
+ * ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame
+ *	 configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..17ab4a3
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..f99af58
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,471 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES/(after_ts - before_ts))
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*8/(after_ts - before_ts))
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*64*8/(after_ts - before_ts))
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+}
+
+static uint32_t port_mask;
+static uint32_t vf_port_mask;
+static uint8_t num_of_ports;
+static int keep_traffic = 1;
+
+static inline int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1 << port_id)) > 0;
+}
+
+static inline int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports = reply_data[0];
+	port_mask = reply_data2[0];
+	vf_port_mask = reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0)
+				printf("setrlimit returned result = %d\n",
+					result);
+			else
+				printf("setrlimit succeed!!!\n");
+		} else
+			printf("default stack size is 0x%x\n",
+				(int)(rl.rlim_cur));
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id))
+		port_id = rand() & 0x1F;
+
+	return port_id;
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1)
+		keep_traffic = atoi(argv[1]);
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0)
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0)
+				netdev_net_set_rx_mode(port_id);
+			else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port");
+				printf(" #%d!!!\n", port_id);
+			} else
+				printf("\nPort #%d mac addr is %s\n",
+					port_id, mac_addr_str(mac_addr));
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s ",
+					drvinfo.driver, drvinfo.version);
+				printf("fw_version: %s bus_info=%s\n",
+					drvinfo.fw_version, drvinfo.bus_info);
+				printf("reg-size(bytes)=%d eeprom-size=%d\n",
+					drvinfo.regdump_len,
+					drvinfo.eedump_len);
+			}
+
+			count = netdev_ethtool_get_regs_len(port_id);
+			if (count <= 0) {
+				printf("There are no registers available from");
+				printf(" device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers ",
+					count);
+				printf("for dump\n");
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF,
+					sizeof(struct ethtool_regs));
+				count = netdev_ethtool_get_regs(port_id,
+					&regs, reply_data);
+				if (count) {
+					printf("failed to run");
+					printf(" ethtool_get_regs ");
+					printf("from port #%d (err=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x ",
+						int_ptr[0], int_ptr[10]);
+					printf("version=0x%x\n",
+						regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			count = 0;
+			if (!is_vf_port(port_id)) {
+				count = netdev_ethtool_get_eeprom_len(0);
+				if (count == 0) {
+					printf("fail to retrieve eeprom");
+					printf("count from port #%d\n",
+						port_id);
+				}
+			}
+
+			if (count) {
+				printf("eeprom size is %d bytes\n", count);
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				eeprom.magic = 0;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to read eeprom");
+					printf(" from port #%d\n",
+						port_id);
+				} else {
+					int i;
+					uint16_t *word = (uint16_t *)
+						((void *)reply_data);
+
+					printf("eeprom-magic: %x;",
+						eeprom.magic);
+					printf("eeprom data ...\n");
+					count = 80;
+					for (i = 0; i < (int)(eeprom.len
+						>> 1); i++) {
+						if (((i+1) % 16) == 0)
+							printf("\n");
+						printf("%4x ", word[i]);
+					}
+					printf("\n");
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (netdev_net_get_mac_addr(port_id,
+			to_mac_type(mac_addr)))
+			printf("Fail to get mac addr from port #%d!!!\n",
+				port_id);
+		else
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+
+		if (!netdev_net_validate_addr(port_id,
+			to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr,
+				MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n",
+				mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id,
+				to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id,
+				to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr");
+					printf(" @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign");
+				printf(" device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets,
+			last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets,
+			last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes,
+			last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes,
+			last_ts, ts));
+
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		int status;
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (!is_vf_port(port_id) && !link_up) {
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("failed to read eeprom");
+					printf(" break from post-run");
+					printf(" testing!!!\n");
+					break;
+				}
+				if (netdev_ethtool_set_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to write read-back");
+					printf(" data to eeprom!!!\n");
+					break;
+				}
+				/* checking mtu setting */
+				if (netdev_net_change_mtu(port_id, mtu)) {
+					printf("failed to set mtu");
+					printf("to %d\n", mtu);
+				}
+
+				/* add/remove vlan to vid */
+				status = netdev_net_vlan_rx_add_vid(
+					port_id, 0);
+				if (status == 0) {
+					status = netdev_net_vlan_rx_kill_vid(
+						port_id, 0);
+
+					if (status) {
+						printf("fail kill vlan-vid\n");
+						break;
+					}
+				} else {
+					printf("fail adding vlan/vid 0\n");
+					break;
+				}
+
+				/* testing pause parameter get/set functions */
+				status = netdev_ethtool_get_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("get pauseparam fail\n");
+					break;
+				}
+				printf("pause setup: autoneg: %d ",
+					pause_param.autoneg);
+				printf("tx_pause: %d ",
+					pause_param.tx_pause);
+				printf("rx_pause: %d\n",
+					pause_param.rx_pause);
+				status = netdev_ethtool_set_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("set pause param fail\n");
+					break;
+				}
+
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0)
+		;
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v14 1/4] ethdev: add apis to support access device info
  2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-07-13 22:26     ` Thomas Monjalon
  0 siblings, 0 replies; 174+ messages in thread
From: Thomas Monjalon @ 2015-07-13 22:26 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

2015-07-12 17:22, Liang-Min Larry Wang:
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -2542,6 +2542,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
>  }
>  
>  int
> +rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
> +{
> +	struct rte_eth_dev *dev;
> +
> +	if (!rte_eth_dev_is_valid_port(port_id)) {
> +		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
> +		return -ENODEV;
> +	}
> +
> +	if (!is_valid_assigned_ether_addr(addr))
> +		return -EINVAL;
> +
> +	dev = &rte_eth_devices[port_id];
> +	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
> +
> +	/* Update default address in NIC data structure */
> +	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
> +
> +	(*dev->dev_ops->mac_addr_set)(dev, addr);
> +
> +	return 0;
> +}

It would be cleaner/clearer in a separate patch.
Why not using VALID_PORTID_OR_ERR_RET instead of rte_eth_dev_is_valid_port?

> +int
> +rte_eth_dev_reg_length(uint8_t port_id)
[...]
> +	return (*dev->dev_ops->get_reg_length)(dev);
> +}
[...]
> +int
> +rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
[...]
> +	return (*dev->dev_ops->get_reg)(dev, info);
> +}
[...]
> +int
> +rte_eth_dev_eeprom_length(uint8_t port_id)
[...]
> +	return (*dev->dev_ops->get_eeprom_length)(dev);
> +}

These functions should have the "get" word in their names.

> --- a/lib/librte_ether/rte_ether_version.map
> +++ b/lib/librte_ether/rte_ether_version.map
> @@ -102,6 +102,12 @@ DPDK_2.0 {
>  	rte_eth_tx_queue_setup;
>  	rte_eth_xstats_get;
>  	rte_eth_xstats_reset;
> +	rte_eth_dev_default_mac_addr_set;
> +	rte_eth_dev_reg_length;
> +	rte_eth_dev_reg_info;
> +	rte_eth_dev_eeprom_length;
> +	rte_eth_dev_get_eeprom;
> +	rte_eth_dev_set_eeprom;

The new symbols should be in a new node for DPDK 2.1.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v15 0/4] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (12 preceding siblings ...)
  2015-07-12 21:22 ` [dpdk-dev] [PATCH v14 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-07-14  2:18 ` Liang-Min Larry Wang
  2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (3 more replies)
  2015-07-14 13:11 ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Liang-Min Larry Wang
  2015-07-16 13:25 ` [dpdk-dev] [PATCH v17 0/5] " Liang-Min Larry Wang
  15 siblings, 4 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14  2:18 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang


This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v15 changes:
- Replace rte_eth_dev_is_valid_port with macro VALID_PORTID_OR_ERR_RET
- Fix VALID_PORTID_OR_ERR_RET issue (unused macro variable)
- Fix api version map (move from 2.0 to 2.1)
v14 changes:
- Add library path to fix top-level, $RTE_SDK, example/l2fwd-ethtool build
v13 changes:
- Rebase beause patch 1588
v12 changes:
- Update coding style to match latest change over rte_ethdev.c (by shemming@brocade.com)
v11 changes:
- Fixed a typo and clean coding style.
v10 changes:
- Merged const fix back to igb/ixgbe.
v9 changes:
- Fixed checkpatch errors.
v8 changes:
- Changed register tables to const.
v7 change:
- Remove rte_eth_dev_get_ringparam implementation
v6 change:
- Rebase to match new changes over librte_ether
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (4):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  175 ++++
 drivers/net/e1000/igb_regs.h                     |  223 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  178 +++-
 drivers/net/ixgbe/ixgbe_regs.h                   |  376 ++++++++
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   59 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   57 ++
 lib/librte_ether/rte_ethdev.c                    |   83 +-
 lib/librte_ether/rte_ethdev.h                    |  118 +++
 lib/librte_ether/rte_ether_version.map           |    6 +
 20 files changed, 4597 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info
  2015-07-14  2:18 ` [dpdk-dev] [PATCH v15 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-07-14  2:18   ` Liang-Min Larry Wang
  2015-07-15  6:16     ` Thomas Monjalon
  2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14  2:18 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add new apis:
- rte_eth_dev_default_mac_addr_set
- rte_eth_dev_get_reg_length
- rte_eth_dev_get_reg_info
- rte_eth_dev_get_eeprom_length
- rte_eth_dev_get_eeprom
- rte_eth_dev_set_eeprom

to enable reading device parameters (mac-addr, register,
eeprom) based upon ethtool alike
data parameter specification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  57 ++++++++++++++++
 lib/librte_ether/rte_ethdev.c          |  83 ++++++++++++++++++++++-
 lib/librte_ether/rte_ethdev.h          | 118 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   6 ++
 5 files changed, 264 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..6848051
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,57 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index ddf3658..c47b91f 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -111,7 +111,7 @@
 #define VALID_PORTID_OR_ERR_RET(port_id, retval) do {		\
 	if (!rte_eth_dev_is_valid_port(port_id)) {		\
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); \
-		return -EINVAL;					\
+		return retval;					\
 	}							\
 } while (0)
 
@@ -2542,6 +2542,27 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3377,3 +3398,63 @@ rte_eth_timesync_read_tx_timestamp(uint8_t port_id, struct timespec *timestamp)
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->timesync_read_tx_timestamp, -ENOTSUP);
 	return (*dev->dev_ops->timesync_read_tx_timestamp)(dev, timestamp);
 }
+
+int
+rte_eth_dev_get_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_get_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_get_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index d76bbb3..cd4666d 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1255,6 +1256,24 @@ typedef int (*eth_timesync_read_tx_timestamp_t)(struct rte_eth_dev *dev,
 						struct timespec *timestamp);
 /**< @internal Function used to read a TX IEEE1588/802.1AS timestamp. */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1394,6 +1413,17 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -3021,6 +3051,21 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   M
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3654,6 +3699,79 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 39baf11..2959c80 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -114,5 +114,11 @@ DPDK_2.1 {
 	rte_eth_timesync_enable;
 	rte_eth_timesync_read_rx_timestamp;
 	rte_eth_timesync_read_tx_timestamp;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
 
 } DPDK_2.0;
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v15 2/4] ixgbe: add ops to support ethtool ops
  2015-07-14  2:18 ` [dpdk-dev] [PATCH v15 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-07-14  2:18   ` Liang-Min Larry Wang
  2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 3/4] igb: " Liang-Min Larry Wang
  2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14  2:18 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 178 +++++++++++++++++-
 drivers/net/ixgbe/ixgbe_regs.h   | 376 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 552 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 8d68125..1fdc86d 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -187,6 +191,8 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev,
+					   struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -231,6 +237,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+					     struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -268,6 +276,19 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev,
+			    struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *regs);
 
 static int ixgbe_timesync_enable(struct rte_eth_dev *dev);
 static int ixgbe_timesync_disable(struct rte_eth_dev *dev);
@@ -375,6 +396,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -406,6 +428,11 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.timesync_disable     = ixgbe_timesync_disable,
 	.timesync_read_rx_timestamp = ixgbe_timesync_read_rx_timestamp,
 	.timesync_read_tx_timestamp = ixgbe_timesync_read_tx_timestamp,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -432,6 +459,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2928,6 +2958,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3785,6 +3823,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4525,8 +4571,8 @@ ixgbe_dev_addr_list_itr(__attribute__((unused)) struct ixgbe_hw *hw,
 
 static int
 ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
-			   struct ether_addr *mc_addr_set,
-			   uint32_t nb_mc_addr)
+			  struct ether_addr *mc_addr_set,
+			  uint32_t nb_mc_addr)
 {
 	struct ixgbe_hw *hw;
 	u8 *mc_addr_list;
@@ -4641,6 +4687,134 @@ ixgbe_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
 	return  0;
 }
 
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	while ((reg_group = reg_set[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = ixgbevf_regs[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	      struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = reg_set[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+				reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = ixgbevf_regs[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+						      reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size * 2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..c7457a6
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,376 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static const struct reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_nvm[] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_interrupt[] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_interrupt[] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rx[] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_tx[] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_tx[] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_wakeup[] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_dcb[] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_mac[] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_diagnostic[] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static const struct reg_info *ixgbe_regs_others[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm, ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_others,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+static const struct reg_info *ixgbe_regs_mac_82598EB[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm,
+				ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_mac_82598EB,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+/* VF registers */
+static const struct reg_info *ixgbevf_regs[] = {
+				ixgbevf_regs_general,
+				ixgbevf_regs_interrupt,
+				ixgbevf_regs_rxdma,
+				ixgbevf_regs_tx,
+				NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++)
+		reg_buf[i] = IXGBE_READ_REG(hw,
+					reg->base_addr + i * reg->stride);
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+					  const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += ixgbe_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IXGBE_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v15 3/4] igb: add ops to support ethtool ops
  2015-07-14  2:18 ` [dpdk-dev] [PATCH v15 0/4] User-space Ethtool Liang-Min Larry Wang
  2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-07-14  2:18   ` Liang-Min Larry Wang
  2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14  2:18 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 175 ++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 223 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 398 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index eb97218..c6d057f 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -137,6 +138,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -150,6 +153,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -201,6 +210,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -283,6 +300,7 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
@@ -293,6 +311,11 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.timesync_disable     = igb_timesync_disable,
 	.timesync_read_rx_timestamp = igb_timesync_read_rx_timestamp,
 	.timesync_read_tx_timestamp = igb_timesync_read_tx_timestamp,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -314,6 +337,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2133,6 +2159,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+				struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2367,6 +2401,17 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* index is not used by rar_set() */
+	hw->mac.ops.rar_set(hw, (void *)addr, 0);
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3778,6 +3823,136 @@ igb_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
 	return  0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igb_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igbvf_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igb_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igbvf_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size * 2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..0b5e5e5
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,223 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+};
+
+static const struct reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_nvm[] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_interrupt[] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rx[] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_tx[] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_wakeup[] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_mac[] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info *igb_regs[] = {
+				igb_regs_general,
+				igb_regs_nvm,
+				igb_regs_interrupt,
+				igb_regs_fctl,
+				igb_regs_rxdma,
+				igb_regs_rx,
+				igb_regs_tx,
+				igb_regs_wakeup,
+				igb_regs_mac,
+				NULL};
+
+/* FIXME: reading igb_regs_interrupt results side-effect which doesn't
+ * work with VFIO; re-install igb_regs_interrupt once issue is resolved.
+ */
+static const struct reg_info *igbvf_regs[] = {
+				igb_regs_general,
+				igb_regs_rxdma,
+				igb_regs_tx,
+				NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw,
+				reg->base_addr + i * reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+		const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += igb_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IGB_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v15 4/4] examples: new example: l2fwd-ethtool
  2015-07-14  2:18 ` [dpdk-dev] [PATCH v15 0/4] User-space Ethtool Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 3/4] igb: " Liang-Min Larry Wang
@ 2015-07-14  2:18   ` Liang-Min Larry Wang
  3 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14  2:18 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   59 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 11 files changed, 3383 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/Makefile b/examples/Makefile
index b4eddbd..cd1c4b0 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -50,6 +50,9 @@ DIRS-y += ip_reassembly
 DIRS-$(CONFIG_RTE_IP_FRAG) += ip_fragmentation
 DIRS-y += ipv4_multicast
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
+DIRS-y += l2fwd-ethtool/lib
+DIRS-y += l2fwd-ethtool/nic-control
+DIRS-y += l2fwd-ethtool/l2fwd-app
 DIRS-y += l2fwd
 DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
 DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..80d257e
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..5f45a79
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,59 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LIBDIRS += -L$(S)/../build/lib
+LIBDIRS += -L$(subst l2fwd-app,lib,$(RTE_OUTPUT))
+LDLIBS += $(LIBDIRS) -lrte_ethtool
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..19dd58c
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1066 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id) ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id) ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask;
+
+/* virtio setup enable */
+static int virtio_setup;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* default period is 10 seconds */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+	return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done(void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ----------------------------",
+			portid);
+		printf("\nPackets sent: %24"PRIu64, port_statistics[portid].tx);
+		printf("\nPackets received: %20"PRIu64,
+			port_statistics[portid].rx);
+		printf("\nPackets dropped: %21"PRIu64,
+			port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ===============================");
+	printf("\nTotal packets sent: %18"PRIu64, total_packets_tx);
+	printf("\nTotal packets received: %14"PRIu64, total_packets_rx);
+	printf("\nTotal packets dropped: %15"PRIu64, total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid = 0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+					US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+	if (virtio_setup) {
+		while (is_ipc_done() == 0)
+			usleep(50);
+	}
+
+	while (1) {
+		cur_tsc = rte_rdtsc();
+
+		/* TX burst queue drain */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >=
+				    (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id ==
+					    rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+		"  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+		"  -V : setting rx/tx mode to enable virtio\n"
+		"  -T PERIOD: statistics will be refreshed each PERIOD seconds",
+		prgname);
+	printf("(0 to disable, 10 default, 86400 maximum)\n");
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) *
+				1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+			virtio_setup = l2fwd_parse_virtio_setup(optarg);
+			if (virtio_setup) {
+				port_conf.rxmode.hw_vlan_strip = 0;
+				port_conf.rxmode.hw_vlan_extend = 0;
+			}
+			break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status) {
+					printf("Port %d Link Up - speed %u "
+						, (uint8_t)portid,
+						(unsigned)link.link_speed);
+					printf("Mbps - %s\n", (link.link_duplex
+						== ETH_LINK_FULL_DUPLEX) ?
+						("full-duplex") :
+						("half-duplex\n"));
+				} else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+	uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of */
+		/* rte_eth_promiscuous_enable to test */
+		/* rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data =
+				(struct rte_eth_dev_data *)dev->data;
+
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is", port_id);
+		printf(" %s", mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))
+				) {
+				if (rte_ethtool_net_set_mac_addr(port_id,
+					(void *)new_mac_addr) == 0) {
+					printf(", and re-assigned to ");
+					printf("%s\n",
+					mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		if (req_type != (enum req_t)ipc_begin)
+			proc_invalid(req_id);
+		else
+			break;
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		port_id = param1[0];
+
+		switch ((enum req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id,
+				first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(
+				port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0)
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			if (reg_count)
+				status = proc_ethtool_get_regs(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0)
+				eeprom_size = rte_ethtool_get_eeprom_len(
+				port_id);
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id,
+				first_param, param2);
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_get_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_set_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id,
+				req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id,
+				req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id,
+				req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type:");
+			printf(" %d\n", req_type);
+			break;
+		}
+		if (status < 0)
+			printf("Request type (=%d) failed\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+	init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		} else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+			lcore_queue_conf[rx_lcore_id].n_rx_port ==
+			l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id,
+			(unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n",
+				(unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"Cannot configure device: err=%d, port=%u\n",
+				ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					rte_eth_dev_socket_id(portid),
+					NULL,
+					l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+	cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+		"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..0964bea
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,769 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE 6
+#define quad_aligned_size(x) ((x & 0x7) ? ((x+7)&0x7) : x)
+
+#define size16(data_type) (uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED -1
+#define NETDEV_INVALID -1
+#define NETDEV_STATUS(data_size) (GOOD_RETURN(data_size) \
+				? 0 : NETDEV_INVALID)
+#define UNUSED(x) (void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close(fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	/* block on read if reply is not available */
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id)
+		return -1;
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs),
+		param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size))
+		return link_status;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return valid;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t *param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else
+			*param2_size = 0;
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct ethtool_drvinfo);
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	reg_len = rte_ethtool_get_regs_len(port_id);
+	if (reg_len == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf))
+		data_size = STATUS_MASK;
+	else
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	eeprom_leng = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_leng == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = MAC_ADDR_SIZE;
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct rte_eth_stats);
+
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..82dd962
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,158 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE "/tmp/nic_request"
+#define REP_PIPE "/tmp/nic_reply"
+#define PAGE_SIZE (4*1024)
+#define STACK_SIZE (4*PAGE_SIZE)
+#define MAXI_DATA (1024*6)
+#define MAXI_PARA 1024
+#define STATUS_MASK 0x8000
+#define MULTIPLE_DATA_MASK 0x4000
+#define MAXI_REQ_TYPE 16
+#define FIRST_DATA_OFFSET 8
+#define to_ptr(new_ptr_type, data, offset) \
+	(new_ptr_type)(&((unsigned char *)(void *)data)[offset])
+#define u8ptr(x) (uint8_t *)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT (sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye) \
+	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size) \
+	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes) \
+	(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes) (data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size) (data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)	((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)		((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)	(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)	((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)	((dword_ptr[0] >> 16) & 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)	(dword_ptr[1])
+
+#define BAD_RETURN(data_size)	(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)	((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)	(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)	\
+	(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)		\
+	((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)	(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data, ptr_type)	\
+	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+enum req_t {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+};
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif /* _SHARED_FIFO_H_ */
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..be33a81
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..2012f64
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,308 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	n = rte_eth_dev_get_reg_length(port_id);
+	if (n > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	n = rte_eth_dev_get_eeprom_length(port_id);
+	if (n > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_get_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	status = rte_eth_dev_get_reg_info(port_id, &reg_info);
+	if (status)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_get_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch (fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..dc234be
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,384 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to
+ * parameter attributes desribed by ethtool data structure,
+ * ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame
+ *	 configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..17ab4a3
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..f99af58
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,471 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES/(after_ts - before_ts))
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*8/(after_ts - before_ts))
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*64*8/(after_ts - before_ts))
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+}
+
+static uint32_t port_mask;
+static uint32_t vf_port_mask;
+static uint8_t num_of_ports;
+static int keep_traffic = 1;
+
+static inline int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1 << port_id)) > 0;
+}
+
+static inline int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports = reply_data[0];
+	port_mask = reply_data2[0];
+	vf_port_mask = reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0)
+				printf("setrlimit returned result = %d\n",
+					result);
+			else
+				printf("setrlimit succeed!!!\n");
+		} else
+			printf("default stack size is 0x%x\n",
+				(int)(rl.rlim_cur));
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id))
+		port_id = rand() & 0x1F;
+
+	return port_id;
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1)
+		keep_traffic = atoi(argv[1]);
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0)
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0)
+				netdev_net_set_rx_mode(port_id);
+			else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port");
+				printf(" #%d!!!\n", port_id);
+			} else
+				printf("\nPort #%d mac addr is %s\n",
+					port_id, mac_addr_str(mac_addr));
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s ",
+					drvinfo.driver, drvinfo.version);
+				printf("fw_version: %s bus_info=%s\n",
+					drvinfo.fw_version, drvinfo.bus_info);
+				printf("reg-size(bytes)=%d eeprom-size=%d\n",
+					drvinfo.regdump_len,
+					drvinfo.eedump_len);
+			}
+
+			count = netdev_ethtool_get_regs_len(port_id);
+			if (count <= 0) {
+				printf("There are no registers available from");
+				printf(" device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers ",
+					count);
+				printf("for dump\n");
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF,
+					sizeof(struct ethtool_regs));
+				count = netdev_ethtool_get_regs(port_id,
+					&regs, reply_data);
+				if (count) {
+					printf("failed to run");
+					printf(" ethtool_get_regs ");
+					printf("from port #%d (err=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x ",
+						int_ptr[0], int_ptr[10]);
+					printf("version=0x%x\n",
+						regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			count = 0;
+			if (!is_vf_port(port_id)) {
+				count = netdev_ethtool_get_eeprom_len(0);
+				if (count == 0) {
+					printf("fail to retrieve eeprom");
+					printf("count from port #%d\n",
+						port_id);
+				}
+			}
+
+			if (count) {
+				printf("eeprom size is %d bytes\n", count);
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				eeprom.magic = 0;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to read eeprom");
+					printf(" from port #%d\n",
+						port_id);
+				} else {
+					int i;
+					uint16_t *word = (uint16_t *)
+						((void *)reply_data);
+
+					printf("eeprom-magic: %x;",
+						eeprom.magic);
+					printf("eeprom data ...\n");
+					count = 80;
+					for (i = 0; i < (int)(eeprom.len
+						>> 1); i++) {
+						if (((i+1) % 16) == 0)
+							printf("\n");
+						printf("%4x ", word[i]);
+					}
+					printf("\n");
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (netdev_net_get_mac_addr(port_id,
+			to_mac_type(mac_addr)))
+			printf("Fail to get mac addr from port #%d!!!\n",
+				port_id);
+		else
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+
+		if (!netdev_net_validate_addr(port_id,
+			to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr,
+				MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n",
+				mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id,
+				to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id,
+				to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr");
+					printf(" @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign");
+				printf(" device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets,
+			last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets,
+			last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes,
+			last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes,
+			last_ts, ts));
+
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		int status;
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (!is_vf_port(port_id) && !link_up) {
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("failed to read eeprom");
+					printf(" break from post-run");
+					printf(" testing!!!\n");
+					break;
+				}
+				if (netdev_ethtool_set_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to write read-back");
+					printf(" data to eeprom!!!\n");
+					break;
+				}
+				/* checking mtu setting */
+				if (netdev_net_change_mtu(port_id, mtu)) {
+					printf("failed to set mtu");
+					printf("to %d\n", mtu);
+				}
+
+				/* add/remove vlan to vid */
+				status = netdev_net_vlan_rx_add_vid(
+					port_id, 0);
+				if (status == 0) {
+					status = netdev_net_vlan_rx_kill_vid(
+						port_id, 0);
+
+					if (status) {
+						printf("fail kill vlan-vid\n");
+						break;
+					}
+				} else {
+					printf("fail adding vlan/vid 0\n");
+					break;
+				}
+
+				/* testing pause parameter get/set functions */
+				status = netdev_ethtool_get_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("get pauseparam fail\n");
+					break;
+				}
+				printf("pause setup: autoneg: %d ",
+					pause_param.autoneg);
+				printf("tx_pause: %d ",
+					pause_param.tx_pause);
+				printf("rx_pause: %d\n",
+					pause_param.rx_pause);
+				status = netdev_ethtool_set_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("set pause param fail\n");
+					break;
+				}
+
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0)
+		;
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v16 0/6] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (13 preceding siblings ...)
  2015-07-14  2:18 ` [dpdk-dev] [PATCH v15 0/4] User-space Ethtool Liang-Min Larry Wang
@ 2015-07-14 13:11 ` Liang-Min Larry Wang
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 1/6] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (6 more replies)
  2015-07-16 13:25 ` [dpdk-dev] [PATCH v17 0/5] " Liang-Min Larry Wang
  15 siblings, 7 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14 13:11 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v16 changes:
- Re-do patch v15 and separate changes between v15 and v14 into patch files 005 and 006
v15 changes:
- Replace rte_eth_dev_is_valid_port with macro VALID_PORTID_OR_ERR_RET
- Fix VALID_PORTID_OR_ERR_RET issue (unused macro variable)
- Fix api version map (move from 2.0 to 2.1)
v14 changes:
- Add library path to fix top-level, $RTE_SDK, example/l2fwd-ethtool build
v13 changes:
- Rebase beause patch 1588
v12 changes:
- Update coding style to match latest change over rte_ethdev.c (by shemming@brocade.com)
v11 changes:
- Fixed a typo and clean coding style.
v10 changes:
- Merged const fix back to igb/ixgbe.
v9 changes:
- Fixed checkpatch errors.
v8 changes:
- Changed register tables to const.
v7 change:
- Remove rte_eth_dev_get_ringparam implementation
v6 change:
- Rebase to match new changes over librte_ether
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (6):
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool
  ethdev: change api name, version information and fix macro
  examples/l2fwd-ethtool: replace lib with new API name

 drivers/net/e1000/igb_ethdev.c                   |  175 ++++
 drivers/net/e1000/igb_regs.h                     |  223 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  178 +++-
 drivers/net/ixgbe/ixgbe_regs.h                   |  376 ++++++++
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   59 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_eth_dev_info.h              |   57 ++
 lib/librte_ether/rte_ethdev.c                    |   83 +-
 lib/librte_ether/rte_ethdev.h                    |  118 +++
 lib/librte_ether/rte_ether_version.map           |    6 +
 20 files changed, 4597 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v16 1/6] ethdev: add apis to support access device info
  2015-07-14 13:11 ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Liang-Min Larry Wang
@ 2015-07-14 13:11   ` Liang-Min Larry Wang
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 2/6] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14 13:11 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add two new apis: rte_eth_dev_default_mac_addr_set
and rte_eth_ethtool_dev_info to enable
reading device parameters (mac, register, eeprom,
pause, ring) based upon ethtool alike
data parameter sepcification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_eth_dev_info.h    |  57 ++++++++++++++++
 lib/librte_ether/rte_ethdev.c          |  84 +++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 118 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   6 ++
 5 files changed, 266 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..05209e9 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_eth_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_dev_info.h b/lib/librte_ether/rte_eth_dev_info.h
new file mode 100644
index 0000000..6848051
--- /dev/null
+++ b/lib/librte_ether/rte_eth_dev_info.h
@@ -0,0 +1,57 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_DEV_INFO_H_
+#define _RTE_ETH_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *buf; /**< Buffer for register */
+	uint32_t offset; /**< Offset for 1st register to fetch */
+	uint32_t leng; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *buf; /**< Buffer for eeprom */
+	uint32_t offset; /**< Offset for 1st eeprom location to access */
+	uint32_t leng; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device ID */
+};
+
+#endif /* _RTE_ETH_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index ddf3658..6423c3c 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2542,6 +2542,30 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	if (!rte_eth_dev_is_valid_port(port_id)) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
@@ -3377,3 +3401,63 @@ rte_eth_timesync_read_tx_timestamp(uint8_t port_id, struct timespec *timestamp)
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->timesync_read_tx_timestamp, -ENOTSUP);
 	return (*dev->dev_ops->timesync_read_tx_timestamp)(dev, timestamp);
 }
+
+int
+rte_eth_dev_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index d76bbb3..470c2b5 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_eth_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1255,6 +1256,24 @@ typedef int (*eth_timesync_read_tx_timestamp_t)(struct rte_eth_dev *dev,
 						struct timespec *timestamp);
 /**< @internal Function used to read a TX IEEE1588/802.1AS timestamp. */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1394,6 +1413,17 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -3021,6 +3051,21 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   M
+ *   - (-ENODEV) if *port* invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
@@ -3654,6 +3699,79 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 39baf11..290b206 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,6 +102,12 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_reg_length;
+	rte_eth_dev_reg_info;
+	rte_eth_dev_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
 
 	local: *;
 };
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v16 2/6] ixgbe: add ops to support ethtool ops
  2015-07-14 13:11 ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Liang-Min Larry Wang
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 1/6] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-07-14 13:11   ` Liang-Min Larry Wang
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 3/6] igb: " Liang-Min Larry Wang
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14 13:11 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 178 +++++++++++++++++-
 drivers/net/ixgbe/ixgbe_regs.h   | 376 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 552 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 8d68125..1fdc86d 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -187,6 +191,8 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev,
+					   struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -231,6 +237,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+					     struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -268,6 +276,19 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev,
+			    struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *regs);
 
 static int ixgbe_timesync_enable(struct rte_eth_dev *dev);
 static int ixgbe_timesync_disable(struct rte_eth_dev *dev);
@@ -375,6 +396,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -406,6 +428,11 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.timesync_disable     = ixgbe_timesync_disable,
 	.timesync_read_rx_timestamp = ixgbe_timesync_read_rx_timestamp,
 	.timesync_read_tx_timestamp = ixgbe_timesync_read_tx_timestamp,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -432,6 +459,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2928,6 +2958,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3785,6 +3823,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4525,8 +4571,8 @@ ixgbe_dev_addr_list_itr(__attribute__((unused)) struct ixgbe_hw *hw,
 
 static int
 ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
-			   struct ether_addr *mc_addr_set,
-			   uint32_t nb_mc_addr)
+			  struct ether_addr *mc_addr_set,
+			  uint32_t nb_mc_addr)
 {
 	struct ixgbe_hw *hw;
 	u8 *mc_addr_list;
@@ -4641,6 +4687,134 @@ ixgbe_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
 	return  0;
 }
 
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	while ((reg_group = reg_set[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = ixgbevf_regs[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	      struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = reg_set[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+				reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = ixgbevf_regs[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &regs_buff[count],
+						      reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size * 2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, leng, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + leng) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, leng, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..c7457a6
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,376 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static const struct reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_nvm[] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_interrupt[] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_interrupt[] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rx[] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_tx[] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_tx[] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_wakeup[] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_dcb[] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_mac[] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_diagnostic[] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static const struct reg_info *ixgbe_regs_others[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm, ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_others,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+static const struct reg_info *ixgbe_regs_mac_82598EB[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm,
+				ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_mac_82598EB,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+/* VF registers */
+static const struct reg_info *ixgbevf_regs[] = {
+				ixgbevf_regs_general,
+				ixgbevf_regs_interrupt,
+				ixgbevf_regs_rxdma,
+				ixgbevf_regs_tx,
+				NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++)
+		reg_buf[i] = IXGBE_READ_REG(hw,
+					reg->base_addr + i * reg->stride);
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+					  const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += ixgbe_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IXGBE_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v16 3/6] igb: add ops to support ethtool ops
  2015-07-14 13:11 ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Liang-Min Larry Wang
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 1/6] ethdev: add apis to support access device info Liang-Min Larry Wang
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 2/6] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-07-14 13:11   ` Liang-Min Larry Wang
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 4/6] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14 13:11 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 175 ++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 223 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 398 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index eb97218..c6d057f 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -137,6 +138,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -150,6 +153,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -201,6 +210,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -283,6 +300,7 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
@@ -293,6 +311,11 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.timesync_disable     = igb_timesync_disable,
 	.timesync_read_rx_timestamp = igb_timesync_read_rx_timestamp,
 	.timesync_read_tx_timestamp = igb_timesync_read_tx_timestamp,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -314,6 +337,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2133,6 +2159,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+				struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2367,6 +2401,17 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* index is not used by rar_set() */
+	hw->mac.ops.rar_set(hw, (void *)addr, 0);
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3778,6 +3823,136 @@ igb_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
 	return  0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igb_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igbvf_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igb_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *regs_buff = regs->buf;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->leng == 0) ||
+	    (regs->leng == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igbvf_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &regs_buff[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size * 2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, leng, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->buf;
+	int first, leng;
+
+	first = in_eeprom->offset >> 1;
+	leng = in_eeprom->leng >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + leng) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, leng, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..0b5e5e5
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,223 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+};
+
+static const struct reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_nvm[] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_interrupt[] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rx[] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_tx[] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_wakeup[] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_mac[] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info *igb_regs[] = {
+				igb_regs_general,
+				igb_regs_nvm,
+				igb_regs_interrupt,
+				igb_regs_fctl,
+				igb_regs_rxdma,
+				igb_regs_rx,
+				igb_regs_tx,
+				igb_regs_wakeup,
+				igb_regs_mac,
+				NULL};
+
+/* FIXME: reading igb_regs_interrupt results side-effect which doesn't
+ * work with VFIO; re-install igb_regs_interrupt once issue is resolved.
+ */
+static const struct reg_info *igbvf_regs[] = {
+				igb_regs_general,
+				igb_regs_rxdma,
+				igb_regs_tx,
+				NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw,
+				reg->base_addr + i * reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+		const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += igb_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IGB_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v16 4/6] examples: new example: l2fwd-ethtool
  2015-07-14 13:11 ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 3/6] igb: " Liang-Min Larry Wang
@ 2015-07-14 13:11   ` Liang-Min Larry Wang
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 5/6] ethdev: change api name, version information and fix macro Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14 13:11 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   60 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  769 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 11 files changed, 3384 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/Makefile b/examples/Makefile
index b4eddbd..cd1c4b0 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -50,6 +50,9 @@ DIRS-y += ip_reassembly
 DIRS-$(CONFIG_RTE_IP_FRAG) += ip_fragmentation
 DIRS-y += ipv4_multicast
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
+DIRS-y += l2fwd-ethtool/lib
+DIRS-y += l2fwd-ethtool/nic-control
+DIRS-y += l2fwd-ethtool/l2fwd-app
 DIRS-y += l2fwd
 DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
 DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..80d257e
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..fd0b9a7
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,60 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LIBDIRS += -L$(S)/../lib/l2fwd-ethtool/lib/$(RTE_TARGET)/lib
+LIBDIRS += -L$(S)/../lib/$(RTE_TARGET)/lib
+LIBDIRS += -L$(S)/../build/lib
+LDLIBS += $(LIBDIRS) -lrte_ethtool
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..19dd58c
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1066 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id) ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id) ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask;
+
+/* virtio setup enable */
+static int virtio_setup;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* default period is 10 seconds */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+	return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done(void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ----------------------------",
+			portid);
+		printf("\nPackets sent: %24"PRIu64, port_statistics[portid].tx);
+		printf("\nPackets received: %20"PRIu64,
+			port_statistics[portid].rx);
+		printf("\nPackets dropped: %21"PRIu64,
+			port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ===============================");
+	printf("\nTotal packets sent: %18"PRIu64, total_packets_tx);
+	printf("\nTotal packets received: %14"PRIu64, total_packets_rx);
+	printf("\nTotal packets dropped: %15"PRIu64, total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid = 0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+					US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+	if (virtio_setup) {
+		while (is_ipc_done() == 0)
+			usleep(50);
+	}
+
+	while (1) {
+		cur_tsc = rte_rdtsc();
+
+		/* TX burst queue drain */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >=
+				    (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id ==
+					    rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+		"  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+		"  -V : setting rx/tx mode to enable virtio\n"
+		"  -T PERIOD: statistics will be refreshed each PERIOD seconds",
+		prgname);
+	printf("(0 to disable, 10 default, 86400 maximum)\n");
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) *
+				1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+			virtio_setup = l2fwd_parse_virtio_setup(optarg);
+			if (virtio_setup) {
+				port_conf.rxmode.hw_vlan_strip = 0;
+				port_conf.rxmode.hw_vlan_extend = 0;
+			}
+			break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status) {
+					printf("Port %d Link Up - speed %u "
+						, (uint8_t)portid,
+						(unsigned)link.link_speed);
+					printf("Mbps - %s\n", (link.link_duplex
+						== ETH_LINK_FULL_DUPLEX) ?
+						("full-duplex") :
+						("half-duplex\n"));
+				} else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+	uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of */
+		/* rte_eth_promiscuous_enable to test */
+		/* rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data =
+				(struct rte_eth_dev_data *)dev->data;
+
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is", port_id);
+		printf(" %s", mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))
+				) {
+				if (rte_ethtool_net_set_mac_addr(port_id,
+					(void *)new_mac_addr) == 0) {
+					printf(", and re-assigned to ");
+					printf("%s\n",
+					mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		if (req_type != (enum req_t)ipc_begin)
+			proc_invalid(req_id);
+		else
+			break;
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		port_id = param1[0];
+
+		switch ((enum req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id,
+				first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(
+				port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0)
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			if (reg_count)
+				status = proc_ethtool_get_regs(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0)
+				eeprom_size = rte_ethtool_get_eeprom_len(
+				port_id);
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id,
+				first_param, param2);
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_get_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_set_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id,
+				req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id,
+				req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id,
+				req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type:");
+			printf(" %d\n", req_type);
+			break;
+		}
+		if (status < 0)
+			printf("Request type (=%d) failed\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+	init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		} else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+			lcore_queue_conf[rx_lcore_id].n_rx_port ==
+			l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id,
+			(unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n",
+				(unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"Cannot configure device: err=%d, port=%u\n",
+				ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					rte_eth_dev_socket_id(portid),
+					NULL,
+					l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+	cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+		"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..0964bea
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,769 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE 6
+#define quad_aligned_size(x) ((x & 0x7) ? ((x+7)&0x7) : x)
+
+#define size16(data_type) (uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED -1
+#define NETDEV_INVALID -1
+#define NETDEV_STATUS(data_size) (GOOD_RETURN(data_size) \
+				? 0 : NETDEV_INVALID)
+#define UNUSED(x) (void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close(fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	/* block on read if reply is not available */
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id)
+		return -1;
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs),
+		param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size))
+		return link_status;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int leng;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &leng, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return leng;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, words, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return valid;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t *param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else
+			*param2_size = 0;
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct ethtool_drvinfo);
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	reg_len = rte_ethtool_get_regs_len(port_id);
+	if (reg_len == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf))
+		data_size = STATUS_MASK;
+	else
+		data_size = rte_ethtool_get_regs_len(port_id)*sizeof(int);
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_leng;
+	uint16_t data_size;
+
+	eeprom_leng = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_leng == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &eeprom_leng);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(eeprom_ptr->len & ~1);
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = MAC_ADDR_SIZE;
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct rte_eth_stats);
+
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..82dd962
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,158 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE "/tmp/nic_request"
+#define REP_PIPE "/tmp/nic_reply"
+#define PAGE_SIZE (4*1024)
+#define STACK_SIZE (4*PAGE_SIZE)
+#define MAXI_DATA (1024*6)
+#define MAXI_PARA 1024
+#define STATUS_MASK 0x8000
+#define MULTIPLE_DATA_MASK 0x4000
+#define MAXI_REQ_TYPE 16
+#define FIRST_DATA_OFFSET 8
+#define to_ptr(new_ptr_type, data, offset) \
+	(new_ptr_type)(&((unsigned char *)(void *)data)[offset])
+#define u8ptr(x) (uint8_t *)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT (sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye) \
+	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size) \
+	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes) \
+	(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes) (data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size) (data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)	((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)		((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)	(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)	((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)	((dword_ptr[0] >> 16) & 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)	(dword_ptr[1])
+
+#define BAD_RETURN(data_size)	(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)	((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)	(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)	\
+	(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)		\
+	((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)	(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data, ptr_type)	\
+	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+enum req_t {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+};
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif /* _SHARED_FIFO_H_ */
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..be33a81
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..744cb0c
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,308 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	n = rte_eth_dev_reg_length(port_id);
+	if (n > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	n = rte_eth_dev_eeprom_length(port_id);
+	if (n > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.buf = buf;
+	reg_info.leng = 0;
+
+	status = rte_eth_dev_reg_info(port_id, &reg_info);
+	if (status)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.leng = eeprom->len;
+	eeprom_info.buf = words;
+
+	status = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch (fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..dc234be
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,384 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param buf
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to
+ * parameter attributes desribed by ethtool data structure,
+ * ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame
+ *	 configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..17ab4a3
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..f99af58
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,471 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES/(after_ts - before_ts))
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*8/(after_ts - before_ts))
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*64*8/(after_ts - before_ts))
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+}
+
+static uint32_t port_mask;
+static uint32_t vf_port_mask;
+static uint8_t num_of_ports;
+static int keep_traffic = 1;
+
+static inline int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1 << port_id)) > 0;
+}
+
+static inline int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports = reply_data[0];
+	port_mask = reply_data2[0];
+	vf_port_mask = reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0)
+				printf("setrlimit returned result = %d\n",
+					result);
+			else
+				printf("setrlimit succeed!!!\n");
+		} else
+			printf("default stack size is 0x%x\n",
+				(int)(rl.rlim_cur));
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id))
+		port_id = rand() & 0x1F;
+
+	return port_id;
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1)
+		keep_traffic = atoi(argv[1]);
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0)
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0)
+				netdev_net_set_rx_mode(port_id);
+			else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port");
+				printf(" #%d!!!\n", port_id);
+			} else
+				printf("\nPort #%d mac addr is %s\n",
+					port_id, mac_addr_str(mac_addr));
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s ",
+					drvinfo.driver, drvinfo.version);
+				printf("fw_version: %s bus_info=%s\n",
+					drvinfo.fw_version, drvinfo.bus_info);
+				printf("reg-size(bytes)=%d eeprom-size=%d\n",
+					drvinfo.regdump_len,
+					drvinfo.eedump_len);
+			}
+
+			count = netdev_ethtool_get_regs_len(port_id);
+			if (count <= 0) {
+				printf("There are no registers available from");
+				printf(" device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers ",
+					count);
+				printf("for dump\n");
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF,
+					sizeof(struct ethtool_regs));
+				count = netdev_ethtool_get_regs(port_id,
+					&regs, reply_data);
+				if (count) {
+					printf("failed to run");
+					printf(" ethtool_get_regs ");
+					printf("from port #%d (err=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x ",
+						int_ptr[0], int_ptr[10]);
+					printf("version=0x%x\n",
+						regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			count = 0;
+			if (!is_vf_port(port_id)) {
+				count = netdev_ethtool_get_eeprom_len(0);
+				if (count == 0) {
+					printf("fail to retrieve eeprom");
+					printf("count from port #%d\n",
+						port_id);
+				}
+			}
+
+			if (count) {
+				printf("eeprom size is %d bytes\n", count);
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				eeprom.magic = 0;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to read eeprom");
+					printf(" from port #%d\n",
+						port_id);
+				} else {
+					int i;
+					uint16_t *word = (uint16_t *)
+						((void *)reply_data);
+
+					printf("eeprom-magic: %x;",
+						eeprom.magic);
+					printf("eeprom data ...\n");
+					count = 80;
+					for (i = 0; i < (int)(eeprom.len
+						>> 1); i++) {
+						if (((i+1) % 16) == 0)
+							printf("\n");
+						printf("%4x ", word[i]);
+					}
+					printf("\n");
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (netdev_net_get_mac_addr(port_id,
+			to_mac_type(mac_addr)))
+			printf("Fail to get mac addr from port #%d!!!\n",
+				port_id);
+		else
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+
+		if (!netdev_net_validate_addr(port_id,
+			to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr,
+				MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n",
+				mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id,
+				to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id,
+				to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr");
+					printf(" @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign");
+				printf(" device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets,
+			last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets,
+			last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes,
+			last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes,
+			last_ts, ts));
+
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		int status;
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (!is_vf_port(port_id) && !link_up) {
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("failed to read eeprom");
+					printf(" break from post-run");
+					printf(" testing!!!\n");
+					break;
+				}
+				if (netdev_ethtool_set_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to write read-back");
+					printf(" data to eeprom!!!\n");
+					break;
+				}
+				/* checking mtu setting */
+				if (netdev_net_change_mtu(port_id, mtu)) {
+					printf("failed to set mtu");
+					printf("to %d\n", mtu);
+				}
+
+				/* add/remove vlan to vid */
+				status = netdev_net_vlan_rx_add_vid(
+					port_id, 0);
+				if (status == 0) {
+					status = netdev_net_vlan_rx_kill_vid(
+						port_id, 0);
+
+					if (status) {
+						printf("fail kill vlan-vid\n");
+						break;
+					}
+				} else {
+					printf("fail adding vlan/vid 0\n");
+					break;
+				}
+
+				/* testing pause parameter get/set functions */
+				status = netdev_ethtool_get_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("get pauseparam fail\n");
+					break;
+				}
+				printf("pause setup: autoneg: %d ",
+					pause_param.autoneg);
+				printf("tx_pause: %d ",
+					pause_param.tx_pause);
+				printf("rx_pause: %d\n",
+					pause_param.rx_pause);
+				status = netdev_ethtool_set_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("set pause param fail\n");
+					break;
+				}
+
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0)
+		;
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v16 5/6] ethdev: change api name, version information and fix macro
  2015-07-14 13:11 ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Liang-Min Larry Wang
                     ` (3 preceding siblings ...)
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 4/6] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
@ 2015-07-14 13:11   ` Liang-Min Larry Wang
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 6/6] examples/l2fwd-ethtool: replace lib with new API name Liang-Min Larry Wang
  2015-07-14 20:13   ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Thomas Monjalon
  6 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14 13:11 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

I. change api name with "get"
- rte_eth_dev_get_reg_length
- rte_eth_dev_get_reg_info
- rte_eth_dev_get_eeprom_length

II. fix unused variable in VALID_PORTID_OR_ERR_RET

III. use VALID_PORTID_OR_ERR_RET instead of rte_eth_dev_is_valid_port and

III. move new api name to version 2.1 list

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/rte_ethdev.c          | 13 +++++--------
 lib/librte_ether/rte_ethdev.h          |  6 +++---
 lib/librte_ether/rte_ether_version.map | 12 ++++++------
 3 files changed, 14 insertions(+), 17 deletions(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 6423c3c..c47b91f 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -111,7 +111,7 @@
 #define VALID_PORTID_OR_ERR_RET(port_id, retval) do {		\
 	if (!rte_eth_dev_is_valid_port(port_id)) {		\
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); \
-		return -EINVAL;					\
+		return retval;					\
 	}							\
 } while (0)
 
@@ -2546,10 +2546,7 @@ rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
 {
 	struct rte_eth_dev *dev;
 
-	if (!rte_eth_dev_is_valid_port(port_id)) {
-		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
-		return -ENODEV;
-	}
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 
 	if (!is_valid_assigned_ether_addr(addr))
 		return -EINVAL;
@@ -3403,7 +3400,7 @@ rte_eth_timesync_read_tx_timestamp(uint8_t port_id, struct timespec *timestamp)
 }
 
 int
-rte_eth_dev_reg_length(uint8_t port_id)
+rte_eth_dev_get_reg_length(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
@@ -3415,7 +3412,7 @@ rte_eth_dev_reg_length(uint8_t port_id)
 }
 
 int
-rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+rte_eth_dev_get_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
 {
 	struct rte_eth_dev *dev;
 
@@ -3427,7 +3424,7 @@ rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
 }
 
 int
-rte_eth_dev_eeprom_length(uint8_t port_id)
+rte_eth_dev_get_eeprom_length(uint8_t port_id)
 {
 	struct rte_eth_dev *dev;
 
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 470c2b5..cd4666d 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -3710,7 +3710,7 @@ int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
  *   - (-ENODEV) if *port_id* invalid.
  *   - others depends on the specific operations implementation.
  */
-int rte_eth_dev_reg_length(uint8_t port_id);
+int rte_eth_dev_get_reg_length(uint8_t port_id);
 
 /**
  * Retrieve device registers and register attributes
@@ -3725,7 +3725,7 @@ int rte_eth_dev_reg_length(uint8_t port_id);
  *   - (-ENODEV) if *port_id* invalid.
  *   - others depends on the specific operations implementation.
  */
-int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+int rte_eth_dev_get_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
 
 /**
  * Retrieve size of device EEPROM
@@ -3738,7 +3738,7 @@ int rte_eth_dev_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
  *   - (-ENODEV) if *port_id* invalid.
  *   - others depends on the specific operations implementation.
  */
-int rte_eth_dev_eeprom_length(uint8_t port_id);
+int rte_eth_dev_get_eeprom_length(uint8_t port_id);
 
 /**
  * Retrieve EEPROM and EEPROM attribute
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 290b206..72eacca 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -102,12 +102,6 @@ DPDK_2.0 {
 	rte_eth_tx_queue_setup;
 	rte_eth_xstats_get;
 	rte_eth_xstats_reset;
-	rte_eth_dev_default_mac_addr_set;
-	rte_eth_dev_reg_length;
-	rte_eth_dev_reg_info;
-	rte_eth_dev_eeprom_length;
-	rte_eth_dev_get_eeprom;
-	rte_eth_dev_set_eeprom;
 
 	local: *;
 };
@@ -120,5 +114,11 @@ DPDK_2.1 {
 	rte_eth_timesync_enable;
 	rte_eth_timesync_read_rx_timestamp;
 	rte_eth_timesync_read_tx_timestamp;
+	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_get_reg_length;
+	rte_eth_dev_get_reg_info;
+	rte_eth_dev_get_eeprom_length;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_set_eeprom;
 
 } DPDK_2.0;
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v16 6/6] examples/l2fwd-ethtool: replace lib with new API name
  2015-07-14 13:11 ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Liang-Min Larry Wang
                     ` (4 preceding siblings ...)
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 5/6] ethdev: change api name, version information and fix macro Liang-Min Larry Wang
@ 2015-07-14 13:11   ` Liang-Min Larry Wang
  2015-07-14 20:13   ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Thomas Monjalon
  6 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-14 13:11 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

I. Change lib/rte_ethtool.c with new API name (rte_eth_dev_get_reg_length,
rte_eth_dev_get_reg_info and rte_eth_dev_get_eeprom_length)

II. Change l2fwd-app/Makefile to adapt build directory change

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/l2fwd-ethtool/l2fwd-app/Makefile |  3 +--
 examples/l2fwd-ethtool/lib/rte_ethtool.c  | 10 +++++-----
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
index fd0b9a7..5f45a79 100644
--- a/examples/l2fwd-ethtool/l2fwd-app/Makefile
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -52,9 +52,8 @@ SRCS-y := main.c
 CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
 CFLAGS += $(WERROR_FLAGS)
 
-LIBDIRS += -L$(S)/../lib/l2fwd-ethtool/lib/$(RTE_TARGET)/lib
-LIBDIRS += -L$(S)/../lib/$(RTE_TARGET)/lib
 LIBDIRS += -L$(S)/../build/lib
+LIBDIRS += -L$(subst l2fwd-app,lib,$(RTE_OUTPUT))
 LDLIBS += $(LIBDIRS) -lrte_ethtool
 
 include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
index 744cb0c..2012f64 100644
--- a/examples/l2fwd-ethtool/lib/rte_ethtool.c
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -55,13 +55,13 @@ rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
 		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
 		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
 
-	n = rte_eth_dev_reg_length(port_id);
+	n = rte_eth_dev_get_reg_length(port_id);
 	if (n > 0)
 		drvinfo->regdump_len = n;
 	else
 		drvinfo->regdump_len = 0;
 
-	n = rte_eth_dev_eeprom_length(port_id);
+	n = rte_eth_dev_get_eeprom_length(port_id);
 	if (n > 0)
 		drvinfo->eedump_len = n;
 	else
@@ -76,7 +76,7 @@ rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
 int
 rte_ethtool_get_regs_len(uint8_t port_id)
 {
-	return rte_eth_dev_reg_length(port_id);
+	return rte_eth_dev_get_reg_length(port_id);
 }
 
 int
@@ -88,7 +88,7 @@ rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
 	reg_info.buf = buf;
 	reg_info.leng = 0;
 
-	status = rte_eth_dev_reg_info(port_id, &reg_info);
+	status = rte_eth_dev_get_reg_info(port_id, &reg_info);
 	if (status)
 		return status;
 	regs->version = reg_info.version;
@@ -108,7 +108,7 @@ rte_ethtool_get_link(uint8_t port_id)
 int
 rte_ethtool_get_eeprom_len(uint8_t port_id)
 {
-	return rte_eth_dev_eeprom_length(port_id);
+	return rte_eth_dev_get_eeprom_length(port_id);
 }
 
 int
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v16 0/6] User-space Ethtool
  2015-07-14 13:11 ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Liang-Min Larry Wang
                     ` (5 preceding siblings ...)
  2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 6/6] examples/l2fwd-ethtool: replace lib with new API name Liang-Min Larry Wang
@ 2015-07-14 20:13   ` Thomas Monjalon
  2015-07-14 20:56     ` Wang, Liang-min
  6 siblings, 1 reply; 174+ messages in thread
From: Thomas Monjalon @ 2015-07-14 20:13 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

2015-07-14 09:11, Liang-Min Larry Wang:
> v16 changes:
> - Re-do patch v15 and separate changes between v15 and v14 into patch files 005 and 006

No, you misunderstood the need.
You must merge your fixes in appropriate patches.
But you must separate the mac_addr_set feature in another patch as it is
not related to ethtool dumps.

You are winning the record of patch iterations :)

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v16 0/6] User-space Ethtool
  2015-07-14 20:13   ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Thomas Monjalon
@ 2015-07-14 20:56     ` Wang, Liang-min
  2015-07-15  5:53       ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-07-14 20:56 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Thomas,
	The mac_addr_set is needed for ethtool net-op as described in examples/ethtool-ethtool/lib/rte_ethtool.c (rte_ethtool_net_set/get_mac_addr). Could you use the v15 for the release?

Larry


> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Tuesday, July 14, 2015 4:14 PM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v16 0/6] User-space Ethtool
> 
> 2015-07-14 09:11, Liang-Min Larry Wang:
> > v16 changes:
> > - Re-do patch v15 and separate changes between v15 and v14 into patch
> files 005 and 006
> 
> No, you misunderstood the need.
> You must merge your fixes in appropriate patches.
> But you must separate the mac_addr_set feature in another patch as it is
> not related to ethtool dumps.
> 
> You are winning the record of patch iterations :)

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v16 0/6] User-space Ethtool
  2015-07-14 20:56     ` Wang, Liang-min
@ 2015-07-15  5:53       ` Thomas Monjalon
  2015-07-15 10:15         ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Thomas Monjalon @ 2015-07-15  5:53 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

2015-07-14 20:56, Wang, Liang-min:
> Thomas,
> 	The mac_addr_set is needed for ethtool net-op as described in
> 	examples/ethtool-ethtool/lib/rte_ethtool.c (rte_ethtool_net_set/get_mac_addr).

That's why it should be the first patch of this series.
You probably misread "another patch" which means different patch in same series.

> 	Could you use the v15 for the release?

No, there are more comments.


> > -----Original Message-----
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > Sent: Tuesday, July 14, 2015 4:14 PM
> > To: Wang, Liang-min
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH v16 0/6] User-space Ethtool
> > 
> > 2015-07-14 09:11, Liang-Min Larry Wang:
> > > v16 changes:
> > > - Re-do patch v15 and separate changes between v15 and v14 into patch
> > files 005 and 006
> > 
> > No, you misunderstood the need.
> > You must merge your fixes in appropriate patches.
> > But you must separate the mac_addr_set feature in another patch as it is
> > not related to ethtool dumps.
> > 
> > You are winning the record of patch iterations :)

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info
  2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-07-15  6:16     ` Thomas Monjalon
  2015-07-15 10:07       ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Thomas Monjalon @ 2015-07-15  6:16 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

2015-07-13 22:18, Liang-Min Larry Wang:
> --- a/lib/librte_ether/Makefile
> +++ b/lib/librte_ether/Makefile
> @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
>  SYMLINK-y-include += rte_ether.h
>  SYMLINK-y-include += rte_ethdev.h
>  SYMLINK-y-include += rte_eth_ctrl.h
> +SYMLINK-y-include += rte_eth_dev_info.h

This file is not related to ethernet so it could be named rte_dev_info.h


> +struct rte_dev_reg_info {
> +	void *buf; /**< Buffer for register */

Maybe data would be more accurate.

> +	uint32_t offset; /**< Offset for 1st register to fetch */

Please precise offset from which point?
Why offset is needed?

> +	uint32_t leng; /**< Number of registers to fetch */

2 more characters for free: length


> +struct rte_dev_eeprom_info {
> +	void *buf; /**< Buffer for eeprom */
> +	uint32_t offset; /**< Offset for 1st eeprom location to access */
> +	uint32_t leng; /**< Length of eeprom region to access */

Same as above for these 3 fields.

> +	uint32_t magic; /**< Device ID */

What means magic? Is it always a device id?


> --- a/lib/librte_ether/rte_ether_version.map
> +++ b/lib/librte_ether/rte_ether_version.map
> @@ -114,5 +114,11 @@ DPDK_2.1 {
>  	rte_eth_timesync_enable;
>  	rte_eth_timesync_read_rx_timestamp;
>  	rte_eth_timesync_read_tx_timestamp;
> +	rte_eth_dev_default_mac_addr_set;
> +	rte_eth_dev_reg_length;
> +	rte_eth_dev_reg_info;
> +	rte_eth_dev_eeprom_length;
> +	rte_eth_dev_get_eeprom;
> +	rte_eth_dev_set_eeprom;

It is not in alphabetical order.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info
  2015-07-15  6:16     ` Thomas Monjalon
@ 2015-07-15 10:07       ` Wang, Liang-min
  2015-07-15 10:27         ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-07-15 10:07 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, July 15, 2015 2:16 AM
> To: Wang, Liang-min
> Cc: dev@dpdk.org; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access
> device info
> 
> 2015-07-13 22:18, Liang-Min Larry Wang:
> > --- a/lib/librte_ether/Makefile
> > +++ b/lib/librte_ether/Makefile
> > @@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
> >  SYMLINK-y-include += rte_ether.h
> >  SYMLINK-y-include += rte_ethdev.h
> >  SYMLINK-y-include += rte_eth_ctrl.h
> > +SYMLINK-y-include += rte_eth_dev_info.h
> 
> This file is not related to ethernet so it could be named rte_dev_info.h
> 
> 
> > +struct rte_dev_reg_info {
> > +	void *buf; /**< Buffer for register */
> 
> Maybe data would be more accurate.
> 
> > +	uint32_t offset; /**< Offset for 1st register to fetch */
> 
> Please precise offset from which point?
> Why offset is needed?
> 
Is C always 0-base?
The offset is introduced because one of the review requesting to support partial register read, 
meaning reading single register or a set of registers.
As comment in my reply, this implementation only supports total register dump, 
but the data structure design allows future expansion to support this request.
> > +	uint32_t leng; /**< Number of registers to fetch */
> 
> 2 more characters for free: length
> 
> 
> > +struct rte_dev_eeprom_info {
> > +	void *buf; /**< Buffer for eeprom */
> > +	uint32_t offset; /**< Offset for 1st eeprom location to access */
> > +	uint32_t leng; /**< Length of eeprom region to access */
> 
> Same as above for these 3 fields.
> 
> > +	uint32_t magic; /**< Device ID */
> 
> What means magic? Is it always a device id?
This field is the same as defined in kernel ethtool data structure.
> 
> 
> > --- a/lib/librte_ether/rte_ether_version.map
> > +++ b/lib/librte_ether/rte_ether_version.map
> > @@ -114,5 +114,11 @@ DPDK_2.1 {
> >  	rte_eth_timesync_enable;
> >  	rte_eth_timesync_read_rx_timestamp;
> >  	rte_eth_timesync_read_tx_timestamp;
> > +	rte_eth_dev_default_mac_addr_set;
> > +	rte_eth_dev_reg_length;
> > +	rte_eth_dev_reg_info;
> > +	rte_eth_dev_eeprom_length;
> > +	rte_eth_dev_get_eeprom;
> > +	rte_eth_dev_set_eeprom;
> 
> It is not in alphabetical order.
Is there a document on such requirement?
I'm asking this question because different API's are added at different time.
Does this comment apply on relative order or absolute order meaning order relative to mainline code?

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v16 0/6] User-space Ethtool
  2015-07-15  5:53       ` Thomas Monjalon
@ 2015-07-15 10:15         ` Wang, Liang-min
  2015-07-15 10:30           ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-07-15 10:15 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, July 15, 2015 1:53 AM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v16 0/6] User-space Ethtool
> 
> 2015-07-14 20:56, Wang, Liang-min:
> > Thomas,
> > 	The mac_addr_set is needed for ethtool net-op as described in
> > 	examples/ethtool-ethtool/lib/rte_ethtool.c
> (rte_ethtool_net_set/get_mac_addr).
> 
> That's why it should be the first patch of this series.
> You probably misread "another patch" which means different patch in same
> series.
> 
That's why this API and rest of API's added into librte_ether are all prepared in the same patch: 001.
I'm confused on your comment here. Are you asking me to break the patch 001 into two patches in the same series?
Meaning 001 and 002, would that be more confusing?

> > 	Could you use the v15 for the release?
> 
> No, there are more comments.
> 
> 
> > > -----Original Message-----
> > > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > Sent: Tuesday, July 14, 2015 4:14 PM
> > > To: Wang, Liang-min
> > > Cc: dev@dpdk.org
> > > Subject: Re: [dpdk-dev] [PATCH v16 0/6] User-space Ethtool
> > >
> > > 2015-07-14 09:11, Liang-Min Larry Wang:
> > > > v16 changes:
> > > > - Re-do patch v15 and separate changes between v15 and v14 into
> patch
> > > files 005 and 006
> > >
> > > No, you misunderstood the need.
> > > You must merge your fixes in appropriate patches.
> > > But you must separate the mac_addr_set feature in another patch as it is
> > > not related to ethtool dumps.
> > >
> > > You are winning the record of patch iterations :)
> 

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info
  2015-07-15 10:07       ` Wang, Liang-min
@ 2015-07-15 10:27         ` Thomas Monjalon
  2015-07-15 10:48           ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Thomas Monjalon @ 2015-07-15 10:27 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

2015-07-15 10:07, Wang, Liang-min:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > Please precise offset from which point?
> > Why offset is needed?
> > 
> Is C always 0-base?
> The offset is introduced because one of the review requesting to support partial register read, 
> meaning reading single register or a set of registers.
> As comment in my reply, this implementation only supports total register dump, 
> but the data structure design allows future expansion to support this request.

OK, so the comment should be something like "Offset in register table"

> > What means magic? Is it always a device id?
> This field is the same as defined in kernel ethtool data structure.

Not an excellent argument :)
Actually you didn't answer.

> > > --- a/lib/librte_ether/rte_ether_version.map
> > > +++ b/lib/librte_ether/rte_ether_version.map
> > > @@ -114,5 +114,11 @@ DPDK_2.1 {
> > >  	rte_eth_timesync_enable;
> > >  	rte_eth_timesync_read_rx_timestamp;
> > >  	rte_eth_timesync_read_tx_timestamp;
> > > +	rte_eth_dev_default_mac_addr_set;
> > > +	rte_eth_dev_reg_length;
> > > +	rte_eth_dev_reg_info;
> > > +	rte_eth_dev_eeprom_length;
> > > +	rte_eth_dev_get_eeprom;
> > > +	rte_eth_dev_set_eeprom;
> > 
> > It is not in alphabetical order.
> Is there a document on such requirement?

No, only emails.
Every .map are alphabetically sorted. It's easier to check symbols.

> I'm asking this question because different API's are added at different time.
> Does this comment apply on relative order or absolute order meaning order relative to mainline code?

Relative to mainline. Conflicts are handled when applying.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v16 0/6] User-space Ethtool
  2015-07-15 10:15         ` Wang, Liang-min
@ 2015-07-15 10:30           ` Thomas Monjalon
  0 siblings, 0 replies; 174+ messages in thread
From: Thomas Monjalon @ 2015-07-15 10:30 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

2015-07-15 10:15, Wang, Liang-min:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > 2015-07-14 20:56, Wang, Liang-min:
> > > Thomas,
> > > 	The mac_addr_set is needed for ethtool net-op as described in
> > > 	examples/ethtool-ethtool/lib/rte_ethtool.c
> > (rte_ethtool_net_set/get_mac_addr).
> > 
> > That's why it should be the first patch of this series.
> > You probably misread "another patch" which means different patch in same
> > series.
> > 
> That's why this API and rest of API's added into librte_ether are all prepared in the same patch: 001.
> I'm confused on your comment here. Are you asking me to break the patch 001 into two patches in the same series?
> Meaning 001 and 002, would that be more confusing?

Yes exactly.
001: mac_addr_set
002: reg/eeprom
Thanks

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info
  2015-07-15 10:27         ` Thomas Monjalon
@ 2015-07-15 10:48           ` Wang, Liang-min
  2015-07-15 11:20             ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-07-15 10:48 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, July 15, 2015 6:27 AM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access
> device info
> 
> 2015-07-15 10:07, Wang, Liang-min:
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > Please precise offset from which point?
> > > Why offset is needed?
> > >
> > Is C always 0-base?
> > The offset is introduced because one of the review requesting to support
> partial register read,
> > meaning reading single register or a set of registers.
> > As comment in my reply, this implementation only supports total register
> dump,
> > but the data structure design allows future expansion to support this
> request.
> 
> OK, so the comment should be something like "Offset in register table"
> 
> > > What means magic? Is it always a device id?
> > This field is the same as defined in kernel ethtool data structure.
> 
> Not an excellent argument :)
> Actually you didn't answer.
> 
I could not speak for other devices. For igb and ixgbe, it's device id.
Based upon literature search, this field is used by device driver to provide extra information.
What would be your suggestion?

> > > > --- a/lib/librte_ether/rte_ether_version.map
> > > > +++ b/lib/librte_ether/rte_ether_version.map
> > > > @@ -114,5 +114,11 @@ DPDK_2.1 {
> > > >  	rte_eth_timesync_enable;
> > > >  	rte_eth_timesync_read_rx_timestamp;
> > > >  	rte_eth_timesync_read_tx_timestamp;
> > > > +	rte_eth_dev_default_mac_addr_set;
> > > > +	rte_eth_dev_reg_length;
> > > > +	rte_eth_dev_reg_info;
> > > > +	rte_eth_dev_eeprom_length;
> > > > +	rte_eth_dev_get_eeprom;
> > > > +	rte_eth_dev_set_eeprom;
> > >
> > > It is not in alphabetical order.
> > Is there a document on such requirement?
> 
> No, only emails.
> Every .map are alphabetically sorted. It's easier to check symbols.
> 
> > I'm asking this question because different API's are added at different
> time.
> > Does this comment apply on relative order or absolute order meaning
> order relative to mainline code?
> 
> Relative to mainline. Conflicts are handled when applying.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info
  2015-07-15 10:48           ` Wang, Liang-min
@ 2015-07-15 11:20             ` Thomas Monjalon
  2015-07-15 11:36               ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Thomas Monjalon @ 2015-07-15 11:20 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

2015-07-15 10:48, Wang, Liang-min:
> > > > What means magic? Is it always a device id?
> > > This field is the same as defined in kernel ethtool data structure.
> > 
> > Not an excellent argument :)
> > Actually you didn't answer.
> > 
> I could not speak for other devices. For igb and ixgbe, it's device id.
> Based upon literature search, this field is used by device driver to provide extra information.
> What would be your suggestion?

I don't have any suggestion.
You are defining a new API in DPDK, so our concern must be to check
that it will be easily understood by users and PMD developers.
If you don't really know what this field will be for, others won't know.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info
  2015-07-15 11:20             ` Thomas Monjalon
@ 2015-07-15 11:36               ` Wang, Liang-min
  2015-07-15 12:06                 ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-07-15 11:36 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, July 15, 2015 7:21 AM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access
> device info
> 
> 2015-07-15 10:48, Wang, Liang-min:
> > > > > What means magic? Is it always a device id?
> > > > This field is the same as defined in kernel ethtool data structure.
> > >
> > > Not an excellent argument :)
> > > Actually you didn't answer.
> > >
> > I could not speak for other devices. For igb and ixgbe, it's device id.
> > Based upon literature search, this field is used by device driver to provide
> extra information.
> > What would be your suggestion?
> 
> I don't have any suggestion.
> You are defining a new API in DPDK, so our concern must be to check
> that it will be easily understood by users and PMD developers.
> If you don't really know what this field will be for, others won't know.
No, I meant it's device driver dependent. 
If I keep the same naming convention following kernel ethtool defined,
and adding comment like "device-specific magic key, such as device-id".
Would that be acceptable from you?
This data structure is defined to be compatible with kernel ethtool API,
and magic key is device specific and known to ethtool API users.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info
  2015-07-15 11:36               ` Wang, Liang-min
@ 2015-07-15 12:06                 ` Thomas Monjalon
  0 siblings, 0 replies; 174+ messages in thread
From: Thomas Monjalon @ 2015-07-15 12:06 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

2015-07-15 11:36, Wang, Liang-min:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > 2015-07-15 10:48, Wang, Liang-min:
> > > > > > What means magic? Is it always a device id?
> > > > > This field is the same as defined in kernel ethtool data structure.
> > > >
> > > > Not an excellent argument :)
> > > > Actually you didn't answer.
> > > >
> > > I could not speak for other devices. For igb and ixgbe, it's device id.
> > > Based upon literature search, this field is used by device driver to provide
> > extra information.
> > > What would be your suggestion?
> > 
> > I don't have any suggestion.
> > You are defining a new API in DPDK, so our concern must be to check
> > that it will be easily understood by users and PMD developers.
> > If you don't really know what this field will be for, others won't know.
> No, I meant it's device driver dependent. 
> If I keep the same naming convention following kernel ethtool defined,
> and adding comment like "device-specific magic key, such as device-id".
> Would that be acceptable from you?

OK

> This data structure is defined to be compatible with kernel ethtool API,
> and magic key is device specific and known to ethtool API users.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v17 0/5] User-space Ethtool
  2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
                   ` (14 preceding siblings ...)
  2015-07-14 13:11 ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Liang-Min Larry Wang
@ 2015-07-16 13:25 ` Liang-Min Larry Wang
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 1/5] ethdev: add api to support setting default mac addr Liang-Min Larry Wang
                     ` (5 more replies)
  15 siblings, 6 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-16 13:25 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

v17 changes:
- Separate bug fix to a separate submission
- Separate rte_eth_dev_default_mac_addr_set implementation to a new patch file
- Change data structure names and comments
v16 changes:
- Re-do patch v15 and separate changes between v15 and v14 into patch files 005 and 006
v15 changes:
- Replace rte_eth_dev_is_valid_port with macro VALID_PORTID_OR_ERR_RET
- Fix VALID_PORTID_OR_ERR_RET issue (unused macro variable)
- Fix api version map (move from 2.0 to 2.1)
v14 changes:
- Add library path to fix top-level, $RTE_SDK, example/l2fwd-ethtool build
v13 changes:
- Rebase beause patch 1588
v12 changes:
- Update coding style to match latest change over rte_ethdev.c (by shemming@brocade.com)
v11 changes:
- Fixed a typo and clean coding style.
v10 changes:
- Merged const fix back to igb/ixgbe.
v9 changes:
- Fixed checkpatch errors.
v8 changes:
- Changed register tables to const.
v7 change:
- Remove rte_eth_dev_get_ringparam implementation
v6 change:
- Rebase to match new changes over librte_ether
v5 change:
- Change API name from 'leng' to 'length'
- Remove unused data structure rte_dev_vf_info
- Remove placeholder API rte_eth_dev_set_ringparam
- Clean up set_mac_addr implementation
v4 change:
- Add rte_eth_xxx apis and respective ops over igb and ixgbe
  to support ethtool and net device alike ops
- Add an example to demonstrate the use of ethtool library
v3 change:
- Fix a build issue
v2 change:
- Implement rte_eth_dev_default_mac_addr_set through dev_ops::mac_addr_set so it would support NIC devices other than ixgbe and igb

Liang-Min Larry Wang (5):
  ethdev: add api to support setting default mac addr
  ethdev: add apis to support access device info
  ixgbe: add ops to support ethtool ops
  igb: add ops to support ethtool ops
  examples: new example: l2fwd-ethtool

 drivers/net/e1000/igb_ethdev.c                   |  175 ++++
 drivers/net/e1000/igb_regs.h                     |  223 +++++
 drivers/net/ixgbe/ixgbe_ethdev.c                 |  178 +++-
 drivers/net/ixgbe/ixgbe_regs.h                   |  376 ++++++++
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   59 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  770 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 lib/librte_ether/Makefile                        |    1 +
 lib/librte_ether/rte_dev_info.h                  |   57 ++
 lib/librte_ether/rte_ethdev.c                    |   81 ++
 lib/librte_ether/rte_ethdev.h                    |  119 +++
 lib/librte_ether/rte_ether_version.map           |    6 +
 20 files changed, 4598 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/e1000/igb_regs.h
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c
 create mode 100644 lib/librte_ether/rte_dev_info.h

-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v17 1/5] ethdev: add api to support setting default mac addr
  2015-07-16 13:25 ` [dpdk-dev] [PATCH v17 0/5] " Liang-Min Larry Wang
@ 2015-07-16 13:25   ` Liang-Min Larry Wang
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 2/5] ethdev: add apis to support access device info Liang-Min Larry Wang
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-16 13:25 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add new api:
- rte_eth_dev_default_mac_addr_set

the new api, rte_eth_dev_default_mac_addr_set, uses the
existing dev_op, mac_addr_set, to enable setting mac
addr from ethdev level.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/rte_ethdev.c          | 21 +++++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 16 ++++++++++++++++
 lib/librte_ether/rte_ether_version.map |  1 +
 3 files changed, 38 insertions(+)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index ddf3658..a809718 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2542,6 +2542,27 @@ rte_eth_dev_mac_addr_remove(uint8_t port_id, struct ether_addr *addr)
 }
 
 int
+rte_eth_dev_default_mac_addr_set(uint8_t port_id, struct ether_addr *addr)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	if (!is_valid_assigned_ether_addr(addr))
+		return -EINVAL;
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->mac_addr_set, -ENOTSUP);
+
+	/* Update default address in NIC data structure */
+	ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+
+	(*dev->dev_ops->mac_addr_set)(dev, addr);
+
+	return 0;
+}
+
+int
 rte_eth_dev_set_vf_rxmode(uint8_t port_id,  uint16_t vf,
 				uint16_t rx_mode, uint8_t on)
 {
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index d76bbb3..57ad653 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -3021,6 +3021,22 @@ int rte_eth_dev_mac_addr_add(uint8_t port, struct ether_addr *mac_addr,
 int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
 
 /**
+ * Set the default MAC address.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param mac_addr
+ *   New default MAC address.
+ * @return
+ *   - (0) if successful, or *mac_addr* didn't exist.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port* invalid.
+ *   - (-EINVAL) if MAC address is invalid.
+ */
+int rte_eth_dev_default_mac_addr_set(uint8_t port, struct ether_addr *mac_addr);
+
+
+/**
  * Update Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
  *
  * @param port
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 39baf11..3c6cca8 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -109,6 +109,7 @@ DPDK_2.0 {
 DPDK_2.1 {
 	global:
 
+	rte_eth_dev_default_mac_addr_set;
 	rte_eth_dev_set_mc_addr_list;
 	rte_eth_timesync_disable;
 	rte_eth_timesync_enable;
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v17 2/5] ethdev: add apis to support access device info
  2015-07-16 13:25 ` [dpdk-dev] [PATCH v17 0/5] " Liang-Min Larry Wang
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 1/5] ethdev: add api to support setting default mac addr Liang-Min Larry Wang
@ 2015-07-16 13:25   ` Liang-Min Larry Wang
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 3/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-16 13:25 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add new apis:
- rte_eth_dev_get_reg_length
- rte_eth_dev_get_reg_info
- rte_eth_dev_get_eeprom_length
- rte_eth_dev_get_eeprom
- rte_eth_dev_set_eeprom

to enable reading device parameters (register and
eeprom) based upon ethtool alike
data parameter specification.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 lib/librte_ether/Makefile              |   1 +
 lib/librte_ether/rte_dev_info.h        |  57 ++++++++++++++++++
 lib/librte_ether/rte_ethdev.c          |  60 +++++++++++++++++++
 lib/librte_ether/rte_ethdev.h          | 103 +++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ether_version.map |   5 ++
 5 files changed, 226 insertions(+)
 create mode 100644 lib/librte_ether/rte_dev_info.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c0e5768..fc45a71 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -51,6 +51,7 @@ SRCS-y += rte_ethdev.c
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
+SYMLINK-y-include += rte_dev_info.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_dev_info.h b/lib/librte_ether/rte_dev_info.h
new file mode 100644
index 0000000..291bd4d
--- /dev/null
+++ b/lib/librte_ether/rte_dev_info.h
@@ -0,0 +1,57 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_DEV_INFO_H_
+#define _RTE_DEV_INFO_H_
+
+/*
+ * Placeholder for accessing device registers
+ */
+struct rte_dev_reg_info {
+	void *data; /**< Buffer for return registers */
+	uint32_t offset; /**< Start register table location for access */
+	uint32_t length; /**< Number of registers to fetch */
+	uint32_t version; /**< Device version */
+};
+
+/*
+ * Placeholder for accessing device eeprom
+ */
+struct rte_dev_eeprom_info {
+	void *data; /**< Buffer for return eeprom */
+	uint32_t offset; /**< Start eeprom address for access*/
+	uint32_t length; /**< Length of eeprom region to access */
+	uint32_t magic; /**< Device-specific key, such as device-id */
+};
+
+#endif /* _RTE_DEV_INFO_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index a809718..b5c81a7 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -3398,3 +3398,63 @@ rte_eth_timesync_read_tx_timestamp(uint8_t port_id, struct timespec *timestamp)
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->timesync_read_tx_timestamp, -ENOTSUP);
 	return (*dev->dev_ops->timesync_read_tx_timestamp)(dev, timestamp);
 }
+
+int
+rte_eth_dev_get_reg_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg_length, -ENOTSUP);
+	return (*dev->dev_ops->get_reg_length)(dev);
+}
+
+int
+rte_eth_dev_get_reg_info(uint8_t port_id, struct rte_dev_reg_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_reg, -ENOTSUP);
+	return (*dev->dev_ops->get_reg)(dev, info);
+}
+
+int
+rte_eth_dev_get_eeprom_length(uint8_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom_length, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom_length)(dev);
+}
+
+int
+rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->get_eeprom)(dev, info);
+}
+
+int
+rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info)
+{
+	struct rte_eth_dev *dev;
+
+	VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->set_eeprom, -ENOTSUP);
+	return (*dev->dev_ops->set_eeprom)(dev, info);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 57ad653..9b6a812 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_devargs.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
+#include "rte_dev_info.h"
 
 struct rte_mbuf;
 
@@ -1255,6 +1256,24 @@ typedef int (*eth_timesync_read_tx_timestamp_t)(struct rte_eth_dev *dev,
 						struct timespec *timestamp);
 /**< @internal Function used to read a TX IEEE1588/802.1AS timestamp. */
 
+typedef int (*eth_get_reg_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve device register count  */
+
+typedef int (*eth_get_reg_t)(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *info);
+/**< @internal Retrieve registers  */
+
+typedef int (*eth_get_eeprom_length_t)(struct rte_eth_dev *dev);
+/**< @internal Retrieve eeprom size  */
+
+typedef int (*eth_get_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Retrieve eeprom data  */
+
+typedef int (*eth_set_eeprom_t)(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *info);
+/**< @internal Program eeprom data  */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1394,6 +1413,17 @@ struct eth_dev_ops {
 	reta_update_t reta_update;
 	/** Query redirection table. */
 	reta_query_t reta_query;
+
+	eth_get_reg_length_t get_reg_length;
+	/**< Get # of registers */
+	eth_get_reg_t get_reg;
+	/**< Get registers */
+	eth_get_eeprom_length_t get_eeprom_length;
+	/**< Get eeprom length */
+	eth_get_eeprom_t get_eeprom;
+	/**< Get eeprom data */
+	eth_set_eeprom_t set_eeprom;
+	/**< Set eeprom */
   /* bypass control */
 #ifdef RTE_NIC_BYPASS
   bypass_init_t bypass_init;
@@ -3670,6 +3700,79 @@ int rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
 int rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
 		struct rte_eth_rxtx_callback *user_cb);
 
+/**
+ * Retrieve number of available registers for access
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) number of registers if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_reg_length(uint8_t port_id);
+
+/**
+ * Retrieve device registers and register attributes
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for register data and attribute to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_reg_info(uint8_t port_id, struct rte_dev_reg_info *info);
+
+/**
+ * Retrieve size of device EEPROM
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (>=0) EEPROM size if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom_length(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM and EEPROM attribute
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes buffer for return EEPROM data and
+ *   EEPROM attributes to be filled.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_get_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
+/**
+ * Program EEPROM with provided data
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param info
+ *   The template includes EEPROM data for programming and
+ *   EEPROM attributes to be filled
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_set_eeprom(uint8_t port_id, struct rte_dev_eeprom_info *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 3c6cca8..b7e4d56 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -110,6 +110,11 @@ DPDK_2.1 {
 	global:
 
 	rte_eth_dev_default_mac_addr_set;
+	rte_eth_dev_get_eeprom;
+	rte_eth_dev_get_eeprom_length;
+	rte_eth_dev_get_reg_info;
+	rte_eth_dev_get_reg_length;
+	rte_eth_dev_set_eeprom;
 	rte_eth_dev_set_mc_addr_list;
 	rte_eth_timesync_disable;
 	rte_eth_timesync_enable;
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v17 3/5] ixgbe: add ops to support ethtool ops
  2015-07-16 13:25 ` [dpdk-dev] [PATCH v17 0/5] " Liang-Min Larry Wang
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 1/5] ethdev: add api to support setting default mac addr Liang-Min Larry Wang
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 2/5] ethdev: add apis to support access device info Liang-Min Larry Wang
@ 2015-07-16 13:25   ` Liang-Min Larry Wang
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 4/5] igb: " Liang-Min Larry Wang
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-16 13:25 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c | 178 +++++++++++++++++-
 drivers/net/ixgbe/ixgbe_regs.h   | 376 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 552 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ixgbe/ixgbe_regs.h

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 8d68125..a76a3f8 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
@@ -187,6 +191,8 @@ static void ixgbe_dev_interrupt_delayed_handler(void *param);
 static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev,
+					   struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -231,6 +237,8 @@ static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev,
 				 struct ether_addr *mac_addr,
 				 uint32_t index, uint32_t pool);
 static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+					     struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 			struct rte_eth_syn_filter *filter,
 			bool add);
@@ -268,6 +276,19 @@ static int ixgbevf_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu);
 static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
 				      struct ether_addr *mc_addr_set,
 				      uint32_t nb_mc_addr);
+/* Ethtool op support */
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev,
+			    struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev,
+				struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev,
+				struct rte_dev_reg_info *regs);
 
 static int ixgbe_timesync_enable(struct rte_eth_dev *dev);
 static int ixgbe_timesync_disable(struct rte_eth_dev *dev);
@@ -375,6 +396,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
 	.mac_addr_add         = ixgbe_add_rar,
 	.mac_addr_remove      = ixgbe_remove_rar,
+	.mac_addr_set         = ixgbe_set_default_mac_addr,
 	.uc_hash_table_set    = ixgbe_uc_hash_table_set,
 	.uc_all_hash_table_set  = ixgbe_uc_all_hash_table_set,
 	.mirror_rule_set      = ixgbe_mirror_rule_set,
@@ -406,6 +428,11 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.timesync_disable     = ixgbe_timesync_disable,
 	.timesync_read_rx_timestamp = ixgbe_timesync_read_rx_timestamp,
 	.timesync_read_tx_timestamp = ixgbe_timesync_read_tx_timestamp,
+	.get_reg_length       = ixgbe_get_reg_length,
+	.get_reg              = ixgbe_get_regs,
+	.get_eeprom_length    = ixgbe_get_eeprom_length,
+	.get_eeprom           = ixgbe_get_eeprom,
+	.set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -432,6 +459,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
 	.mac_addr_add         = ixgbevf_add_mac_addr,
 	.mac_addr_remove      = ixgbevf_remove_mac_addr,
 	.set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+	.mac_addr_set         = ixgbevf_set_default_mac_addr,
+	.get_reg_length       = ixgbevf_get_reg_length,
+	.get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -2928,6 +2958,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
 	ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	ixgbe_remove_rar(dev, 0);
+
+	ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3785,6 +3823,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	}
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
 	if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
 		(type) != ixgbe_mac_X550)\
@@ -4525,8 +4571,8 @@ ixgbe_dev_addr_list_itr(__attribute__((unused)) struct ixgbe_hw *hw,
 
 static int
 ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
-			   struct ether_addr *mc_addr_set,
-			   uint32_t nb_mc_addr)
+			  struct ether_addr *mc_addr_set,
+			  uint32_t nb_mc_addr)
 {
 	struct ixgbe_hw *hw;
 	u8 *mc_addr_list;
@@ -4641,6 +4687,134 @@ ixgbe_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
 	return  0;
 }
 
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	while ((reg_group = reg_set[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbevf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = ixgbevf_regs[g_ind++]))
+		count += ixgbe_regs_group_count(reg_group);
+
+	return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+	      struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *data = regs->data;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+	const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+				    ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+	/* Support only full register dump */
+	if ((regs->length == 0) ||
+	    (regs->length == (uint32_t)ixgbe_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = reg_set[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &data[count],
+				reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *data = regs->data;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->length == 0) ||
+	    (regs->length == (uint32_t)ixgbevf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = ixgbevf_regs[g_ind++]))
+			count += ixgbe_read_regs_group(dev, &data[count],
+						      reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->eeprom.word_size * 2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->data;
+	int first, length;
+
+	first = in_eeprom->offset >> 1;
+	length = in_eeprom->length >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + length) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.read_buffer(hw, first, length, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	uint16_t *data = in_eeprom->data;
+	int first, length;
+
+	first = in_eeprom->offset >> 1;
+	length = in_eeprom->length >> 1;
+	if ((first >= hw->eeprom.word_size) ||
+	    ((first + length) >= hw->eeprom.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	return eeprom->ops.write_buffer(hw,  first, length, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
 	.type = PMD_PDEV,
 	.init = rte_ixgbe_pmd_init,
diff --git a/drivers/net/ixgbe/ixgbe_regs.h b/drivers/net/ixgbe/ixgbe_regs.h
new file mode 100644
index 0000000..c7457a6
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_regs.h
@@ -0,0 +1,376 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IXGBE_REGS_H_
+#define _IXGBE_REGS_H_
+
+#include "ixgbe_ethdev.h"
+
+struct ixgbe_hw;
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+} reg_info;
+
+static const struct reg_info ixgbe_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_CTRL_EXT, 1, 1, "IXGBE_CTRL_EXT"},
+	{IXGBE_ESDP, 1, 1, "IXGBE_ESDP"},
+	{IXGBE_EODSDP, 1, 1, "IXGBE_EODSDP"},
+	{IXGBE_LEDCTL, 1, 1, "IXGBE_LEDCTL"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_TCPTIMER, 1, 1, "IXGBE_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_general[] = {
+	{IXGBE_CTRL, 1, 1, "IXGBE_CTRL"},
+	{IXGBE_STATUS, 1, 1, "IXGBE_STATUS"},
+	{IXGBE_VFLINKS, 1, 1, "IXGBE_VFLINKS"},
+	{IXGBE_FRTIMER, 1, 1, "IXGBE_FRTIMER"},
+	{IXGBE_VFMAILBOX, 1, 1, "IXGBE_VFMAILBOX"},
+	{IXGBE_VFMBMEM, 16, 4, "IXGBE_VFMBMEM"},
+	{IXGBE_VFRXMEMWRAP, 1, 1, "IXGBE_VFRXMEMWRAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_nvm[] = {
+	{IXGBE_EEC, 1, 1, "IXGBE_EEC"},
+	{IXGBE_EERD, 1, 1, "IXGBE_EERD"},
+	{IXGBE_FLA, 1, 1, "IXGBE_FLA"},
+	{IXGBE_EEMNGCTL, 1, 1, "IXGBE_EEMNGCTL"},
+	{IXGBE_EEMNGDATA, 1, 1, "IXGBE_EEMNGDATA"},
+	{IXGBE_FLMNGCTL, 1, 1, "IXGBE_FLMNGCTL"},
+	{IXGBE_FLMNGDATA, 1, 1, "IXGBE_FLMNGDATA"},
+	{IXGBE_FLMNGCNT, 1, 1, "IXGBE_FLMNGCNT"},
+	{IXGBE_FLOP, 1, 1, "IXGBE_FLOP"},
+	{IXGBE_GRC,  1, 1, "IXGBE_GRC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_interrupt[] = {
+	{IXGBE_EICS, 1, 1, "IXGBE_EICS"},
+	{IXGBE_EIMS, 1, 1, "IXGBE_EIMS"},
+	{IXGBE_EIMC, 1, 1, "IXGBE_EIMC"},
+	{IXGBE_EIAC, 1, 1, "IXGBE_EIAC"},
+	{IXGBE_EIAM, 1, 1, "IXGBE_EIAM"},
+	{IXGBE_EITR(0), 24, 4, "IXGBE_EITR"},
+	{IXGBE_IVAR(0), 24, 4, "IXGBE_IVAR"},
+	{IXGBE_MSIXT, 1, 1, "IXGBE_MSIXT"},
+	{IXGBE_MSIXPBA, 1, 1, "IXGBE_MSIXPBA"},
+	{IXGBE_PBACL(0),  1, 4, "IXGBE_PBACL"},
+	{IXGBE_GPIE, 1, 1, ""},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_interrupt[] = {
+	{IXGBE_VTEICR, 1, 1, "IXGBE_VTEICR"},
+	{IXGBE_VTEICS, 1, 1, "IXGBE_VTEICS"},
+	{IXGBE_VTEIMS, 1, 1, "IXGBE_VTEIMS"},
+	{IXGBE_VTEIMC, 1, 1, "IXGBE_VTEIMC"},
+	{IXGBE_VTEIAM, 1, 1, "IXGBE_VTEIAM"},
+	{IXGBE_VTEITR(0), 2, 4, "IXGBE_VTEITR"},
+	{IXGBE_VTIVAR(0), 4, 4, "IXGBE_VTIVAR"},
+	{IXGBE_VTIVAR_MISC, 1, 1, "IXGBE_VTIVAR_MISC"},
+	{IXGBE_VTRSCINT(0), 2, 4, "IXGBE_VTRSCINT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_mac_82598EB[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL(0), 8, 8, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH(0), 8, 8, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_fctl_others[] = {
+	{IXGBE_PFCTOP, 1, 1, ""},
+	{IXGBE_FCTTV(0), 4, 4, ""},
+	{IXGBE_FCRTV, 1, 1, ""},
+	{IXGBE_TFCS, 1, 1, ""},
+	{IXGBE_FCRTL_82599(0), 8, 4, "IXGBE_FCRTL"},
+	{IXGBE_FCRTH_82599(0), 8, 4, "IXGBE_FCRTH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 64, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 64, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 64, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 64, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 64, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 64, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 16, 0x4, "IXGBE_SRRCTL"},
+	{IXGBE_DCA_RXCTRL(0), 16, 4, "IXGBE_DCA_RXCTRL"},
+	{IXGBE_RDRXCTL, 1, 1, "IXGBE_RDRXCTL"},
+	{IXGBE_RXPBSIZE(0), 8, 4, "IXGBE_RXPBSIZE"},
+	{IXGBE_RXCTRL, 1, 1, "IXGBE_RXCTRL"},
+	{IXGBE_DROPEN, 1, 1, "IXGBE_DROPEN"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_rxdma[] = {
+	{IXGBE_RDBAL(0), 8, 0x40, "IXGBE_RDBAL"},
+	{IXGBE_RDBAH(0), 8, 0x40, "IXGBE_RDBAH"},
+	{IXGBE_RDLEN(0), 8, 0x40, "IXGBE_RDLEN"},
+	{IXGBE_RDH(0), 8, 0x40, "IXGBE_RDH"},
+	{IXGBE_RDT(0), 8, 0x40, "IXGBE_RDT"},
+	{IXGBE_RXDCTL(0), 8, 0x40, "IXGBE_RXDCTL"},
+	{IXGBE_SRRCTL(0), 8, 0x40, "IXGBE_SRRCTL"},
+	{IXGBE_VFPSRTYPE, 1, 1,	"IXGBE_VFPSRTYPE"},
+	{IXGBE_VFRSCCTL(0), 8, 0x40, "IXGBE_VFRSCCTL"},
+	{IXGBE_PVFDCA_RXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_RXCTRL"},
+	{IXGBE_PVFDCA_TXCTRL(0), 8, 0x40, "IXGBE_PVFDCA_TXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_rx[] = {
+	{IXGBE_RXCSUM, 1, 1, "IXGBE_RXCSUM"},
+	{IXGBE_RFCTL, 1, 1, "IXGBE_RFCTL"},
+	{IXGBE_RAL(0), 16, 8, "IXGBE_RAL"},
+	{IXGBE_RAH(0), 16, 8, "IXGBE_RAH"},
+	{IXGBE_PSRTYPE(0), 1, 4, "IXGBE_PSRTYPE"},
+	{IXGBE_FCTRL, 1, 1, "IXGBE_FCTRL"},
+	{IXGBE_VLNCTRL, 1, 1, "IXGBE_VLNCTRL"},
+	{IXGBE_MCSTCTRL, 1, 1, "IXGBE_MCSTCTRL"},
+	{IXGBE_MRQC, 1, 1, "IXGBE_MRQC"},
+	{IXGBE_VMD_CTL, 1, 1, "IXGBE_VMD_CTL"},
+	{IXGBE_IMIR(0), 8, 4, "IXGBE_IMIR"},
+	{IXGBE_IMIREXT(0), 8, 4, "IXGBE_IMIREXT"},
+	{IXGBE_IMIRVP, 1, 1, "IXGBE_IMIRVP"},
+	{0, 0, 0, ""}
+};
+
+static struct reg_info ixgbe_regs_tx[] = {
+	{IXGBE_TDBAL(0), 32, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 32, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 32, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 32, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 32, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 32, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 32, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 32, 0x40, "IXGBE_TDWBAH"},
+	{IXGBE_DTXCTL, 1, 1, "IXGBE_DTXCTL"},
+	{IXGBE_DCA_TXCTRL(0), 16, 4, "IXGBE_DCA_TXCTRL"},
+	{IXGBE_TXPBSIZE(0), 8, 4, "IXGBE_TXPBSIZE"},
+	{IXGBE_MNGTXMAP, 1, 1, "IXGBE_MNGTXMAP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbevf_regs_tx[] = {
+	{IXGBE_TDBAL(0), 4, 0x40, "IXGBE_TDBAL"},
+	{IXGBE_TDBAH(0), 4, 0x40, "IXGBE_TDBAH"},
+	{IXGBE_TDLEN(0), 4, 0x40, "IXGBE_TDLEN"},
+	{IXGBE_TDH(0), 4, 0x40, "IXGBE_TDH"},
+	{IXGBE_TDT(0), 4, 0x40, "IXGBE_TDT"},
+	{IXGBE_TXDCTL(0), 4, 0x40, "IXGBE_TXDCTL"},
+	{IXGBE_TDWBAL(0), 4, 0x40, "IXGBE_TDWBAL"},
+	{IXGBE_TDWBAH(0), 4, 0x40, "IXGBE_TDWBAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_wakeup[] = {
+	{IXGBE_WUC, 1, 1, "IXGBE_WUC"},
+	{IXGBE_WUFC, 1, 1, "IXGBE_WUFC"},
+	{IXGBE_WUS, 1, 1, "IXGBE_WUS"},
+	{IXGBE_IPAV, 1, 1, "IXGBE_IPAV"},
+	{IXGBE_IP4AT, 1, 1, "IXGBE_IP4AT"},
+	{IXGBE_IP6AT, 1, 1, "IXGBE_IP6AT"},
+	{IXGBE_WUPL, 1, 1, "IXGBE_WUPL"},
+	{IXGBE_WUPM, 1, 1, "IXGBE_WUPM"},
+	{IXGBE_FHFT(0), 1, 1, "IXGBE_FHFT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_dcb[] = {
+	{IXGBE_RMCS, 1, 1, "IXGBE_RMCS"},
+	{IXGBE_DPMCS, 1, 1, "IXGBE_DPMCS"},
+	{IXGBE_PDPMCS, 1, 1, "IXGBE_PDPMCS"},
+	{IXGBE_RUPPBMR, 1, 1, "IXGBE_RUPPBMR"},
+	{IXGBE_RT2CR(0), 8, 4, "IXGBE_RT2CR"},
+	{IXGBE_RT2SR(0), 8, 4, "IXGBE_RT2SR"},
+	{IXGBE_TDTQ2TCCR(0), 8, 0x40, "IXGBE_TDTQ2TCCR"},
+	{IXGBE_TDTQ2TCSR(0), 8, 0x40, "IXGBE_TDTQ2TCSR"},
+	{IXGBE_TDPT2TCCR(0), 8, 4, "IXGBE_TDPT2TCCR"},
+	{IXGBE_TDPT2TCSR(0), 8, 4, "IXGBE_TDPT2TCSR"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_mac[] = {
+	{IXGBE_PCS1GCFIG, 1, 1, "IXGBE_PCS1GCFIG"},
+	{IXGBE_PCS1GLCTL, 1, 1, "IXGBE_PCS1GLCTL"},
+	{IXGBE_PCS1GLSTA, 1, 1, "IXGBE_PCS1GLSTA"},
+	{IXGBE_PCS1GDBG0, 1, 1, "IXGBE_PCS1GDBG0"},
+	{IXGBE_PCS1GDBG1, 1, 1, "IXGBE_PCS1GDBG1"},
+	{IXGBE_PCS1GANA, 1, 1, "IXGBE_PCS1GANA"},
+	{IXGBE_PCS1GANLP, 1, 1, "IXGBE_PCS1GANLP"},
+	{IXGBE_PCS1GANNP, 1, 1, "IXGBE_PCS1GANNP"},
+	{IXGBE_PCS1GANLPNP, 1, 1, "IXGBE_PCS1GANLPNP"},
+	{IXGBE_HLREG0, 1, 1, "IXGBE_HLREG0"},
+	{IXGBE_HLREG1, 1, 1, "IXGBE_HLREG1"},
+	{IXGBE_PAP, 1, 1, "IXGBE_PAP"},
+	{IXGBE_MACA, 1, 1, "IXGBE_MACA"},
+	{IXGBE_APAE, 1, 1, "IXGBE_APAE"},
+	{IXGBE_ARD, 1, 1, "IXGBE_ARD"},
+	{IXGBE_AIS, 1, 1, "IXGBE_AIS"},
+	{IXGBE_MSCA, 1, 1, "IXGBE_MSCA"},
+	{IXGBE_MSRWD, 1, 1, "IXGBE_MSRWD"},
+	{IXGBE_MLADD, 1, 1, "IXGBE_MLADD"},
+	{IXGBE_MHADD, 1, 1, "IXGBE_MHADD"},
+	{IXGBE_TREG, 1, 1, "IXGBE_TREG"},
+	{IXGBE_PCSS1, 1, 1, "IXGBE_PCSS1"},
+	{IXGBE_PCSS2, 1, 1, "IXGBE_PCSS2"},
+	{IXGBE_XPCSS, 1, 1, "IXGBE_XPCSS"},
+	{IXGBE_SERDESC, 1, 1, "IXGBE_SERDESC"},
+	{IXGBE_MACS, 1, 1, "IXGBE_MACS"},
+	{IXGBE_AUTOC, 1, 1, "IXGBE_AUTOC"},
+	{IXGBE_LINKS, 1, 1, "IXGBE_LINKS"},
+	{IXGBE_AUTOC2, 1, 1, "IXGBE_AUTOC2"},
+	{IXGBE_AUTOC3, 1, 1, "IXGBE_AUTOC3"},
+	{IXGBE_ANLP1, 1, 1, "IXGBE_ANLP1"},
+	{IXGBE_ANLP2, 1, 1, "IXGBE_ANLP2"},
+	{IXGBE_ATLASCTL, 1, 1, "IXGBE_ATLASCTL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info ixgbe_regs_diagnostic[] = {
+	{IXGBE_RDSTATCTL, 1, 1, "IXGBE_RDSTATCTL"},
+	{IXGBE_RDSTAT(0), 8, 4, "IXGBE_RDSTAT"},
+	{IXGBE_RDHMPN, 1, 1, "IXGBE_RDHMPN"},
+	{IXGBE_RIC_DW(0), 4, 4, "IXGBE_RIC_DW"},
+	{IXGBE_RDPROBE, 1, 1, "IXGBE_RDPROBE"},
+	{IXGBE_TDHMPN, 1, 1, "IXGBE_TDHMPN"},
+	{IXGBE_TIC_DW(0), 4, 4, "IXGBE_TIC_DW"},
+	{IXGBE_TDPROBE, 1, 1, "IXGBE_TDPROBE"},
+	{IXGBE_TXBUFCTRL, 1, 1, "IXGBE_TXBUFCTRL"},
+	{IXGBE_TXBUFDATA0, 1, 1, "IXGBE_TXBUFDATA0"},
+	{IXGBE_TXBUFDATA1, 1, 1, "IXGBE_TXBUFDATA1"},
+	{IXGBE_TXBUFDATA2, 1, 1, "IXGBE_TXBUFDATA2"},
+	{IXGBE_TXBUFDATA3, 1, 1, "IXGBE_TXBUFDATA3"},
+	{IXGBE_RXBUFCTRL, 1, 1, "IXGBE_RXBUFCTRL"},
+	{IXGBE_RXBUFDATA0, 1, 1, "IXGBE_RXBUFDATA0"},
+	{IXGBE_RXBUFDATA1, 1, 1, "IXGBE_RXBUFDATA1"},
+	{IXGBE_RXBUFDATA2, 1, 1, "IXGBE_RXBUFDATA2"},
+	{IXGBE_RXBUFDATA3, 1, 1, "IXGBE_RXBUFDATA3"},
+	{IXGBE_PCIE_DIAG(0), 8, 4, ""},
+	{IXGBE_RFVAL, 1, 1, "IXGBE_RFVAL"},
+	{IXGBE_MDFTC1, 1, 1, "IXGBE_MDFTC1"},
+	{IXGBE_MDFTC2, 1, 1, "IXGBE_MDFTC2"},
+	{IXGBE_MDFTFIFO1, 1, 1, "IXGBE_MDFTFIFO1"},
+	{IXGBE_MDFTFIFO2, 1, 1, "IXGBE_MDFTFIFO2"},
+	{IXGBE_MDFTS, 1, 1, "IXGBE_MDFTS"},
+	{IXGBE_PCIEECCCTL, 1, 1, "IXGBE_PCIEECCCTL"},
+	{IXGBE_PBTXECC, 1, 1, "IXGBE_PBTXECC"},
+	{IXGBE_PBRXECC, 1, 1, "IXGBE_PBRXECC"},
+	{IXGBE_MFLCN, 1, 1, "IXGBE_MFLCN"},
+	{0, 0, 0, ""},
+};
+
+/* PF registers */
+static const struct reg_info *ixgbe_regs_others[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm, ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_others,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+static const struct reg_info *ixgbe_regs_mac_82598EB[] = {
+				ixgbe_regs_general,
+				ixgbe_regs_nvm,
+				ixgbe_regs_interrupt,
+				ixgbe_regs_fctl_mac_82598EB,
+				ixgbe_regs_rxdma,
+				ixgbe_regs_rx,
+				ixgbe_regs_tx,
+				ixgbe_regs_wakeup,
+				ixgbe_regs_dcb,
+				ixgbe_regs_mac,
+				ixgbe_regs_diagnostic,
+				NULL};
+
+/* VF registers */
+static const struct reg_info *ixgbevf_regs[] = {
+				ixgbevf_regs_general,
+				ixgbevf_regs_interrupt,
+				ixgbevf_regs_rxdma,
+				ixgbevf_regs_tx,
+				NULL};
+
+static inline int
+ixgbe_read_regs(struct ixgbe_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++)
+		reg_buf[i] = IXGBE_READ_REG(hw,
+					reg->base_addr + i * reg->stride);
+	return reg->count;
+};
+
+static inline int
+ixgbe_regs_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+ixgbe_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+					  const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += ixgbe_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IXGBE_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v17 4/5] igb: add ops to support ethtool ops
  2015-07-16 13:25 ` [dpdk-dev] [PATCH v17 0/5] " Liang-Min Larry Wang
                     ` (2 preceding siblings ...)
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 3/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
@ 2015-07-16 13:25   ` Liang-Min Larry Wang
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 5/5] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
  2015-07-16 21:48   ` [dpdk-dev] [PATCH v17 0/5] User-space Ethtool Thomas Monjalon
  5 siblings, 0 replies; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-16 13:25 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

add function to support ethtool ops:
- set_mac_addr
- get_reg_length
- get_regs
- get_eeprom_length
- get_eeprom
- set_eeprom

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 drivers/net/e1000/igb_ethdev.c | 175 ++++++++++++++++++++++++++++++++
 drivers/net/e1000/igb_regs.h   | 223 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 398 insertions(+)
 create mode 100644 drivers/net/e1000/igb_regs.h

diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index eb97218..6a0c55c 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -55,6 +55,7 @@
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
+#include "igb_regs.h"
 
 /*
  * Default values for port configuration
@@ -137,6 +138,8 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev,
 		struct ether_addr *mac_addr,
 		uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
+static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -150,6 +153,12 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
+static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+		struct ether_addr *addr);
+static int igbvf_get_reg_length(struct rte_eth_dev *dev);
+static int igbvf_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -201,6 +210,14 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
 		     enum rte_filter_op filter_op,
 		     void *arg);
+static int eth_igb_get_reg_length(struct rte_eth_dev *dev);
+static int eth_igb_get_regs(struct rte_eth_dev *dev,
+		struct rte_dev_reg_info *regs);
+static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev);
+static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
+		struct rte_dev_eeprom_info *eeprom);
 
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
 				    struct ether_addr *mc_addr_set,
@@ -283,6 +300,7 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.flow_ctrl_set        = eth_igb_flow_ctrl_set,
 	.mac_addr_add         = eth_igb_rar_set,
 	.mac_addr_remove      = eth_igb_rar_clear,
+	.mac_addr_set         = eth_igb_default_mac_addr_set,
 	.reta_update          = eth_igb_rss_reta_update,
 	.reta_query           = eth_igb_rss_reta_query,
 	.rss_hash_update      = eth_igb_rss_hash_update,
@@ -293,6 +311,11 @@ static const struct eth_dev_ops eth_igb_ops = {
 	.timesync_disable     = igb_timesync_disable,
 	.timesync_read_rx_timestamp = igb_timesync_read_rx_timestamp,
 	.timesync_read_tx_timestamp = igb_timesync_read_tx_timestamp,
+	.get_reg_length       = eth_igb_get_reg_length,
+	.get_reg              = eth_igb_get_regs,
+	.get_eeprom_length    = eth_igb_get_eeprom_length,
+	.get_eeprom           = eth_igb_get_eeprom,
+	.set_eeprom           = eth_igb_set_eeprom,
 };
 
 /*
@@ -314,6 +337,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
 	.tx_queue_setup       = eth_igb_tx_queue_setup,
 	.tx_queue_release     = eth_igb_tx_queue_release,
 	.set_mc_addr_list     = eth_igb_set_mc_addr_list,
+	.mac_addr_set         = igbvf_default_mac_addr_set,
+	.get_reg_length       = igbvf_get_reg_length,
+	.get_reg              = igbvf_get_regs,
 };
 
 /**
@@ -2133,6 +2159,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
 	e1000_rar_set(hw, addr, index);
 }
 
+static void
+eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+				struct ether_addr *addr)
+{
+	eth_igb_rar_clear(dev, 0);
+
+	eth_igb_rar_set(dev, (void *)addr, 0, 0);
+}
 /*
  * Virtual Function operations
  */
@@ -2367,6 +2401,17 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static void
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct e1000_hw *hw =
+		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* index is not used by rar_set() */
+	hw->mac.ops.rar_set(hw, (void *)addr, 0);
+}
+
+
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 			struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -3778,6 +3823,136 @@ igb_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
 	return  0;
 }
 
+static int
+eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igb_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused)
+{
+	int count = 0;
+	int g_ind = 0;
+	const struct reg_info *reg_group;
+
+	while ((reg_group = igbvf_regs[g_ind++]))
+		count += igb_reg_group_count(reg_group);
+
+	return count;
+}
+
+static int
+eth_igb_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *data = regs->data;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->length == 0) ||
+	    (regs->length == (uint32_t)eth_igb_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igb_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &data[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+igbvf_get_regs(struct rte_eth_dev *dev,
+	struct rte_dev_reg_info *regs)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *data = regs->data;
+	int g_ind = 0;
+	int count = 0;
+	const struct reg_info *reg_group;
+
+	/* Support only full register dump */
+	if ((regs->length == 0) ||
+	    (regs->length == (uint32_t)igbvf_get_reg_length(dev))) {
+		regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+			hw->device_id;
+		while ((reg_group = igbvf_regs[g_ind++]))
+			count += igb_read_regs_group(dev, &data[count],
+							reg_group);
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
+
+static int
+eth_igb_get_eeprom_length(struct rte_eth_dev *dev)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	/* Return unit is byte count */
+	return hw->nvm.word_size * 2;
+}
+
+static int
+eth_igb_get_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->data;
+	int first, length;
+
+	first = in_eeprom->offset >> 1;
+	length = in_eeprom->length >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + length) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.read) == NULL)
+		return -ENOTSUP;
+
+	return nvm->ops.read(hw, first, length, data);
+}
+
+static int
+eth_igb_set_eeprom(struct rte_eth_dev *dev,
+	struct rte_dev_eeprom_info *in_eeprom)
+{
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	uint16_t *data = in_eeprom->data;
+	int first, length;
+
+	first = in_eeprom->offset >> 1;
+	length = in_eeprom->length >> 1;
+	if ((first >= hw->nvm.word_size) ||
+	    ((first + length) >= hw->nvm.word_size))
+		return -EINVAL;
+
+	in_eeprom->magic = (uint32_t)hw->vendor_id |
+		((uint32_t)hw->device_id << 16);
+
+	if ((nvm->ops.write) == NULL)
+		return -ENOTSUP;
+	return nvm->ops.write(hw,  first, length, data);
+}
+
 static struct rte_driver pmd_igb_drv = {
 	.type = PMD_PDEV,
 	.init = rte_igb_pmd_init,
diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h
new file mode 100644
index 0000000..0b5e5e5
--- /dev/null
+++ b/drivers/net/e1000/igb_regs.h
@@ -0,0 +1,223 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _IGB_REGS_H_
+#define _IGB_REGS_H_
+
+#include "e1000_ethdev.h"
+
+struct reg_info {
+	uint32_t base_addr;
+	uint32_t count;
+	uint32_t stride;
+	const char *name;
+};
+
+static const struct reg_info igb_regs_general[] = {
+	{E1000_CTRL, 1, 1, "E1000_CTRL"},
+	{E1000_STATUS, 1, 1, "E1000_STATUS"},
+	{E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"},
+	{E1000_MDIC, 1, 1, "E1000_MDIC"},
+	{E1000_SCTL, 1, 1, "E1000_SCTL"},
+	{E1000_CONNSW, 1, 1, "E1000_CONNSW"},
+	{E1000_VET, 1, 1, "E1000_VET"},
+	{E1000_LEDCTL, 1, 1, "E1000_LEDCTL"},
+	{E1000_PBA, 1, 1, "E1000_PBA"},
+	{E1000_PBS, 1, 1, "E1000_PBS"},
+	{E1000_FRTIMER, 1, 1, "E1000_FRTIMER"},
+	{E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_nvm[] = {
+	{E1000_EECD, 1, 1, "E1000_EECD"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_interrupt[] = {
+	{E1000_EICS, 1, 1, "E1000_EICS"},
+	{E1000_EIMS, 1, 1, "E1000_EIMS"},
+	{E1000_EIMC, 1, 1, "E1000_EIMC"},
+	{E1000_EIAC, 1, 1, "E1000_EIAC"},
+	{E1000_EIAM, 1, 1, "E1000_EIAM"},
+	{E1000_ICS, 1, 1, "E1000_ICS"},
+	{E1000_IMS, 1, 1, "E1000_IMS"},
+	{E1000_IMC, 1, 1, "E1000_IMC"},
+	{E1000_IAC, 1, 1, "E1000_IAC"},
+	{E1000_IAM,  1, 1, "E1000_IAM"},
+	{E1000_IMIRVP, 1, 1, "E1000_IMIRVP"},
+	{E1000_EITR(0), 10, 4, "E1000_EITR"},
+	{E1000_IMIR(0), 8, 4, "E1000_IMIR"},
+	{E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_fctl[] = {
+	{E1000_FCAL, 1, 1, "E1000_FCAL"},
+	{E1000_FCAH, 1, 1, "E1000_FCAH"},
+	{E1000_FCTTV, 1, 1, "E1000_FCTTV"},
+	{E1000_FCRTL, 1, 1, "E1000_FCRTL"},
+	{E1000_FCRTH, 1, 1, "E1000_FCRTH"},
+	{E1000_FCRTV, 1, 1, "E1000_FCRTV"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rxdma[] = {
+	{E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"},
+	{E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"},
+	{E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"},
+	{E1000_RDH(0), 4, 0x100, "E1000_RDH"},
+	{E1000_RDT(0), 4, 0x100, "E1000_RDT"},
+	{E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"},
+	{E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"},
+	{E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_rx[] = {
+	{E1000_RCTL, 1, 1, "E1000_RCTL"},
+	{E1000_RXCSUM, 1, 1, "E1000_RXCSUM"},
+	{E1000_RLPML, 1, 1, "E1000_RLPML"},
+	{E1000_RFCTL, 1, 1, "E1000_RFCTL"},
+	{E1000_MRQC, 1, 1, "E1000_MRQC"},
+	{E1000_VT_CTL, 1, 1, "E1000_VT_CTL"},
+	{E1000_RAL(0), 16, 8, "E1000_RAL"},
+	{E1000_RAH(0), 16, 8, "E1000_RAH"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_tx[] = {
+	{E1000_TCTL, 1, 1, "E1000_TCTL"},
+	{E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"},
+	{E1000_TIPG, 1, 1, "E1000_TIPG"},
+	{E1000_DTXCTL, 1, 1, "E1000_DTXCTL"},
+	{E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"},
+	{E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"},
+	{E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDH(0), 4, 0x100, "E1000_TDLEN"},
+	{E1000_TDT(0), 4, 0x100, "E1000_TDT"},
+	{E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"},
+	{E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"},
+	{E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"},
+	{E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"},
+	{E1000_TDFH, 1, 1, "E1000_TDFH"},
+	{E1000_TDFT, 1, 1, "E1000_TDFT"},
+	{E1000_TDFHS, 1, 1, "E1000_TDFHS"},
+	{E1000_TDFPC, 1, 1, "E1000_TDFPC"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_wakeup[] = {
+	{E1000_WUC, 1, 1, "E1000_WUC"},
+	{E1000_WUFC, 1, 1, "E1000_WUFC"},
+	{E1000_WUS, 1, 1, "E1000_WUS"},
+	{E1000_IPAV, 1, 1, "E1000_IPAV"},
+	{E1000_WUPL, 1, 1, "E1000_WUPL"},
+	{E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"},
+	{E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"},
+	{E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"},
+	{E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"},
+	{E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"},
+	{E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info igb_regs_mac[] = {
+	{E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"},
+	{E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"},
+	{E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"},
+	{E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"},
+	{E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"},
+	{E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"},
+	{E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"},
+	{0, 0, 0, ""}
+};
+
+static const struct reg_info *igb_regs[] = {
+				igb_regs_general,
+				igb_regs_nvm,
+				igb_regs_interrupt,
+				igb_regs_fctl,
+				igb_regs_rxdma,
+				igb_regs_rx,
+				igb_regs_tx,
+				igb_regs_wakeup,
+				igb_regs_mac,
+				NULL};
+
+/* FIXME: reading igb_regs_interrupt results side-effect which doesn't
+ * work with VFIO; re-install igb_regs_interrupt once issue is resolved.
+ */
+static const struct reg_info *igbvf_regs[] = {
+				igb_regs_general,
+				igb_regs_rxdma,
+				igb_regs_tx,
+				NULL};
+
+static inline int
+igb_read_regs(struct e1000_hw *hw, const struct reg_info *reg,
+	uint32_t *reg_buf)
+{
+	unsigned int i;
+
+	for (i = 0; i < reg->count; i++) {
+		reg_buf[i] = E1000_READ_REG(hw,
+				reg->base_addr + i * reg->stride);
+	}
+	return reg->count;
+};
+
+static inline int
+igb_reg_group_count(const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+
+	while (regs[i].count)
+		count += regs[i++].count;
+	return count;
+};
+
+static inline int
+igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf,
+		const struct reg_info *regs)
+{
+	int count = 0;
+	int i = 0;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	while (regs[i].count)
+		count += igb_read_regs(hw, &regs[i++], &reg_buf[count]);
+	return count;
+};
+
+#endif /* _IGB_REGS_H_ */
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH v17 5/5] examples: new example: l2fwd-ethtool
  2015-07-16 13:25 ` [dpdk-dev] [PATCH v17 0/5] " Liang-Min Larry Wang
                     ` (3 preceding siblings ...)
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 4/5] igb: " Liang-Min Larry Wang
@ 2015-07-16 13:25   ` Liang-Min Larry Wang
  2015-07-16 21:25     ` Thomas Monjalon
  2015-07-16 21:48   ` [dpdk-dev] [PATCH v17 0/5] User-space Ethtool Thomas Monjalon
  5 siblings, 1 reply; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-07-16 13:25 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

The example includes an ethtool library and two applications:
one application is a non- DPDK process (nic-control)
and the other is a DPDK l2fwd applicaiton (l2fwd-app).
The nic-control process sends ethtool alike device management
requests to l2fwd-app through a named pipe IPC. This example
is designed to show how to build a ethtool shim library and
how to use ethtool apis to manage device parameters.

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 examples/Makefile                                |    3 +
 examples/l2fwd-ethtool/Makefile                  |   55 ++
 examples/l2fwd-ethtool/l2fwd-app/Makefile        |   59 ++
 examples/l2fwd-ethtool/l2fwd-app/main.c          | 1066 ++++++++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h    |  770 ++++++++++++++++
 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h   |  158 ++++
 examples/l2fwd-ethtool/lib/Makefile              |   55 ++
 examples/l2fwd-ethtool/lib/rte_ethtool.c         |  308 +++++++
 examples/l2fwd-ethtool/lib/rte_ethtool.h         |  384 ++++++++
 examples/l2fwd-ethtool/nic-control/Makefile      |   55 ++
 examples/l2fwd-ethtool/nic-control/nic_control.c |  471 ++++++++++
 11 files changed, 3384 insertions(+)
 create mode 100644 examples/l2fwd-ethtool/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/Makefile
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/main.c
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
 create mode 100644 examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
 create mode 100644 examples/l2fwd-ethtool/lib/Makefile
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.c
 create mode 100644 examples/l2fwd-ethtool/lib/rte_ethtool.h
 create mode 100644 examples/l2fwd-ethtool/nic-control/Makefile
 create mode 100644 examples/l2fwd-ethtool/nic-control/nic_control.c

diff --git a/examples/Makefile b/examples/Makefile
index b4eddbd..cd1c4b0 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -50,6 +50,9 @@ DIRS-y += ip_reassembly
 DIRS-$(CONFIG_RTE_IP_FRAG) += ip_fragmentation
 DIRS-y += ipv4_multicast
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
+DIRS-y += l2fwd-ethtool/lib
+DIRS-y += l2fwd-ethtool/nic-control
+DIRS-y += l2fwd-ethtool/l2fwd-app
 DIRS-y += l2fwd
 DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
 DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
diff --git a/examples/l2fwd-ethtool/Makefile b/examples/l2fwd-ethtool/Makefile
new file mode 100644
index 0000000..80d257e
--- /dev/null
+++ b/examples/l2fwd-ethtool/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+DIRS-y += lib nic-control l2fwd-app
+
+.PHONY: all clean $(DIRS-y)
+
+all: $(DIRS-y)
+clean: $(DIRS-y)
+
+$(DIRS-y):
+	$(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
diff --git a/examples/l2fwd-ethtool/l2fwd-app/Makefile b/examples/l2fwd-ethtool/l2fwd-app/Makefile
new file mode 100644
index 0000000..5f45a79
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/Makefile
@@ -0,0 +1,59 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = l2fwd-app
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+LIBDIRS += -L$(S)/../build/lib
+LIBDIRS += -L$(subst l2fwd-app,lib,$(RTE_OUTPUT))
+LDLIBS += $(LIBDIRS) -lrte_ethtool
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/l2fwd-app/main.c b/examples/l2fwd-ethtool/l2fwd-app/main.c
new file mode 100644
index 0000000..19dd58c
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/main.c
@@ -0,0 +1,1066 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include "rte_ethtool.h"
+#define NETDEV_OP_REPLY 1
+#include "netdev_api.h"
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define is_vf_port(vf_mask, port_id) ((vf_mask & (1 << port_id)) > 0)
+#define is_port_enabled(port_mask, port_id) ((port_mask & (1 << port_id)) > 0)
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask;
+
+/* virtio setup enable */
+static int virtio_setup;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+static struct rte_eth_txconf tx_conf = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = 32,
+	.tx_rs_thresh = 32,
+	.txq_flags = 0xf00,
+};
+
+struct rte_mempool *l2fwd_pktmbuf_pool;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* default period is 10 seconds */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000;
+
+/* IPC done checking utility function */
+/* status of ipc completed */
+static rte_atomic64_t ipc_done;
+
+static inline void init_ipc_done(void)
+{
+	rte_atomic64_init(&ipc_done);
+}
+
+static inline int is_ipc_done(void)
+{
+	return rte_atomic64_read(&ipc_done) > 0;
+}
+
+static inline void set_ipc_done(void)
+{
+	rte_atomic64_inc(&ipc_done);
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ----------------------------",
+			portid);
+		printf("\nPackets sent: %24"PRIu64, port_statistics[portid].tx);
+		printf("\nPackets received: %20"PRIu64,
+			port_statistics[portid].rx);
+		printf("\nPackets dropped: %21"PRIu64,
+			port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ===============================");
+	printf("\nTotal packets sent: %18"PRIu64, total_packets_tx);
+	printf("\nTotal packets received: %14"PRIu64, total_packets_rx);
+	printf("\nTotal packets dropped: %15"PRIu64, total_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid = 0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+
+	dst_port = l2fwd_dst_ports[portid];
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/* 02:00:00:00:00:xx */
+	tmp = &eth->d_addr.addr_bytes[0];
+	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+	/* src addr */
+	ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+					US_PER_S * BURST_TX_DRAIN_US;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+	if (virtio_setup) {
+		while (is_ipc_done() == 0)
+			usleep(50);
+	}
+
+	while (1) {
+		cur_tsc = rte_rdtsc();
+
+		/* TX burst queue drain */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >=
+				    (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id ==
+					    rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+		"  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+		"  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+		"  -V : setting rx/tx mode to enable virtio\n"
+		"  -T PERIOD: statistics will be refreshed each PERIOD seconds",
+		prgname);
+	printf("(0 to disable, 10 default, 86400 maximum)\n");
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_virtio_setup(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:V:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) *
+				1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* virtio setup */
+		case 'V':
+			/* get option as the pf mac addr */
+			virtio_setup = l2fwd_parse_virtio_setup(optarg);
+			if (virtio_setup) {
+				port_conf.rxmode.hw_vlan_strip = 0;
+				port_conf.rxmode.hw_vlan_extend = 0;
+			}
+			break;
+
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status!!!");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status) {
+					printf("Port %d Link Up - speed %u "
+						, (uint8_t)portid,
+						(unsigned)link.link_speed);
+					printf("Mbps - %s\n", (link.link_duplex
+						== ETH_LINK_FULL_DUPLEX) ?
+						("full-duplex") :
+						("half-duplex\n"));
+				} else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+static int
+proc_ipc_begin(struct nic_info *info, uint16_t req_id, void *mac_ptr)
+{
+	struct ethtool_drvinfo drvinfo;
+	uint8_t mac_addr[MAC_ADDR_SIZE];
+	uint8_t param[4], port_id, num_of_ports = info->num_of_ports;
+	uint32_t param2[2];
+	uint8_t *new_mac_addr = mac_ptr;
+	int status;
+
+	param[0] = num_of_ports;
+	info->vf_port_mask = 0;
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		status = rte_ethtool_get_drvinfo(port_id, &drvinfo);
+		if (status) {
+			printf("get_drvinfo from port #%d fails\n", port_id);
+			return -1;
+		}
+		info->vf_port_mask |= (drvinfo.eedump_len == 0?1:0) << port_id;
+		rte_ethtool_net_stop(port_id);
+	}
+	param2[0] = info->port_mask;
+	param2[1] = info->vf_port_mask;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		rte_ethtool_net_open(port_id);
+		/* Using rte_ethtool_net_set_rx_mode instead of */
+		/* rte_eth_promiscuous_enable to test */
+		/* rte_ethtool_net_set_rx_mode */
+		if (!is_vf_port(info->vf_port_mask, port_id)) {
+			struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+			struct rte_eth_dev_data *dev_data =
+				(struct rte_eth_dev_data *)dev->data;
+
+			dev_data->promiscuous = 1;
+
+			rte_ethtool_net_set_rx_mode(port_id);
+		}
+		rte_ethtool_net_get_mac_addr(port_id, (void *)mac_addr);
+		printf("Port #%d init mac address is", port_id);
+		printf(" %s", mac_addr_str(mac_addr));
+
+		if (is_vf_port(info->vf_port_mask, port_id)) {
+			/* use new mac addr if the default addr is not valid */
+			if (!is_valid_assigned_ether_addr(to_mac_type(mac_addr))
+				) {
+				if (rte_ethtool_net_set_mac_addr(port_id,
+					(void *)new_mac_addr) == 0) {
+					printf(", and re-assigned to ");
+					printf("%s\n",
+					mac_addr_str(new_mac_addr));
+					new_mac_addr[MAC_ADDR_SIZE-1]++;
+				} else {
+					printf("\n");
+				}
+			}
+		} else {
+			printf("\n");
+		}
+	}
+
+	send_reply2(req_id, 1, param, (uint16_t)(sizeof(uint32_t)*2), param2);
+	return 0;
+}
+
+static inline void
+proc_no_action(uint16_t req_id)
+{
+	send_reply(req_id, 0, NULL);
+}
+
+static inline void
+proc_invalid(uint16_t req_id)
+{
+	send_reply(req_id, BAD_RETURN(0), NULL);
+}
+
+static void*
+ethtool(void *ctx)
+{
+	struct nic_info *info = ctx;
+	int keep_req = 1;
+	int reg_count, eeprom_size;
+	uint16_t req_id, param1_size, param2_size;
+	uint8_t req_type, port_id;
+	int status;
+	uint8_t param1[MAXI_PARA];
+	uint8_t param2[MAXI_PARA];
+	uint8_t reply1[MAXI_DATA];
+	void *first_param	= FIRST_PARAM(param1);
+
+	init_rep_pipe();
+	while (1) {
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		if (req_type != (enum req_t)ipc_begin)
+			proc_invalid(req_id);
+		else
+			break;
+	}
+	proc_ipc_begin(info, req_id, first_param);
+
+	set_ipc_done();
+	reg_count = eeprom_size = 0;
+
+	while (keep_req) {
+		status = NETDEV_INVALID;
+		read_request(&req_id, &req_type, &param1_size, param1,
+			&param2_size, param2);
+		port_id = param1[0];
+
+		switch ((enum req_t)req_type) {
+		case get_drvinfo:
+			status = proc_ethtool_get_drvinfo(port_id, req_id,
+				first_param);
+			break;
+
+		case get_regs_len:
+			status = reg_count = proc_ethtool_get_regs_len(
+				port_id, req_id);
+			break;
+
+		case get_regs:
+			if (reg_count == 0)
+				reg_count = rte_ethtool_get_regs_len(port_id);
+			if (reg_count)
+				status = proc_ethtool_get_regs(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case get_link:
+			status = proc_ethtool_get_link(port_id, req_id);
+			break;
+
+		case get_eeprom_len:
+			if (eeprom_size == 0)
+				eeprom_size = rte_ethtool_get_eeprom_len(
+				port_id);
+			status = proc_ethtool_get_eeprom_len(port_id, req_id);
+			break;
+
+		case get_eeprom:
+			status = proc_ethtool_get_eeprom(port_id, req_id,
+				first_param, reply1);
+			break;
+
+		case set_eeprom:
+			status = proc_ethtool_set_eeprom(port_id, req_id,
+				first_param, param2);
+			break;
+
+		case get_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_get_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("get_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case set_pauseparam:
+			{
+				struct ethtool_pauseparam *pause_param =
+					(void *)reply1;
+
+				status = proc_ethtool_set_pauseparam(port_id,
+					req_id, pause_param);
+
+				if (status != 0) {
+					printf("set_pauseparam return");
+					printf(" status %d\n", status);
+				}
+			}
+			break;
+
+		case dev_open:
+			status = proc_net_open(port_id, req_id);
+			break;
+
+		case dev_stop:
+			status = proc_net_stop(port_id, req_id);
+			break;
+
+		case set_rx_mode:
+			status = proc_net_set_rx_mode(port_id, req_id);
+			break;
+
+		case get_mac_addr:
+			status = proc_net_get_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_mac_addr:
+			status = proc_net_set_mac_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case validate_addr:
+			status = proc_net_validate_addr(port_id,
+				req_id, first_param);
+			break;
+
+		case set_config:
+			status = proc_net_set_config(port_id,
+				req_id, first_param);
+			break;
+
+		case change_mtu:
+			status = proc_net_change_mtu(port_id,
+				req_id, first_param);
+			break;
+
+		case get_stats64:
+			status = proc_net_get_stats64(port_id,
+				req_id, reply1);
+			break;
+
+		case vlan_rx_add_vid:
+			status = proc_net_vlan_rx_add_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case vlan_rx_kill_vid:
+			status = proc_net_vlan_rx_kill_vid(port_id,
+				req_id, first_param);
+			break;
+
+		case ipc_end:
+			keep_req = 0;
+			proc_no_action(req_id);
+			status = 0;
+			break;
+
+		default:
+			proc_invalid(req_id);
+			printf("unsupported service request type:");
+			printf(" %d\n", req_type);
+			break;
+		}
+		if (status < 0)
+			printf("Request type (=%d) failed\n", (int)req_type);
+		/* check if termination flag is set */
+	}
+	printf("IPC session is over\n");
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+
+	init_ipc_done();
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool =
+		rte_mempool_create("mbuf_pool", NB_MBUF,
+				   MBUF_SIZE, 32,
+				   sizeof(struct rte_pktmbuf_pool_private),
+				   rte_pktmbuf_pool_init, NULL,
+				   rte_pktmbuf_init, NULL,
+				   rte_socket_id(), 0);
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		if (nb_ports_in_mask % 2) {
+			l2fwd_dst_ports[portid] = last_port;
+			l2fwd_dst_ports[last_port] = portid;
+		} else
+			last_port = portid;
+
+		nb_ports_in_mask++;
+
+		rte_eth_dev_info_get(portid, &dev_info);
+	}
+	if (nb_ports_in_mask % 2) {
+		printf("Notice: odd number of ports in portmask.\n");
+		l2fwd_dst_ports[last_port] = last_port;
+	}
+
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+			lcore_queue_conf[rx_lcore_id].n_rx_port ==
+			l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id,
+			(unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n",
+				(unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"Cannot configure device: err=%d, port=%u\n",
+				ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					rte_eth_dev_socket_id(portid),
+					NULL,
+					l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		if (virtio_setup) {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid), &tx_conf);
+		} else {
+			ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		}
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE,
+			"rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+	}
+
+	/* create a ethtool proxy thread */
+	pthread_attr_t attr;
+	cpu_set_t cpus;
+	pthread_t ethtool_thread;
+	struct nic_info info;
+
+	/* set core affinity to core 1 */
+	CPU_ZERO(&cpus);
+	CPU_SET(2, &cpus);
+	pthread_attr_init(&attr);
+	pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpus);
+	/* Since the register size is more than 4K (1147*4) */
+	pthread_attr_setstacksize(&attr, 4*PAGE_SIZE);
+
+	info.num_of_ports = nb_ports;
+	info.port_mask = l2fwd_enabled_port_mask;
+	if (pthread_create(&ethtool_thread, NULL, &ethtool, &info)) {
+		rte_exit(EXIT_FAILURE,
+			"Fail to create a pthread for ethtool task!!!\n");
+	}
+	memset(&port_statistics, 0, sizeof(port_statistics));
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+		"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
new file mode 100644
index 0000000..6e9a7c6
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/netdev_api.h
@@ -0,0 +1,770 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETDEV_API_H_
+#define _NETDEV_API_H_
+
+#include <linux/ethtool.h>
+#include <string.h>
+#include "shared_fifo.h"
+
+#define MAC_ADDR_SIZE 6
+#define quad_aligned_size(x) ((x & 0x7) ? ((x+7)&0x7) : x)
+
+#define size16(data_type) (uint16_t)(sizeof(data_type))
+
+/* NETDEV_STATUS = 0 if successful */
+#define NETDEV_UNSUPPORTED -1
+#define NETDEV_INVALID -1
+#define NETDEV_STATUS(data_size) (GOOD_RETURN(data_size) \
+				? 0 : NETDEV_INVALID)
+#define UNUSED(x) (void)(x)
+
+#ifdef NETDEV_OP_REQUEST
+static uint16_t
+next_reqid(void) {
+	static uint16_t request_id;
+
+	return request_id++;
+}
+
+/*
+ * send request (with one or two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request(uint16_t req_id, uint8_t req_type, uint16_t param_size,
+	void *param_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 0, req_type);
+	req[1] = REQ_DWORD_HI(param_size, 0);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+	if (param_size)
+		write(fd, param_data, param_size);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send request (with more than two variables) to request-pipe
+ * (invoked by non- DPDK process)
+ */
+static int
+send_request2(uint16_t req_id, uint8_t req_type, uint16_t param1_size,
+	void *param1_data, int param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REQ_DWORD_LO(req_id, 1, req_type);
+	req[1] = REQ_DWORD_HI(param1_size, param2_size);
+
+	fd = open(REQ_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (param1_size)
+		write(fd, param1_data, param1_size);
+	if (param2_size)
+		write(fd, param2_data, param2_size);
+	close(fd);
+
+	return 0;
+}
+
+/* read return variables from the reply-pipe (invoked by non- DPDK process) */
+static int
+read_reply(uint16_t expected_id, uint16_t *byte_count, void *reply_data1,
+	void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+	uint16_t rx_id, data1_size;
+
+	/* block on read if reply is not available */
+	fd = open(REP_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*byte_count = REP_DATA1_COUNT(req);
+	rx_id = REP_ID(req);
+
+	if (!GOOD_RETURN(*byte_count)) {
+		close(fd);
+		return -1;
+	}
+	data1_size = BYTE_COUNT((*byte_count));
+	read(fd, reply_data1, data1_size);
+	if (MULTIPLE_DATA(*byte_count)) {
+		assert(reply_data2);
+		read(fd, reply_data2, REP_DATA2_COUNT(req));
+	}
+	close(fd);
+
+	if (expected_id != rx_id)
+		return -1;
+	return 0;
+}
+
+/* definition of netdev op request */
+
+static int
+netdev_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_drvinfo, 1, &port_id);
+	read_reply(req_id, &data_size, drvinfo, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int length;
+
+	send_request(req_id, get_regs_len, 1, &port_id);
+	read_reply(req_id, &data_size, &length, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return length;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *buf)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_regs)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), regs, sizeof(struct ethtool_regs));
+
+	send_request(req_id, get_regs, PARAM_SIZE(struct ethtool_regs),
+		param_data);
+	read_reply(req_id, &data_size, regs, buf);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_link(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int link_status;
+
+	send_request(req_id, get_link, 1, &port_id);
+	read_reply(req_id, &data_size, &link_status, NULL);
+	if (GOOD_RETURN(data_size))
+		return link_status;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	int length;
+
+	send_request(req_id, get_eeprom_len, 1, &port_id);
+	read_reply(req_id, &data_size, &length, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return length;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request(req_id, get_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data);
+	read_reply(req_id, &data_size, eeprom, words);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(struct ethtool_eeprom)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), eeprom, sizeof(struct ethtool_eeprom));
+
+	send_request2(req_id, set_eeprom, PARAM_SIZE(struct ethtool_eeprom),
+		param_data, eeprom->len, words);
+	read_reply(req_id, &data_size, eeprom, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_get_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_ethtool_set_pauseparam(uint8_t port_id, struct ethtool_pauseparam *param)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_pauseparam, 1, &port_id);
+	read_reply(req_id, &data_size, param, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_open(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_stop(uint8_t port_id) {
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, dev_open, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, set_rx_mode, 1, &port_id);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_mac_addr, 1, &port_id);
+	read_reply(req_id, &data_size, addr, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_set_mac_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, set_mac_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_validate_addr(uint8_t port_id, void *addr)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+	int valid;
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), addr, MAC_ADDR_SIZE);
+	send_request(req_id, validate_addr,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, &valid, NULL);
+
+	if (GOOD_RETURN(data_size))
+		return valid;
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_change_mtu(uint8_t port_id, int mtu)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &mtu, sizeof(int));
+	send_request(req_id, change_mtu, PARAM_SIZE(int), param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_get_stats64(uint8_t port_id, void *stats)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, get_stats64, 1, &port_id);
+	read_reply(req_id, &data_size, stats, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_add_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+static int
+netdev_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint8_t param_data[PARAM_SIZE(int)];
+
+	param_data[0] = port_id;
+	memcpy(FIRST_PARAM(param_data), &vid, sizeof(uint16_t));
+	send_request(req_id, vlan_rx_kill_vid, FIRST_DATA_OFFSET+sizeof(int),
+		param_data);
+	read_reply(req_id, &data_size, NULL, NULL);
+
+	return NETDEV_STATUS(data_size);
+};
+
+#endif /* NETDEV_OP_REQUEST */
+
+#ifdef NETDEV_OP_REPLY
+/* read request from request-pipe (invoked by rte-api server thread) */
+static int
+read_request(uint16_t *req_id, uint8_t *req_type, uint16_t *param1_size,
+	uint8_t *param1_data, uint16_t *param2_size, void *param2_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	/* block on read if request is not sent ... */
+	fd = open(REQ_PIPE, O_RDONLY);
+	read(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	*req_id			= REQ_ID(req);
+	*req_type		= REQ_TYPE(req);
+	*param1_size	= REQ_PARAM1_SIZE(req);
+
+	if (*param1_size > 0) {
+		read(fd, param1_data, *param1_size);
+		if (REQ_IDTYPE(req)) {
+			*param2_size = REQ_PARAM2_SIZE(req);
+			read(fd, param2_data, *param2_size);
+		} else
+			*param2_size = 0;
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* definition of netdev op service */
+/*
+ * rep[1:0]: request id
+ * rep[3:2]: data byte count; bit[15]: error status bit[14]: multiple return
+ *           variables are requested
+ *
+ * send reply with one return variable to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply(uint16_t rx_id, uint16_t byte_count, void *reply_data)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, byte_count);
+	req[1] = REP_DWORD_HI(0);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count) && (byte_count > 0))
+		write(fd, reply_data, byte_count);
+	close(fd);
+
+	return 0;
+}
+
+/*
+ * send reply with two or more variables to reply-pipe
+ * (invoked by rte-api server thread)
+ */
+static int
+send_reply2(uint16_t rx_id, uint16_t byte_count1, void *reply_data1,
+	uint16_t byte_count2, void *reply_data2)
+{
+	int fd;
+	uint32_t req[2];
+
+	req[0] = REP_DWORD_LO(rx_id, REP_MUTILPLE_DATA(byte_count1));
+	req[1] = REP_DWORD_HI(byte_count2);
+
+	fd = open(REP_PIPE, O_WRONLY);
+	write(fd, req, PIPE_CTL_BYTE_COUNT);
+
+	if (GOOD_RETURN(byte_count1)  && (byte_count2 > 0)) {
+		write(fd, reply_data1, byte_count1);
+		write(fd, reply_data2, byte_count2);
+	}
+	close(fd);
+
+	return 0;
+}
+
+/* Functions for netdev service thread */
+static int
+proc_ethtool_get_drvinfo(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	struct ethtool_drvinfo *drvinfo = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_drvinfo(port_id, drvinfo))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct ethtool_drvinfo);
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_ethtool_get_regs_len(uint8_t port_id, uint16_t req_id)
+{
+	int reg_len;
+	uint16_t data_size;
+
+	reg_len = rte_ethtool_get_regs_len(port_id);
+	if (reg_len == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &reg_len);
+};
+
+static int
+proc_ethtool_get_regs(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_regs *reg_info = param_data;
+	void *buf = reply_data2;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_regs(port_id, reg_info, buf))
+		data_size = STATUS_MASK;
+	else
+		data_size = sizeof(struct ethtool_regs);
+	return send_reply2(req_id, data_size, reg_info,
+		rte_ethtool_get_regs_len(port_id)*sizeof(int), reply_data2);
+};
+
+static int
+proc_ethtool_get_link(uint8_t port_id, uint16_t req_id)
+{
+	int link_status;
+
+	link_status = rte_ethtool_get_link(port_id);
+	return  send_reply(req_id, (uint16_t)sizeof(int), &link_status);
+};
+
+static int
+proc_ethtool_get_eeprom_len(uint8_t port_id, uint16_t req_id)
+{
+	int eeprom_length;
+	uint16_t data_size;
+
+	eeprom_length = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_length == 0)
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(int);
+	return send_reply(req_id, data_size, &eeprom_length);
+};
+
+static int
+proc_ethtool_get_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *reply_data2)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_get_eeprom(port_id, eeprom_ptr, reply_data2))
+		data_size = STATUS_MASK;
+	else
+		data_size = sizeof(struct ethtool_eeprom);
+	return send_reply2(req_id, data_size, eeprom_ptr,
+		eeprom_ptr->len & ~1, reply_data2);
+};
+
+static int
+proc_ethtool_set_eeprom(uint8_t port_id, uint16_t req_id, void *param_data,
+	void *param2_data)
+{
+	struct ethtool_eeprom *eeprom_ptr = param_data;
+	uint16_t data_size;
+
+	if (rte_ethtool_set_eeprom(port_id, eeprom_ptr, param2_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = sizeof(struct ethtool_eeprom);
+	return send_reply(req_id, data_size, eeprom_ptr);
+};
+
+static int
+proc_ethtool_get_pauseparam(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_get_pauseparam(port_id,
+		(struct ethtool_pauseparam *)reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_ethtool_set_pauseparam(uint8_t port_id, uint16_t req_id, void *set_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_set_pauseparam(port_id,
+		(struct ethtool_pauseparam *)set_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = (uint16_t)(sizeof(struct ethtool_pauseparam));
+	return send_reply(req_id, data_size, set_data);
+};
+
+static int
+proc_net_open(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_open(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_stop(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	rte_ethtool_net_stop(port_id);
+	data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_set_rx_mode(uint8_t port_id, uint16_t req_id)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_rx_mode(port_id))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = MAC_ADDR_SIZE;
+
+	return send_reply(req_id, data_size, param_data);
+};
+
+static int
+proc_net_set_mac_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_mac_addr(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_validate_addr(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	int status;
+
+	status = rte_ethtool_net_validate_addr(port_id, param_data);
+
+	return send_reply(req_id, (uint16_t)sizeof(int), &status);
+};
+
+static int
+proc_net_set_config(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_set_config(port_id, param_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_change_mtu(uint8_t port_id, uint16_t req_id, void *param_data)
+{
+	uint16_t data_size;
+	int mtu = *(int *)(param_data);
+
+	if (rte_ethtool_net_change_mtu(port_id, mtu))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_get_stats64(uint8_t port_id, uint16_t req_id, void *reply_data)
+{
+	uint16_t data_size;
+
+	if (rte_ethtool_net_get_stats64(port_id, reply_data))
+		data_size = STATUS_MASK;
+	else
+		data_size = size16(struct rte_eth_stats);
+
+	return send_reply(req_id, data_size, reply_data);
+};
+
+static int
+proc_net_vlan_rx_add_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_add_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+static int
+proc_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t req_id,
+	void *param_data)
+{
+	uint16_t data_size;
+	int *vid_ptr = (int *)param_data;
+
+	if (rte_ethtool_net_vlan_rx_kill_vid(port_id, *vid_ptr))
+		data_size = STATUS_MASK;
+	else
+		data_size = 0;
+
+	return send_reply(req_id, data_size, &data_size);
+};
+
+#endif /* NETDEV_OP_REPLY */
+#endif /* _NETDEV_API_H_ */
diff --git a/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
new file mode 100644
index 0000000..82dd962
--- /dev/null
+++ b/examples/l2fwd-ethtool/l2fwd-app/shared_fifo.h
@@ -0,0 +1,158 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHARED_FIFO_H_
+#define _SHARED_FIFO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define REQ_PIPE "/tmp/nic_request"
+#define REP_PIPE "/tmp/nic_reply"
+#define PAGE_SIZE (4*1024)
+#define STACK_SIZE (4*PAGE_SIZE)
+#define MAXI_DATA (1024*6)
+#define MAXI_PARA 1024
+#define STATUS_MASK 0x8000
+#define MULTIPLE_DATA_MASK 0x4000
+#define MAXI_REQ_TYPE 16
+#define FIRST_DATA_OFFSET 8
+#define to_ptr(new_ptr_type, data, offset) \
+	(new_ptr_type)(&((unsigned char *)(void *)data)[offset])
+#define u8ptr(x) (uint8_t *)((void *)x)
+
+
+/*
+ * req[1:0]:	request-id
+ * req[2]:		request-id type
+ * req[3]:		request type
+ * req[4:5]:	param1-size
+ * req[7:6]:	param2-size
+ *
+ * rep[1:0]		reply-id
+ * rep[3:2]:	data1-size	// bit[15]: status bit[14]: two return data
+ * rep[7:4]:	data2-size
+ */
+#define PIPE_CTL_BYTE_COUNT (sizeof(uint32_t)*2)
+#define REQ_DWORD_LO(req_id, id_type, req_tye) \
+	(((uint32_t)req_type << 24) | ((uint32_t)id_type << 16) | req_id)
+#define REQ_DWORD_HI(param1_size, param2_size) \
+	(((uint32_t)param2_size << 16) | param1_size)
+
+#define REP_DWORD_LO(rep_id, data_bytes) \
+	(((uint32_t)data_bytes << 16) | (uint32_t)rep_id)
+#define REP_DWORD_HI(data2_bytes) (data2_bytes)
+
+#define REP_MUTILPLE_DATA(data1_size) (data1_size | MULTIPLE_DATA_MASK)
+#define REQ_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REQ_IDTYPE(dword_ptr)	((dword_ptr[0] >> 16) & 0xFF)
+#define REQ_TYPE(dword_ptr)		((dword_ptr[0] >> 24) & 0xFF)
+#define REQ_PARAM1_SIZE(dword_ptr)	(dword_ptr[1] & 0xFFFF)
+#define REQ_PARAM2_SIZE(dword_ptr)	((dword_ptr[1]>>16) & 0xFFFF)
+#define REP_ID(dword_ptr)		(dword_ptr[0] & 0xFFFF)
+#define REP_DATA1_COUNT(dword_ptr)	((dword_ptr[0] >> 16) & 0xFFFF)
+#define REP_DATA2_COUNT(dword_ptr)	(dword_ptr[1])
+
+#define BAD_RETURN(data_size)	(data_size | STATUS_MASK)
+#define GOOD_RETURN(data_size)	((data_size & STATUS_MASK) == 0)
+#define MULTIPLE_DATA(data_size)	(data_size & MULTIPLE_DATA_MASK)
+#define BYTE_COUNT(data_size)	\
+	(data_size & ~(STATUS_MASK|MULTIPLE_DATA_MASK))
+
+#define PARAM_SIZE(type)		\
+	((uint16_t)(FIRST_DATA_OFFSET+sizeof(type)))
+#define FIRST_PARAM(param_data)	(void *)(&(param_data[FIRST_DATA_OFFSET]))
+#define FIRST_PARAM_TYPE(param_data, ptr_type)	\
+	(ptr_type)(FIRST_PARAM(param_data))
+
+void init_req_pipe(void);
+void init_rep_pipe(void);
+
+struct nic_info {
+	uint8_t num_of_ports;
+	uint32_t port_mask;
+	uint32_t vf_port_mask;
+	uint32_t flag;
+} nic_info;
+
+enum req_t {
+	get_drvinfo = 0,
+	get_setting,
+	set_setting,
+	get_regs_len,
+	get_regs,
+	get_link,
+	get_eeprom_len,
+	get_eeprom,
+	set_eeprom,
+	get_coalesce,
+	set_coalesce,
+	get_pauseparam,
+	set_pauseparam,
+	dump_data,
+
+	dev_open,
+	dev_stop,
+	set_rx_mode,
+	get_mac_addr,
+	set_mac_addr,
+	validate_addr,
+	set_config,
+	change_mtu,
+	get_stats64,
+	get_stats,
+	vlan_rx_add_vid,
+	vlan_rx_kill_vid,
+	ipc_begin,	/* request to start ipc, and get nic info ... */
+	ipc_end,	/* request to stop ipc ... */
+	invalid_req,
+};
+
+void
+init_req_pipe(void)
+{
+	mkfifo(REQ_PIPE, 0666);
+}
+
+void
+init_rep_pipe(void)
+{
+	mkfifo(REP_PIPE, 0666);
+}
+
+#endif /* _SHARED_FIFO_H_ */
diff --git a/examples/l2fwd-ethtool/lib/Makefile b/examples/l2fwd-ethtool/lib/Makefile
new file mode 100644
index 0000000..be33a81
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# library name
+LIB = librte_ethtool.a
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extlib.mk
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.c b/examples/l2fwd-ethtool/lib/rte_ethtool.c
new file mode 100644
index 0000000..4d4c2b6
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.c
@@ -0,0 +1,308 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	n = rte_eth_dev_get_reg_length(port_id);
+	if (n > 0)
+		drvinfo->regdump_len = n;
+	else
+		drvinfo->regdump_len = 0;
+
+	n = rte_eth_dev_get_eeprom_length(port_id);
+	if (n > 0)
+		drvinfo->eedump_len = n;
+	else
+		drvinfo->eedump_len = 0;
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_regs_len(uint8_t port_id)
+{
+	return rte_eth_dev_get_reg_length(port_id);
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *data)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	reg_info.data = data;
+	reg_info.length = 0;
+
+	status = rte_eth_dev_get_reg_info(port_id, &reg_info);
+	if (status)
+		return status;
+	regs->version = reg_info.version;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_get_eeprom_len(uint8_t port_id)
+{
+	return rte_eth_dev_get_eeprom_length(port_id);
+}
+
+int
+rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.length = eeprom->len;
+	eeprom_info.data = words;
+
+	status = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+	void *words)
+{
+	struct rte_dev_eeprom_info eeprom_info;
+	int status;
+
+	eeprom_info.offset = eeprom->offset;
+	eeprom_info.length = eeprom->len;
+	eeprom_info.data = words;
+
+	status = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+	if (status)
+		return status;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	pause_param->tx_pause = 0;
+	pause_param->rx_pause = 0;
+	switch (fc_conf.mode) {
+	case RTE_FC_NONE:
+		/* dummy block to avoid compiler warning */
+		break;
+	case RTE_FC_RX_PAUSE:
+		pause_param->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pause_param->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pause_param->rx_pause = 1;
+		pause_param->tx_pause = 1;
+	}
+	pause_param->autoneg = (uint32_t)fc_conf.autoneg;
+
+	return 0;
+}
+
+int
+rte_ethtool_set_pauseparam(uint8_t port_id,
+	struct ethtool_pauseparam *pause_param)
+{
+	struct rte_eth_fc_conf fc_conf;
+	int status;
+	/*
+	 * Read device flow control parameter first since
+	 * ethtool set_pauseparam op doesn't have all the information.
+	 * as defined in struct rte_eth_fc_conf.
+	 * This API requires the device to support both
+	 * rte_eth_dev_flow_ctrl_get and rte_eth_dev_flow_ctrl_set, otherwise
+	 * return -ENOTSUP
+	 */
+	status = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	fc_conf.autoneg = (uint8_t)pause_param->autoneg;
+
+	if (pause_param->tx_pause) {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pause_param->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	status = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/examples/l2fwd-ethtool/lib/rte_ethtool.h b/examples/l2fwd-ethtool/lib/rte_ethtool.h
new file mode 100644
index 0000000..b098be0
--- /dev/null
+++ b/examples/l2fwd-ethtool/lib/rte_ethtool.h
@@ -0,0 +1,384 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device register length in bytes.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (> 0) # of device registers (in bytes) available for dump
+ *   - (0) no registers available for dump.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs_len(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device register information according to attributes described by
+ * ethtool data structure, ethtool_regs
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param reg
+ *   A pointer to ethtool_regs that has register information
+ * @param data
+ *   A pointer to a buffer that is used to retrieve device register content
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *data);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Retrieve the Ethernet device EEPROM size
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *	 - (> 0) device EEPROM size in bytes
+ *   - (0) device has NO EEPROM
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom_len(uint8_t port_id);
+
+/**
+ * Retrieve EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data read from eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Setting EEPROM content based upon eeprom range described in ethtool
+ * data structure, ethtool_eeprom
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param eeprom
+ *	 The pointer of ethtool_eeprom that provides eeprom range
+ * @param words
+ *	 A buffer that holds data to be written into eeprom
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_eeprom(uint8_t port_id, struct ethtool_eeprom *eeprom,
+			      void *words);
+
+/**
+ * Retrieve the Ethernet device pause frame configuration according to
+ * parameter attributes desribed by ethtool data structure,
+ * ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets pause frame
+ *	 configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *pause_param);
+
+/**
+ * Setting the Ethernet device pause frame configuration according to parameter attributes
+ * desribed by ethtool data structure, ethtool_pauseparam.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param pause_param
+ *	 The pointer of ethtool_coalesce that gets ring configuration parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_set_pauseparam(uint8_t port_id,
+				   struct ethtool_pauseparam *param);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/l2fwd-ethtool/nic-control/Makefile b/examples/l2fwd-ethtool/nic-control/Makefile
new file mode 100644
index 0000000..17ab4a3
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/Makefile
@@ -0,0 +1,55 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overwritten by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = nic-control
+
+# all source are stored in SRCS-y
+SRCS-y := nic_control.c
+
+CFLAGS += -O3 -I$(SRCDIR)/../l2fwd-app -I$(SRCDIR)/../lib
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-ethtool/nic-control/nic_control.c b/examples/l2fwd-ethtool/nic-control/nic_control.c
new file mode 100644
index 0000000..f99af58
--- /dev/null
+++ b/examples/l2fwd-ethtool/nic-control/nic_control.c
@@ -0,0 +1,471 @@
+/*-
+*   BSD LICENSE
+*
+*   Copyright(c) 2015 Intel Corporation. All rights reserved.
+*   All rights reserved.
+*
+*   Redistribution and use in source and binary forms, with or without
+*   modification, are permitted provided that the following conditions
+*   are met:
+*
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in
+*       the documentation and/or other materials provided with the
+*       distribution.
+*     * Neither the name of Intel Corporation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+*   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+*   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+*   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+*   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+*   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+*   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+*   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This is a non- DPDK application that sends NIC device management request
+ * through named pipe to a DPDK data plan process.
+ *
+ */
+#define USE_NEW_TYPE
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+#include "rte_ethtool.h"
+#define NETDEV_OP_REQUEST 1
+#include "netdev_api.h"
+
+#define PACKET_THD	100000000
+#define ITER_LIMIT	30
+#define STOP_TIME	10 /* in seconds */
+#define CPU_CYCLES	(double)(2400.0*1000000)
+
+#define PACKET_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES/(after_ts - before_ts))
+
+#define BYTE2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*8/(after_ts - before_ts))
+
+#define PACKET2BIT_RATE(before_value, after_value, before_ts, after_ts) \
+	((double)(after_value - before_value) * \
+	CPU_CYCLES*64*8/(after_ts - before_ts))
+
+#define to_mac_type(x) (struct ether_addr *)(void *)(x)
+
+struct __time_stamp {
+	uint32_t hi;
+	uint32_t lo;
+} time_stamp;
+
+static inline unsigned long long
+rdtsc(void)
+{
+	unsigned hi, lo;
+
+	__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+	return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+}
+
+static uint32_t port_mask;
+static uint32_t vf_port_mask;
+static uint8_t num_of_ports;
+static int keep_traffic = 1;
+
+static inline int
+is_port_enabled(uint8_t port_id)
+{
+	return (port_mask & (1 << port_id)) > 0;
+}
+
+static inline int
+is_vf_port(uint8_t port_id)
+{
+	return (vf_port_mask & (1 << port_id)) > 0;
+}
+
+static int
+netdev_ipc_begin(unsigned char *mac_addr)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+	uint32_t reply_data2[2];
+	uint8_t param_data[FIRST_DATA_OFFSET+MAC_ADDR_SIZE];
+
+	param_data[0] = 0;
+	memcpy(FIRST_PARAM(param_data), mac_addr, MAC_ADDR_SIZE);
+	send_request(req_id, ipc_begin,
+		(FIRST_DATA_OFFSET+MAC_ADDR_SIZE), param_data);
+	read_reply(req_id, &data_size, reply_data, reply_data2);
+	num_of_ports = reply_data[0];
+	port_mask = reply_data2[0];
+	vf_port_mask = reply_data2[1];
+	return reply_data[0];
+}
+
+static int
+netdev_ipc_end(void)
+{
+	uint8_t reply_data[sizeof(double)];
+	uint16_t req_id = next_reqid();
+	uint16_t data_size;
+
+	send_request(req_id, ipc_end, 0, NULL);
+	read_reply(req_id, &data_size, reply_data, NULL);
+
+	return NETDEV_STATUS(data_size);
+}
+
+static void
+set_stacksize(void)
+{
+	struct rlimit rl;
+	int result;
+
+	result = getrlimit(RLIMIT_STACK, &rl);
+	if (result == 0) {
+		if (rl.rlim_cur < (const rlim_t)STACK_SIZE) {
+			rl.rlim_cur = STACK_SIZE;
+			result = setrlimit(RLIMIT_STACK, &rl);
+			if (result != 0)
+				printf("setrlimit returned result = %d\n",
+					result);
+			else
+				printf("setrlimit succeed!!!\n");
+		} else
+			printf("default stack size is 0x%x\n",
+				(int)(rl.rlim_cur));
+	}
+}
+
+static uint8_t
+get_port(void)
+{
+	uint8_t port_id;
+	/* assume maximum of 32 ports */
+	port_id = rand() & 0x1F;
+	while (!is_port_enabled(port_id))
+		port_id = rand() & 0x1F;
+
+	return port_id;
+}
+
+static inline char*
+mac_addr_str(unsigned char *mac_addr)
+{
+#define MAC_STR_SIZE (3*MAC_ADDR_SIZE+1)
+	static char addr_string[MAC_STR_SIZE];
+
+	snprintf(addr_string, MAC_STR_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+	return addr_string;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs regs;
+	struct ethtool_pauseparam pause_param;
+	struct ethtool_eeprom eeprom;
+
+	int8_t reply_data[MAXI_DATA] __attribute__((aligned(8)));
+	uint8_t mac_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 0};
+	uint8_t mac_base_addr[MAC_ADDR_SIZE] = {0x52, 0x54, 0, 0, 0, 1};
+	uint8_t port_id;
+	const int mtu = 1024;
+	int iter_count = 0;
+	int count, link_up;
+	int *int_ptr;
+
+	/* get command parameter */
+	if (argc > 1)
+		keep_traffic = atoi(argv[1]);
+	/* set stack size */
+	set_stacksize();
+
+	/* initialize request pipe */
+	init_req_pipe();
+
+	printf("issue ipc begin\n");
+	/* send a request to start the NIC device */
+	num_of_ports = netdev_ipc_begin(mac_addr);
+	while (num_of_ports == 0)
+		num_of_ports = netdev_ipc_begin(mac_addr) & 0xFF;
+
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		link_up = netdev_ethtool_get_link(port_id);
+		printf("port #%d is %s\n", port_id, link_up?"up":"down");
+		if (!link_up) {
+			if (netdev_net_open(port_id) == 0)
+				netdev_net_set_rx_mode(port_id);
+			else
+				printf("failed to start port #%d\n", port_id);
+		}
+	}
+
+	memset(reply_data, 0xFF, MAXI_DATA);
+	/* Testing ethtool API */
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (!is_port_enabled(port_id))
+			continue;
+		else {
+			/* print out mac address */
+			if (netdev_net_get_mac_addr(port_id, mac_addr)) {
+				printf("Fail to get mac addr from port");
+				printf(" #%d!!!\n", port_id);
+			} else
+				printf("\nPort #%d mac addr is %s\n",
+					port_id, mac_addr_str(mac_addr));
+
+			if (netdev_ethtool_get_drvinfo(port_id, &drvinfo)) {
+				printf("fail to get drvinfo ...\n");
+			} else {
+				printf("driver: %s version: %s ",
+					drvinfo.driver, drvinfo.version);
+				printf("fw_version: %s bus_info=%s\n",
+					drvinfo.fw_version, drvinfo.bus_info);
+				printf("reg-size(bytes)=%d eeprom-size=%d\n",
+					drvinfo.regdump_len,
+					drvinfo.eedump_len);
+			}
+
+			count = netdev_ethtool_get_regs_len(port_id);
+			if (count <= 0) {
+				printf("There are no registers available from");
+				printf(" device/port #%d", port_id);
+			} else {
+				printf("Target device has %d registers ",
+					count);
+				printf("for dump\n");
+			}
+
+			if (count > 0) {
+				memset(&regs, 0xFF,
+					sizeof(struct ethtool_regs));
+				count = netdev_ethtool_get_regs(port_id,
+					&regs, reply_data);
+				if (count) {
+					printf("failed to run");
+					printf(" ethtool_get_regs ");
+					printf("from port #%d (err=%d)\n",
+						port_id, count);
+				} else {
+					int_ptr = (int *)((void *)reply_data);
+					printf("reg[0]=%x reg[10]=%x ",
+						int_ptr[0], int_ptr[10]);
+					printf("version=0x%x\n",
+						regs.version);
+				}
+			}
+
+			/* Only testing eeprom access over a PF */
+			count = 0;
+			if (!is_vf_port(port_id)) {
+				count = netdev_ethtool_get_eeprom_len(0);
+				if (count == 0) {
+					printf("fail to retrieve eeprom");
+					printf("count from port #%d\n",
+						port_id);
+				}
+			}
+
+			if (count) {
+				printf("eeprom size is %d bytes\n", count);
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				eeprom.magic = 0;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to read eeprom");
+					printf(" from port #%d\n",
+						port_id);
+				} else {
+					int i;
+					uint16_t *word = (uint16_t *)
+						((void *)reply_data);
+
+					printf("eeprom-magic: %x;",
+						eeprom.magic);
+					printf("eeprom data ...\n");
+					count = 80;
+					for (i = 0; i < (int)(eeprom.len
+						>> 1); i++) {
+						if (((i+1) % 16) == 0)
+							printf("\n");
+						printf("%4x ", word[i]);
+					}
+					printf("\n");
+				}
+			}
+		}
+	}
+
+	/* testing set/get mac address */
+	printf("MAC base address is %s\n", mac_addr_str(mac_base_addr));
+	for (port_id = 0; port_id < num_of_ports; port_id++) {
+		if (netdev_net_get_mac_addr(port_id,
+			to_mac_type(mac_addr)))
+			printf("Fail to get mac addr from port #%d!!!\n",
+				port_id);
+		else
+			printf("Port #%d, device mac addr is %s\n", port_id,
+				mac_addr_str(mac_addr));
+
+		if (!netdev_net_validate_addr(port_id,
+			to_mac_type(mac_addr))) {
+			printf("Default mac addr, %s, is not valid\n",
+				mac_addr_str(mac_addr));
+			strncpy((char *)mac_addr, (char *)mac_base_addr,
+				MAC_ADDR_SIZE);
+			mac_addr[MAC_ADDR_SIZE-1] = 1+port_id;
+			printf("New mac address:%s is used.\n",
+				mac_addr_str(mac_addr));
+
+			if (netdev_net_set_mac_addr(port_id,
+				to_mac_type(mac_addr)) ||
+				netdev_net_get_mac_addr(port_id,
+				to_mac_type(mac_addr))) {
+					printf("Fail to reset mac addr");
+					printf(" @ port #%d!!!\n", port_id);
+			} else {
+				printf("After mac address re-assign");
+				printf(" device mac addr is %s\n",
+					mac_addr_str(mac_addr));
+			}
+		}
+	}
+
+	printf("start nic statistics collection ...\n");
+
+	port_id = get_port();
+	while (iter_count++ < ITER_LIMIT) {
+		uint64_t last_ts, ts;
+		struct rte_eth_stats last_stats, stats;
+
+		if (netdev_net_get_stats64(port_id, &last_stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		last_ts = rdtsc();
+
+		sleep(10);
+
+		if (netdev_net_get_stats64(port_id, &stats)) {
+			printf("Fail to query statistics from port %d\n",
+				port_id);
+			break;
+		}
+		ts = rdtsc();
+
+		printf("rx packet rate = %lf, tx packet rate = %lf\n",
+			PACKET_RATE(last_stats.ipackets, stats.ipackets,
+			last_ts, ts),
+			PACKET_RATE(last_stats.opackets, stats.opackets,
+			last_ts, ts));
+
+
+		printf("rx bit rate = %lf, tx bit rate = %lf\n",
+			BYTE2BIT_RATE(last_stats.ibytes, stats.ibytes,
+			last_ts, ts),
+			BYTE2BIT_RATE(last_stats.obytes, stats.obytes,
+			last_ts, ts));
+
+		sleep(5);
+	}
+
+	/* stop link for testing */
+	if (!keep_traffic) {
+		int status;
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (link_up)
+				netdev_net_stop(port_id);
+		}
+
+		for (port_id = 0; port_id < num_of_ports; port_id++) {
+			link_up = netdev_ethtool_get_link(port_id);
+			if (!is_vf_port(port_id) && !link_up) {
+				eeprom.offset = 20;
+				eeprom.len = 80;
+				if (netdev_ethtool_get_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("failed to read eeprom");
+					printf(" break from post-run");
+					printf(" testing!!!\n");
+					break;
+				}
+				if (netdev_ethtool_set_eeprom(port_id,
+					&eeprom, reply_data)) {
+					printf("Fail to write read-back");
+					printf(" data to eeprom!!!\n");
+					break;
+				}
+				/* checking mtu setting */
+				if (netdev_net_change_mtu(port_id, mtu)) {
+					printf("failed to set mtu");
+					printf("to %d\n", mtu);
+				}
+
+				/* add/remove vlan to vid */
+				status = netdev_net_vlan_rx_add_vid(
+					port_id, 0);
+				if (status == 0) {
+					status = netdev_net_vlan_rx_kill_vid(
+						port_id, 0);
+
+					if (status) {
+						printf("fail kill vlan-vid\n");
+						break;
+					}
+				} else {
+					printf("fail adding vlan/vid 0\n");
+					break;
+				}
+
+				/* testing pause parameter get/set functions */
+				status = netdev_ethtool_get_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("get pauseparam fail\n");
+					break;
+				}
+				printf("pause setup: autoneg: %d ",
+					pause_param.autoneg);
+				printf("tx_pause: %d ",
+					pause_param.tx_pause);
+				printf("rx_pause: %d\n",
+					pause_param.rx_pause);
+				status = netdev_ethtool_set_pauseparam(
+					port_id, &pause_param);
+				if (status) {
+					printf("set pause param fail\n");
+					break;
+				}
+
+			}
+		}
+	}
+
+	while (netdev_ipc_end() < 0)
+		;
+
+	printf("Done for ethtool service request!!!\n");
+	return 0;
+}
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v17 5/5] examples: new example: l2fwd-ethtool
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 5/5] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
@ 2015-07-16 21:25     ` Thomas Monjalon
  0 siblings, 0 replies; 174+ messages in thread
From: Thomas Monjalon @ 2015-07-16 21:25 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

2015-07-16 09:25, Liang-Min Larry Wang:
> The example includes an ethtool library and two applications:
> one application is a non- DPDK process (nic-control)
> and the other is a DPDK l2fwd applicaiton (l2fwd-app).
> The nic-control process sends ethtool alike device management
> requests to l2fwd-app through a named pipe IPC. This example
> is designed to show how to build a ethtool shim library and
> how to use ethtool apis to manage device parameters.

The makefiles need some clean-up and it does not build in shared lib mode.

Beginning of a cleanup patch to merge with this one:

--- a/examples/Makefile
+++ b/examples/Makefile
@@ -50,12 +50,10 @@ DIRS-y += ip_reassembly
 DIRS-$(CONFIG_RTE_IP_FRAG) += ip_fragmentation
 DIRS-y += ipv4_multicast
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += kni
-DIRS-y += l2fwd-ethtool/lib
-DIRS-y += l2fwd-ethtool/nic-control
-DIRS-y += l2fwd-ethtool/l2fwd-app
 DIRS-y += l2fwd
 DIRS-$(CONFIG_RTE_LIBRTE_IVSHMEM) += l2fwd-ivshmem
 DIRS-$(CONFIG_RTE_LIBRTE_JOBSTATS) += l2fwd-jobstats
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += l2fwd-ethtool
 DIRS-y += l3fwd
 DIRS-$(CONFIG_RTE_LIBRTE_ACL) += l3fwd-acl
 DIRS-$(CONFIG_RTE_LIBRTE_POWER) += l3fwd-power

--- a/examples/l2fwd-ethtool/Makefile
+++ b/examples/l2fwd-ethtool/Makefile
@@ -37,7 +37,6 @@ endif
 RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
-unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK
 
 ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
 $(error This application can only operate in a linuxapp environment, \
@@ -46,10 +45,4 @@ endif
 
 DIRS-y += lib nic-control l2fwd-app
 
-.PHONY: all clean $(DIRS-y)
-
-all: $(DIRS-y)
-clean: $(DIRS-y)
-
-$(DIRS-y):
-       $(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT)
+include $(RTE_SDK)/mk/rte.extsubdir.mk

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v17 0/5] User-space Ethtool
  2015-07-16 13:25 ` [dpdk-dev] [PATCH v17 0/5] " Liang-Min Larry Wang
                     ` (4 preceding siblings ...)
  2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 5/5] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
@ 2015-07-16 21:48   ` Thomas Monjalon
  2015-07-16 21:55     ` Wang, Liang-min
  5 siblings, 1 reply; 174+ messages in thread
From: Thomas Monjalon @ 2015-07-16 21:48 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

2015-07-16 09:25, Liang-Min Larry Wang:
> This implementation is designed to provide a familar interface for applications that rely on kernel-space driver to support ethtool_op and net_device_op for device management. The initial implementation focuses on ops that can be implemented through existing netdev APIs. More ops will be supported in latter release.

Applied without example which needs more work, thanks

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v17 0/5] User-space Ethtool
  2015-07-16 21:48   ` [dpdk-dev] [PATCH v17 0/5] User-space Ethtool Thomas Monjalon
@ 2015-07-16 21:55     ` Wang, Liang-min
  2015-07-16 22:09       ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-07-16 21:55 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Thomas,
	Do you want me to create a separate patch just include the example/l2fwd-ethtool? Do you also mean besides the identified Makefiles, you see more rework needs to be done, or I just need to fix Makefile issue? If just Makefile issue, I could try to make another attempt tomorrow?

Thanks,
Larry

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Thursday, July 16, 2015 5:48 PM
> To: Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v17 0/5] User-space Ethtool
> 
> 2015-07-16 09:25, Liang-Min Larry Wang:
> > This implementation is designed to provide a familar interface for
> applications that rely on kernel-space driver to support ethtool_op and
> net_device_op for device management. The initial implementation focuses
> on ops that can be implemented through existing netdev APIs. More ops will
> be supported in latter release.
> 
> Applied without example which needs more work, thanks

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v17 0/5] User-space Ethtool
  2015-07-16 21:55     ` Wang, Liang-min
@ 2015-07-16 22:09       ` Thomas Monjalon
  2015-07-16 22:15         ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Thomas Monjalon @ 2015-07-16 22:09 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

2015-07-16 21:55, Wang, Liang-min:
> Thomas,
> 	Do you want me to create a separate patch just include the example/l2fwd-ethtool?

Yes

> 	Do you also mean besides the identified Makefiles, you see more rework needs to be done,
> 	or I just need to fix Makefile issue? If just Makefile issue, I could try to make another attempt tomorrow?

After checking the build there is probably more review to do.
Let's take more time to have something clean and maybe more complete in 2.2.
This patchset is your first contribution to DPDK and is already a nice achievement.
The new API must now be implemented in more drivers to be effective.


> > -----Original Message-----
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > Sent: Thursday, July 16, 2015 5:48 PM
> > To: Wang, Liang-min
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH v17 0/5] User-space Ethtool
> > 
> > 2015-07-16 09:25, Liang-Min Larry Wang:
> > > This implementation is designed to provide a familar interface for
> > applications that rely on kernel-space driver to support ethtool_op and
> > net_device_op for device management. The initial implementation focuses
> > on ops that can be implemented through existing netdev APIs. More ops will
> > be supported in latter release.
> > 
> > Applied without example which needs more work, thanks

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH v17 0/5] User-space Ethtool
  2015-07-16 22:09       ` Thomas Monjalon
@ 2015-07-16 22:15         ` Wang, Liang-min
  0 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-07-16 22:15 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Thomas,
	Thanks for clarification. Our next step is to create hooks on virtio and vmxnet3 and other ethtool op.

Thanks again for making prompt reply as I am aware it's very late in your time zone.

Larry

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Thursday, July 16, 2015 6:09 PM
> To: Wang, Liang-min
> Cc: dev@dpdk.org; O'Driscoll, Tim
> Subject: Re: [dpdk-dev] [PATCH v17 0/5] User-space Ethtool
> 
> 2015-07-16 21:55, Wang, Liang-min:
> > Thomas,
> > 	Do you want me to create a separate patch just include the
> example/l2fwd-ethtool?
> 
> Yes
> 
> > 	Do you also mean besides the identified Makefiles, you see more
> rework needs to be done,
> > 	or I just need to fix Makefile issue? If just Makefile issue, I could try
> to make another attempt tomorrow?
> 
> After checking the build there is probably more review to do.
> Let's take more time to have something clean and maybe more complete in
> 2.2.
> This patchset is your first contribution to DPDK and is already a nice
> achievement.
> The new API must now be implemented in more drivers to be effective.
> 
> 
> > > -----Original Message-----
> > > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > Sent: Thursday, July 16, 2015 5:48 PM
> > > To: Wang, Liang-min
> > > Cc: dev@dpdk.org
> > > Subject: Re: [dpdk-dev] [PATCH v17 0/5] User-space Ethtool
> > >
> > > 2015-07-16 09:25, Liang-Min Larry Wang:
> > > > This implementation is designed to provide a familar interface for
> > > applications that rely on kernel-space driver to support ethtool_op and
> > > net_device_op for device management. The initial implementation
> focuses
> > > on ops that can be implemented through existing netdev APIs. More ops
> will
> > > be supported in latter release.
> > >
> > > Applied without example which needs more work, thanks
> 

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-05 17:24                             ` Andrew Harvey (agh)
@ 2015-06-05 21:03                               ` Thomas Monjalon
  0 siblings, 0 replies; 174+ messages in thread
From: Thomas Monjalon @ 2015-06-05 21:03 UTC (permalink / raw)
  To: Andrew Harvey (agh); +Cc: dev, Wang, Liang-min

2015-06-05 17:24, Andrew Harvey:
> On 6/5/15, 5:47 AM, "Bruce Richardson" <bruce.richardson@intel.com> wrote:
> >> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> >> > That's why we need to understand what we (or you) are missing.
> >> > Maybe that it would be clearer with some code examples (which would
> >> > go in the lib documentation if any).
> >> > 
> >> > Thanks
> >
> >How about doing this work as a sample application initially, to
> >demonstrate how
> >an application written using ethtool APIs could be shimmed to use DPDK
> >underneath.
> >The ethtool to dpdk mapping could be contained in a single header file
> >(or header
> >and c file) inside the sample app. This would allow easy re-use of the
> >shim
> >layer, while at the same time not making it part of the core DPDK
> >libraries.
> >
> >Regards,
> >/Bruce
> 
> This would appear to be the most pragmatic way forward.  It would allow
> others to see more of the code and judge its value for themselves. I have
> no issues with this approach if others agree.

Since the beginning of this thread, a doc is requested (many times) to
show the benefit of integrating such a layer.
If you prefer coding a full example, it would probably also be fine.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-05 16:07                         ` Andrew Harvey (agh)
@ 2015-06-05 20:57                           ` Thomas Monjalon
  0 siblings, 0 replies; 174+ messages in thread
From: Thomas Monjalon @ 2015-06-05 20:57 UTC (permalink / raw)
  To: Andrew Harvey (agh); +Cc: dev, Wang, Liang-min

2015-06-05 16:07, Andrew Harvey:
> On 6/5/15, 3:46 AM, "Thomas Monjalon" <thomas.monjalon@6wind.com> wrote:
> >Stephen and me say the same thing about using the ethdev API.
> 
> And your would have a point would be valid if dpdk were available to every
> interface we support (it is not) and on every processor architecture that
> we support (it is not) and every OS we support (it is not).  So to
> minimize entropy in the code why not leave the client code the same
> ioctl(fd, …) and hide the implementation
> detail in a wrapper library.

Please, explain the relation between an ioctl and the DPDK.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-05 12:47                           ` Bruce Richardson
@ 2015-06-05 17:24                             ` Andrew Harvey (agh)
  2015-06-05 21:03                               ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Andrew Harvey (agh) @ 2015-06-05 17:24 UTC (permalink / raw)
  To: Bruce Richardson, Wang, Liang-min; +Cc: dev

On 6/5/15, 5:47 AM, "Bruce Richardson" <bruce.richardson@intel.com> wrote:

>On Fri, Jun 05, 2015 at 11:25:09AM +0000, Wang, Liang-min wrote:
>> 
>> 
>> > -----Original Message-----
>> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
>> > Sent: Friday, June 05, 2015 6:47 AM
>> > To: Andrew Harvey (agh)
>> > Cc: Stephen Hemminger; Wang, Liang-min; dev@dpdk.org
>> > Subject: Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to
>>provide
>> > ethtool-alike APIs
>> > 
>> > 2015-06-04 22:10, Andrew Harvey:
>> > > On 6/4/15, 7:58 AM, "Stephen Hemminger"
>> > <stephen@networkplumber.org> wrote:
>> > > >"Andrew Harvey (agh)" <agh@cisco.com> wrote:
>> > > >> I believe that their is value in this interface for software
>>stacks
>> > > >>not  based on Linux being moved toward DPDK that need simple
>> > > >>operations like  getting the mac address.  Some of these stacks
>>have
>> > > >>a dearth of resources  available and dedicating a core/thread to
>>KNI
>> > > >>to get/set a mac address  is considered excessive. There are also
>> > > >>issues with 32/64 bit kernel  integration  using KNI.  If the
>> > > >>ethtool interface is not the correct interface then  please help
>>me
>> > > >>understand what should/could have been used. If ethtool is
>> > > >>considered 'old  and clunky¹  Stephen's and your input would be
>> > > >>valuable in designing another interface  with  similar properties.
>> > > >>The use-case is pretty simple and there is no plans  for moving
>> > > >>anything back into the kernel on the contrary its the complete
>>opposite.
>> > > >>
>> > > >> ‹ Andy
>> > > >
>> > > >We have DPDK API's to do this, and any added wrappers make it
>>bigger.
>> > > >I don't see why calling your ethtool API is better than calling
>> > > >rte_eth* API.
>> > > >
>> > > >If there is a missing functionality in the rte_ethXXX api's for an
>> > > >application then add that. For example: rte_eth_mac_addr_get()
>> > >
>> > > I am getting somewhat confused by your latest comments.  Your first
>> > > email (referenced below) looked really positive and I found your
>> > > suggestions useful. Your latest post appears to contradict this and
>> > > now the interface was there all the time.  The wrapper façade
>>provided
>> > > by the ethtool library provide a clean separation of concerns and
>>will
>> > > allow people to migrate from not only KNI but in our case from a
>> > > legacy system.  If a software stack has requirements to work with
>> > > multiple IO abstractions then the ethtool approach is attractive. I
>> > > would speculate that many other stacks moving towards dpdk will have
>> > similar issues.
>> > >
>> > > Summarizing, for our use-cases the ethtool interface facilitated our
>> > > adoption to dpdk while allowing us to support our legacy IO
>>abstractions.
>> > 
>> > Stephen and me say the same thing about using the ethdev API.
>> > We don't understand why using a fake ethtool lib would be easier.
>> > Though you are saying it "facilitated [your] adoption to dpdk".
>> > Please could you explain why using an ethtool-like API is easier than
>>using
>> > the existing ethdev API?
>> > In any case, you have to develop a specific backend for DPDK
>>(rte_ethtool
>> > would be also DPDK-specific).
>> 
>> As described earlier in this patch comment reply, there are other
>>ethtool ops that have been implemented.
>> Those ops includes set/get eeprom, set/get pauseparam, set/get
>>ringparam which are not available in the exiting ethdev library.
>> For this release, we focus on releasing some basic functions (btw,
>>mac_addr_set is not available but is covered by this patch).
>> The key reason that this set of library is not released as part of
>>ethdev is the ethtool API dependency on kernel include file.
>> To faithfully carry the ethtool ops and net dev ops API parameters, the
>>ethtool APIs are designed to follow the original definition except
>>avoiding carry kernel states.
>> With that, to support ethtool APIs faithfully, we need to include
>><linux/ethtool.h>.
>> As suggested by many DPDK veterans including Thomas (indicated over
>>your reply), you would prefer these APIs in a separate library.
>> 
>> > 
>> > It seems you already started to use such an ethtool implementation.
>> > Please note that our goal is not to prevent Cisco from upstreaming
>>(evidence
>> > with enic driver integration) but we want to guide you, and others
>>having the
>> > same needs, to the best solution for everybody.
>> > That's why we need to understand what we (or you) are missing.
>> > Maybe that it would be clearer with some code examples (which would
>>go in
>> > the lib documentation if any).
>> > 
>> > Thanks
>
>How about doing this work as a sample application initially, to
>demonstrate how
>an application written using ethtool APIs could be shimmed to use DPDK
>underneath.
>The ethtool to dpdk mapping could be contained in a single header file
>(or header
>and c file) inside the sample app. This would allow easy re-use of the
>shim
>layer, while at the same time not making it part of the core DPDK
>libraries.
>
>Regards,
>/Bruce

This would appear to be the most pragmatic way forward.  It would allow
others to see more of the code and judge its value for themselves. I have
no issues with this approach if others agree.

— Andy


^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-05 10:46                       ` Thomas Monjalon
  2015-06-05 11:25                         ` Wang, Liang-min
@ 2015-06-05 16:07                         ` Andrew Harvey (agh)
  2015-06-05 20:57                           ` Thomas Monjalon
  1 sibling, 1 reply; 174+ messages in thread
From: Andrew Harvey (agh) @ 2015-06-05 16:07 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, Wang, Liang-min

On 6/5/15, 3:46 AM, "Thomas Monjalon" <thomas.monjalon@6wind.com> wrote:

>2015-06-04 22:10, Andrew Harvey:
>> On 6/4/15, 7:58 AM, "Stephen Hemminger" <stephen@networkplumber.org>
>>wrote:
>> >"Andrew Harvey (agh)" <agh@cisco.com> wrote:
>> >> I believe that their is value in this interface for software stacks
>>not
>> >> based on Linux being moved toward DPDK that need simple operations
>>like
>> >> getting the mac address.  Some of these stacks have a dearth of
>> >>resources
>> >> available and dedicating a core/thread to KNI to get/set a mac
>>address
>> >> is considered excessive. There are also issues with 32/64 bit kernel
>> >> integration
>> >> using KNI.  If the ethtool interface is not the correct interface
>>then
>> >> please help me
>> >> understand what should/could have been used. If ethtool is considered
>> >>'old
>> >> and clunky¹
>> >> Stephen's and your input would be valuable in designing another
>> >>interface
>> >> with
>> >> similar properties.  The use-case is pretty simple and there is no
>>plans
>> >> for moving
>> >> anything back into the kernel on the contrary its the complete
>>opposite.
>> >> 
>> >> ‹ Andy
>> >
>> >We have DPDK API's to do this, and any added wrappers make it bigger.
>> >I don't see why calling your ethtool API is better than calling
>> >rte_eth* API.
>> >
>> >If there is a missing functionality in the rte_ethXXX api's for an
>> >application then add that. For example: rte_eth_mac_addr_get()
>> 
>> I am getting somewhat confused by your latest comments.  Your first
>>email
>> (referenced below) looked really positive and I found your suggestions
>> useful. Your latest post appears to contradict this and now the
>>interface
>> was there all the time.  The wrapper façade provided by the ethtool
>> library provide a clean separation of concerns and will allow people to
>> migrate from not only KNI but in our case from a legacy system.  If a
>> software stack has requirements to work with multiple IO abstractions
>> then the ethtool approach is attractive. I would speculate that many
>> other stacks moving towards dpdk will have similar issues.
>> 
>> Summarizing, for our use-cases the ethtool interface facilitated our
>> adoption to dpdk while allowing us to support our legacy IO
>>abstractions.
>
>Stephen and me say the same thing about using the ethdev API.

And your would have a point would be valid if dpdk were available to every
interface we support (it is not) and on every processor architecture that
we support (it is not) and every OS we support (it is not).  So to
minimize entropy in the code why not leave the client code the same
ioctl(fd, …) and hide the implementation
detail in a wrapper library.  We have a large legacy code base to move
forward and sprinkling special interest code like rte_xxx throughout every
client we have is not appropriate at this time.

 
>We don't understand why using a fake ethtool lib would be easier.
>Though you are saying it "facilitated [your] adoption to dpdk".
>Please could you explain why using an ethtool-like API is easier than
>using the existing ethdev API?
>In any case, you have to develop a specific backend for DPDK
>(rte_ethtool would be also DPDK-specific).
>
>It seems you already started to use such an ethtool implementation.
>Please note that our goal is not to prevent Cisco from upstreaming
>(evidence with enic driver integration) but we want to guide you, and
>others having the same needs, to the best solution for everybody.
>That's why we need to understand what we (or you) are missing.
>Maybe that it would be clearer with some code examples (which would
>go in the lib documentation if any).
>
>Thanks


^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-05 13:40                           ` Thomas Monjalon
@ 2015-06-05 14:20                             ` Wang, Liang-min
  0 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-05 14:20 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Friday, June 05, 2015 9:41 AM
> To: Wang, Liang-min
> Cc: Andrew Harvey (agh); Stephen Hemminger; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide
> ethtool-alike APIs
> 
> 2015-06-05 11:25, Wang, Liang-min:
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > Stephen and me say the same thing about using the ethdev API.
> > > We don't understand why using a fake ethtool lib would be easier.
> > > Though you are saying it "facilitated [your] adoption to dpdk".
> > > Please could you explain why using an ethtool-like API is easier
> > > than using the existing ethdev API?
> > > In any case, you have to develop a specific backend for DPDK
> > > (rte_ethtool would be also DPDK-specific).
> >
> > As described earlier in this patch comment reply, there are other ethtool
> ops that have been implemented.
> > Those ops includes set/get eeprom, set/get pauseparam, set/get
> ringparam which are not available in the exiting ethdev library.
> 
> 1/ We cannot really consider code which is not public 2/ You may extend
> ethdev if some functions are missing
> 
> > For this release, we focus on releasing some basic functions (btw,
> mac_addr_set is not available but is covered by this patch).
> 
> Yes, you are extending ethdev by adding
> rte_eth_dev_default_mac_addr_set.
> 
> > The key reason that this set of library is not released as part of ethdev is
> the ethtool API dependency on kernel include file.
> 
> It is a good reason to separate the library.
> But it doesn't justify its need.
> 
> > To faithfully carry the ethtool ops and net dev ops API parameters, the
> ethtool APIs are designed to follow the original definition except avoiding
> carry kernel states.
> > With that, to support ethtool APIs faithfully, we need to include
> <linux/ethtool.h>.
> > As suggested by many DPDK veterans including Thomas (indicated over
> your reply), you would prefer these APIs in a separate library.
> 
> I think I'm starting to understand that you really need ethtool conversion
> (implemented in rte_ethtool_get_drvinfo) but not the other functions which
> are simple wrappers. Right?

The rte_ethtool_get_drvinfo and many others ethtool ops have the same conversion requirement.
As for ethtool and net dev ops that don't require conversion. For the sake of clean API interface, they are implemented in the same ethtool library.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-05 11:25                         ` Wang, Liang-min
  2015-06-05 12:47                           ` Bruce Richardson
@ 2015-06-05 13:40                           ` Thomas Monjalon
  2015-06-05 14:20                             ` Wang, Liang-min
  1 sibling, 1 reply; 174+ messages in thread
From: Thomas Monjalon @ 2015-06-05 13:40 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

2015-06-05 11:25, Wang, Liang-min:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > Stephen and me say the same thing about using the ethdev API.
> > We don't understand why using a fake ethtool lib would be easier.
> > Though you are saying it "facilitated [your] adoption to dpdk".
> > Please could you explain why using an ethtool-like API is easier than using
> > the existing ethdev API?
> > In any case, you have to develop a specific backend for DPDK (rte_ethtool
> > would be also DPDK-specific).
> 
> As described earlier in this patch comment reply, there are other ethtool ops that have been implemented.
> Those ops includes set/get eeprom, set/get pauseparam, set/get ringparam which are not available in the exiting ethdev library.

1/ We cannot really consider code which is not public
2/ You may extend ethdev if some functions are missing

> For this release, we focus on releasing some basic functions (btw, mac_addr_set is not available but is covered by this patch).

Yes, you are extending ethdev by adding rte_eth_dev_default_mac_addr_set.

> The key reason that this set of library is not released as part of ethdev is the ethtool API dependency on kernel include file.

It is a good reason to separate the library.
But it doesn't justify its need.

> To faithfully carry the ethtool ops and net dev ops API parameters, the ethtool APIs are designed to follow the original definition except avoiding carry kernel states.
> With that, to support ethtool APIs faithfully, we need to include <linux/ethtool.h>. 
> As suggested by many DPDK veterans including Thomas (indicated over your reply), you would prefer these APIs in a separate library.

I think I'm starting to understand that you really need ethtool conversion
(implemented in rte_ethtool_get_drvinfo) but not the other functions which
are simple wrappers. Right?

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-05 11:25                         ` Wang, Liang-min
@ 2015-06-05 12:47                           ` Bruce Richardson
  2015-06-05 17:24                             ` Andrew Harvey (agh)
  2015-06-05 13:40                           ` Thomas Monjalon
  1 sibling, 1 reply; 174+ messages in thread
From: Bruce Richardson @ 2015-06-05 12:47 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

On Fri, Jun 05, 2015 at 11:25:09AM +0000, Wang, Liang-min wrote:
> 
> 
> > -----Original Message-----
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > Sent: Friday, June 05, 2015 6:47 AM
> > To: Andrew Harvey (agh)
> > Cc: Stephen Hemminger; Wang, Liang-min; dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide
> > ethtool-alike APIs
> > 
> > 2015-06-04 22:10, Andrew Harvey:
> > > On 6/4/15, 7:58 AM, "Stephen Hemminger"
> > <stephen@networkplumber.org> wrote:
> > > >"Andrew Harvey (agh)" <agh@cisco.com> wrote:
> > > >> I believe that their is value in this interface for software stacks
> > > >>not  based on Linux being moved toward DPDK that need simple
> > > >>operations like  getting the mac address.  Some of these stacks have
> > > >>a dearth of resources  available and dedicating a core/thread to KNI
> > > >>to get/set a mac address  is considered excessive. There are also
> > > >>issues with 32/64 bit kernel  integration  using KNI.  If the
> > > >>ethtool interface is not the correct interface then  please help me
> > > >>understand what should/could have been used. If ethtool is
> > > >>considered 'old  and clunky¹  Stephen's and your input would be
> > > >>valuable in designing another interface  with  similar properties.
> > > >>The use-case is pretty simple and there is no plans  for moving
> > > >>anything back into the kernel on the contrary its the complete opposite.
> > > >>
> > > >> ‹ Andy
> > > >
> > > >We have DPDK API's to do this, and any added wrappers make it bigger.
> > > >I don't see why calling your ethtool API is better than calling
> > > >rte_eth* API.
> > > >
> > > >If there is a missing functionality in the rte_ethXXX api's for an
> > > >application then add that. For example: rte_eth_mac_addr_get()
> > >
> > > I am getting somewhat confused by your latest comments.  Your first
> > > email (referenced below) looked really positive and I found your
> > > suggestions useful. Your latest post appears to contradict this and
> > > now the interface was there all the time.  The wrapper façade provided
> > > by the ethtool library provide a clean separation of concerns and will
> > > allow people to migrate from not only KNI but in our case from a
> > > legacy system.  If a software stack has requirements to work with
> > > multiple IO abstractions then the ethtool approach is attractive. I
> > > would speculate that many other stacks moving towards dpdk will have
> > similar issues.
> > >
> > > Summarizing, for our use-cases the ethtool interface facilitated our
> > > adoption to dpdk while allowing us to support our legacy IO abstractions.
> > 
> > Stephen and me say the same thing about using the ethdev API.
> > We don't understand why using a fake ethtool lib would be easier.
> > Though you are saying it "facilitated [your] adoption to dpdk".
> > Please could you explain why using an ethtool-like API is easier than using
> > the existing ethdev API?
> > In any case, you have to develop a specific backend for DPDK (rte_ethtool
> > would be also DPDK-specific).
> 
> As described earlier in this patch comment reply, there are other ethtool ops that have been implemented.
> Those ops includes set/get eeprom, set/get pauseparam, set/get ringparam which are not available in the exiting ethdev library.
> For this release, we focus on releasing some basic functions (btw, mac_addr_set is not available but is covered by this patch).
> The key reason that this set of library is not released as part of ethdev is the ethtool API dependency on kernel include file.
> To faithfully carry the ethtool ops and net dev ops API parameters, the ethtool APIs are designed to follow the original definition except avoiding carry kernel states.
> With that, to support ethtool APIs faithfully, we need to include <linux/ethtool.h>. 
> As suggested by many DPDK veterans including Thomas (indicated over your reply), you would prefer these APIs in a separate library.
> 
> > 
> > It seems you already started to use such an ethtool implementation.
> > Please note that our goal is not to prevent Cisco from upstreaming (evidence
> > with enic driver integration) but we want to guide you, and others having the
> > same needs, to the best solution for everybody.
> > That's why we need to understand what we (or you) are missing.
> > Maybe that it would be clearer with some code examples (which would go in
> > the lib documentation if any).
> > 
> > Thanks

How about doing this work as a sample application initially, to demonstrate how
an application written using ethtool APIs could be shimmed to use DPDK underneath.
The ethtool to dpdk mapping could be contained in a single header file (or header
and c file) inside the sample app. This would allow easy re-use of the shim
layer, while at the same time not making it part of the core DPDK libraries.

Regards,
/Bruce

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-05 10:46                       ` Thomas Monjalon
@ 2015-06-05 11:25                         ` Wang, Liang-min
  2015-06-05 12:47                           ` Bruce Richardson
  2015-06-05 13:40                           ` Thomas Monjalon
  2015-06-05 16:07                         ` Andrew Harvey (agh)
  1 sibling, 2 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-05 11:25 UTC (permalink / raw)
  To: Thomas Monjalon, Andrew Harvey (agh); +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Friday, June 05, 2015 6:47 AM
> To: Andrew Harvey (agh)
> Cc: Stephen Hemminger; Wang, Liang-min; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide
> ethtool-alike APIs
> 
> 2015-06-04 22:10, Andrew Harvey:
> > On 6/4/15, 7:58 AM, "Stephen Hemminger"
> <stephen@networkplumber.org> wrote:
> > >"Andrew Harvey (agh)" <agh@cisco.com> wrote:
> > >> I believe that their is value in this interface for software stacks
> > >>not  based on Linux being moved toward DPDK that need simple
> > >>operations like  getting the mac address.  Some of these stacks have
> > >>a dearth of resources  available and dedicating a core/thread to KNI
> > >>to get/set a mac address  is considered excessive. There are also
> > >>issues with 32/64 bit kernel  integration  using KNI.  If the
> > >>ethtool interface is not the correct interface then  please help me
> > >>understand what should/could have been used. If ethtool is
> > >>considered 'old  and clunky¹  Stephen's and your input would be
> > >>valuable in designing another interface  with  similar properties.
> > >>The use-case is pretty simple and there is no plans  for moving
> > >>anything back into the kernel on the contrary its the complete opposite.
> > >>
> > >> ‹ Andy
> > >
> > >We have DPDK API's to do this, and any added wrappers make it bigger.
> > >I don't see why calling your ethtool API is better than calling
> > >rte_eth* API.
> > >
> > >If there is a missing functionality in the rte_ethXXX api's for an
> > >application then add that. For example: rte_eth_mac_addr_get()
> >
> > I am getting somewhat confused by your latest comments.  Your first
> > email (referenced below) looked really positive and I found your
> > suggestions useful. Your latest post appears to contradict this and
> > now the interface was there all the time.  The wrapper façade provided
> > by the ethtool library provide a clean separation of concerns and will
> > allow people to migrate from not only KNI but in our case from a
> > legacy system.  If a software stack has requirements to work with
> > multiple IO abstractions then the ethtool approach is attractive. I
> > would speculate that many other stacks moving towards dpdk will have
> similar issues.
> >
> > Summarizing, for our use-cases the ethtool interface facilitated our
> > adoption to dpdk while allowing us to support our legacy IO abstractions.
> 
> Stephen and me say the same thing about using the ethdev API.
> We don't understand why using a fake ethtool lib would be easier.
> Though you are saying it "facilitated [your] adoption to dpdk".
> Please could you explain why using an ethtool-like API is easier than using
> the existing ethdev API?
> In any case, you have to develop a specific backend for DPDK (rte_ethtool
> would be also DPDK-specific).

As described earlier in this patch comment reply, there are other ethtool ops that have been implemented.
Those ops includes set/get eeprom, set/get pauseparam, set/get ringparam which are not available in the exiting ethdev library.
For this release, we focus on releasing some basic functions (btw, mac_addr_set is not available but is covered by this patch).
The key reason that this set of library is not released as part of ethdev is the ethtool API dependency on kernel include file.
To faithfully carry the ethtool ops and net dev ops API parameters, the ethtool APIs are designed to follow the original definition except avoiding carry kernel states.
With that, to support ethtool APIs faithfully, we need to include <linux/ethtool.h>. 
As suggested by many DPDK veterans including Thomas (indicated over your reply), you would prefer these APIs in a separate library.

> 
> It seems you already started to use such an ethtool implementation.
> Please note that our goal is not to prevent Cisco from upstreaming (evidence
> with enic driver integration) but we want to guide you, and others having the
> same needs, to the best solution for everybody.
> That's why we need to understand what we (or you) are missing.
> Maybe that it would be clearer with some code examples (which would go in
> the lib documentation if any).
> 
> Thanks

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-04 22:10                     ` Andrew Harvey (agh)
@ 2015-06-05 10:46                       ` Thomas Monjalon
  2015-06-05 11:25                         ` Wang, Liang-min
  2015-06-05 16:07                         ` Andrew Harvey (agh)
  0 siblings, 2 replies; 174+ messages in thread
From: Thomas Monjalon @ 2015-06-05 10:46 UTC (permalink / raw)
  To: Andrew Harvey (agh); +Cc: dev, Wang, Liang-min

2015-06-04 22:10, Andrew Harvey:
> On 6/4/15, 7:58 AM, "Stephen Hemminger" <stephen@networkplumber.org> wrote:
> >"Andrew Harvey (agh)" <agh@cisco.com> wrote:
> >> I believe that their is value in this interface for software stacks not
> >> based on Linux being moved toward DPDK that need simple operations like
> >> getting the mac address.  Some of these stacks have a dearth of
> >>resources
> >> available and dedicating a core/thread to KNI to get/set a mac address
> >> is considered excessive. There are also issues with 32/64 bit kernel
> >> integration
> >> using KNI.  If the ethtool interface is not the correct interface then
> >> please help me
> >> understand what should/could have been used. If ethtool is considered
> >>'old
> >> and clunky¹
> >> Stephen's and your input would be valuable in designing another
> >>interface
> >> with
> >> similar properties.  The use-case is pretty simple and there is no plans
> >> for moving
> >> anything back into the kernel on the contrary its the complete opposite.
> >> 
> >> ‹ Andy
> >
> >We have DPDK API's to do this, and any added wrappers make it bigger.
> >I don't see why calling your ethtool API is better than calling
> >rte_eth* API.
> >
> >If there is a missing functionality in the rte_ethXXX api's for an
> >application then add that. For example: rte_eth_mac_addr_get()
> 
> I am getting somewhat confused by your latest comments.  Your first email
> (referenced below) looked really positive and I found your suggestions
> useful. Your latest post appears to contradict this and now the interface
> was there all the time.  The wrapper façade provided by the ethtool
> library provide a clean separation of concerns and will allow people to
> migrate from not only KNI but in our case from a legacy system.  If a
> software stack has requirements to work with multiple IO abstractions
> then the ethtool approach is attractive. I would speculate that many
> other stacks moving towards dpdk will have similar issues.
> 
> Summarizing, for our use-cases the ethtool interface facilitated our
> adoption to dpdk while allowing us to support our legacy IO abstractions.

Stephen and me say the same thing about using the ethdev API.
We don't understand why using a fake ethtool lib would be easier.
Though you are saying it "facilitated [your] adoption to dpdk".
Please could you explain why using an ethtool-like API is easier than
using the existing ethdev API?
In any case, you have to develop a specific backend for DPDK
(rte_ethtool would be also DPDK-specific).

It seems you already started to use such an ethtool implementation.
Please note that our goal is not to prevent Cisco from upstreaming
(evidence with enic driver integration) but we want to guide you, and
others having the same needs, to the best solution for everybody.
That's why we need to understand what we (or you) are missing.
Maybe that it would be clearer with some code examples (which would
go in the lib documentation if any).

Thanks

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-04 14:58                   ` Stephen Hemminger
@ 2015-06-04 22:10                     ` Andrew Harvey (agh)
  2015-06-05 10:46                       ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Andrew Harvey (agh) @ 2015-06-04 22:10 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev, Wang, Liang-min

On 6/4/15, 7:58 AM, "Stephen Hemminger" <stephen@networkplumber.org> wrote:

>On Wed, 3 Jun 2015 02:09:39 +0000
>"Andrew Harvey (agh)" <agh@cisco.com> wrote:
>
>> I believe that their is value in this interface for software stacks not
>> based on Linux being moved toward DPDK that need simple operations like
>> getting the mac address.  Some of these stacks have a dearth of
>>resources
>> available and dedicating a core/thread to KNI to get/set a mac address
>> is considered excessive. There are also issues with 32/64 bit kernel
>> integration
>> using KNI.  If the ethtool interface is not the correct interface then
>> please help me
>> understand what should/could have been used. If ethtool is considered
>>'old
>> and clunky¹
>> Stephen's and your input would be valuable in designing another
>>interface
>> with
>> similar properties.  The use-case is pretty simple and there is no plans
>> for moving
>> anything back into the kernel on the contrary its the complete opposite.
>> 
>> ‹ Andy
>
>We have DPDK API's to do this, and any added wrappers make it bigger.
>I don't see why calling your ethtool API is better than calling
>rte_eth* API.
>
>If there is a missing functionality in the rte_ethXXX api's for an
>application then add that. For example: rte_eth_mac_addr_get()

I am getting somewhat confused by your latest comments.  Your first email
(referenced below) looked really positive and I found your suggestions
useful. Your latest post appears to contradict this and now the interface
was there all the time.  The wrapper façade provided by the ethtool
library provide a clean separation of concerns and will allow people to
migrate from not only KNI but in our case from a legacy system.  If a
software stack has requirements to work with multiple IO abstractions
then the ethtool approach is attractive. I would speculate that many
other stacks moving towards dpdk will have similar issues.

Summarizing, for our use-cases the ethtool interface facilitated our
adoption to dpdk while allowing us to support our legacy IO abstractions.

— Andy

http://dpdk.org/ml/archives/dev/2015-May/018408.html (original email)

http://dpdk.org/ml/archives/dev/2014-June/003005.html (ethtool request)



^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-03  2:09                 ` Andrew Harvey (agh)
  2015-06-04 14:25                   ` O'Driscoll, Tim
@ 2015-06-04 14:58                   ` Stephen Hemminger
  2015-06-04 22:10                     ` Andrew Harvey (agh)
  1 sibling, 1 reply; 174+ messages in thread
From: Stephen Hemminger @ 2015-06-04 14:58 UTC (permalink / raw)
  To: Andrew Harvey (agh); +Cc: dev, Wang, Liang-min

On Wed, 3 Jun 2015 02:09:39 +0000
"Andrew Harvey (agh)" <agh@cisco.com> wrote:

> I believe that their is value in this interface for software stacks not
> based on Linux being moved toward DPDK that need simple operations like
> getting the mac address.  Some of these stacks have a dearth of resources
> available and dedicating a core/thread to KNI to get/set a mac address
> is considered excessive. There are also issues with 32/64 bit kernel
> integration
> using KNI.  If the ethtool interface is not the correct interface then
> please help me
> understand what should/could have been used. If ethtool is considered 'old
> and clunky¹
> Stephen's and your input would be valuable in designing another interface
> with
> similar properties.  The use-case is pretty simple and there is no plans
> for moving
> anything back into the kernel on the contrary its the complete opposite.
> 
> ‹ Andy

We have DPDK API's to do this, and any added wrappers make it bigger.
I don't see why calling your ethtool API is better than calling
rte_eth* API.

If there is a missing functionality in the rte_ethXXX api's for an
application then add that. For example: rte_eth_mac_addr_get()

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-03  2:09                 ` Andrew Harvey (agh)
@ 2015-06-04 14:25                   ` O'Driscoll, Tim
  2015-06-04 14:58                   ` Stephen Hemminger
  1 sibling, 0 replies; 174+ messages in thread
From: O'Driscoll, Tim @ 2015-06-04 14:25 UTC (permalink / raw)
  To: Andrew Harvey (agh),
	Thomas Monjalon, Wang, Liang-min, Stephen Hemminger,
	David Harton (dharton)
  Cc: dev


> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Andrew Harvey (agh)
> Sent: Wednesday, June 3, 2015 3:10 AM
> To: Thomas Monjalon; Wang, Liang-min
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide
> ethtool-alike APIs
> 
> I believe that their is value in this interface for software stacks not
> based on Linux being moved toward DPDK that need simple operations like
> getting the mac address.  Some of these stacks have a dearth of
> resources
> available and dedicating a core/thread to KNI to get/set a mac address
> is considered excessive. There are also issues with 32/64 bit kernel
> integration
> using KNI.  If the ethtool interface is not the correct interface then
> please help me
> understand what should/could have been used. If ethtool is considered
> 'old
> and clunky¹
> Stephen's and your input would be valuable in designing another
> interface
> with
> similar properties.  The use-case is pretty simple and there is no plans
> for moving
> anything back into the kernel on the contrary its the complete opposite.
> 
> < Andy

Stephen, Thomas: I think it was the two of you that originally questioned the justification for including this change. Now that Andy and Dave Harton have clarified, does this resolve your concerns or do you still have questions? I just want to make sure that we reach a timely conclusion on this.


Tim

> 
> 
> On 6/2/15, 1:37 PM, "Thomas Monjalon" <thomas.monjalon@6wind.com> wrote:
> 
> >I have the feeling we are not progressing in this discussion.
> >Please bring new explanations or I'll give up.
> >David Harton already acked it so maybe he could explain why it is
> useful.
> >
> >Comments below
> >
> >2015-06-02 17:06, Wang, Liang-min:
> >> >2015-06-02 15:47, Wang, Liang-min:
> >> >> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> >> >> > >>I'm curious to understand how renaming rte_eth_dev_set_mtu()
> to
> >> >> > >>rte_ethtool_net_change_mtu() will help anyone.
> >> >> >>
> >> >> >> As described, this interface is designed to provide API closely
> >>to kernel space ethtool ops and net_device_op.
> >> >>
> >> >> >But the application still needs to adapt the code to call rte_*
> >>functions.
> >> >> >So changing to rte_ethtool_net_change_mtu is equivalent to change
> >>to the existing rte_eth_dev_set_mtu. I don't see the benefit.
> >> >>
> >> >> The benefit is single interface for users to access. Instead of
> >>looking into two different interfaces (ethtool, ether).
> >> >
> >> >Sorry it doesn't help to understand.
> >> >Today, there is an ethdev API. Why adding an ethtool-like API would
> >>help?
> >>
> >> Need to understand your specific concern. Do you oppose introducing
> new
> >>API to support ethtool ops and net_device_ops?
> >
> >They are not ethtool/netdev ops but fake ones.
> >In linux:
> >	int dev_set_mtu(struct net_device *dev, int new_mtu)
> >In dpdk:
> >	int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
> >So yes, I'm opposed to add an API which is neither ethdev, neither
> >ethtool.
> >But I may be missing an obvious justification.
> >
> >> Or your concern is on the implementation. If that's latter.
> >> Do you oppose adding a new library to implement ethtool ops and
> >>net_device_ops?
> >
> >Already answered above
> >
> >>     If so, are you satisfied with my previous answer on avoiding
> >>polluting ethdev APIs?
> >>         If not, do you suggest integrating ethtool APIs into ethdev
> API?
> >
> >No, it's better as a separate library.
> >
> >>     If not, is your concern on the implementation of common
> >>functionality between ethtool and ethdev APIs?
> >>         If so, as explained, it is designed to provide a unified
> >>interface to assist users to migrate from kernel ethtool/net-device-op
> >>API to DPDK
> >
> >Do you mean it would help migrating some code from kernel space to
> dpdk?
> >How it would help since the functions and data are different from the
> >kernel ones?
> >
> >> BTW, as my reply to Steve's comment, more ops are on their way. This
> >>patch is to open up the interface.
> >
> >Currently they are only some one-liners plus ethtool_drvinfo formatting
> >so there is no real benefit.
> >Why not wait to have more ops implemented?
> >

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-02 20:37               ` Thomas Monjalon
  2015-06-02 20:56                 ` Wang, Liang-min
@ 2015-06-03  2:09                 ` Andrew Harvey (agh)
  2015-06-04 14:25                   ` O'Driscoll, Tim
  2015-06-04 14:58                   ` Stephen Hemminger
  1 sibling, 2 replies; 174+ messages in thread
From: Andrew Harvey (agh) @ 2015-06-03  2:09 UTC (permalink / raw)
  To: Thomas Monjalon, Wang, Liang-min; +Cc: dev

I believe that their is value in this interface for software stacks not
based on Linux being moved toward DPDK that need simple operations like
getting the mac address.  Some of these stacks have a dearth of resources
available and dedicating a core/thread to KNI to get/set a mac address
is considered excessive. There are also issues with 32/64 bit kernel
integration
using KNI.  If the ethtool interface is not the correct interface then
please help me
understand what should/could have been used. If ethtool is considered 'old
and clunky¹
Stephen's and your input would be valuable in designing another interface
with
similar properties.  The use-case is pretty simple and there is no plans
for moving
anything back into the kernel on the contrary its the complete opposite.

‹ Andy


On 6/2/15, 1:37 PM, "Thomas Monjalon" <thomas.monjalon@6wind.com> wrote:

>I have the feeling we are not progressing in this discussion.
>Please bring new explanations or I'll give up.
>David Harton already acked it so maybe he could explain why it is useful.
>
>Comments below
>
>2015-06-02 17:06, Wang, Liang-min:
>> >2015-06-02 15:47, Wang, Liang-min:
>> >> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
>> >> > >>I'm curious to understand how renaming rte_eth_dev_set_mtu() to
>> >> > >>rte_ethtool_net_change_mtu() will help anyone.
>> >> >> 
>> >> >> As described, this interface is designed to provide API closely
>>to kernel space ethtool ops and net_device_op.
>> >> 
>> >> >But the application still needs to adapt the code to call rte_*
>>functions.
>> >> >So changing to rte_ethtool_net_change_mtu is equivalent to change
>>to the existing rte_eth_dev_set_mtu. I don't see the benefit.
>> >> 
>> >> The benefit is single interface for users to access. Instead of
>>looking into two different interfaces (ethtool, ether).
>> >
>> >Sorry it doesn't help to understand.
>> >Today, there is an ethdev API. Why adding an ethtool-like API would
>>help?
>> 
>> Need to understand your specific concern. Do you oppose introducing new
>>API to support ethtool ops and net_device_ops?
>
>They are not ethtool/netdev ops but fake ones.
>In linux:
>	int dev_set_mtu(struct net_device *dev, int new_mtu)
>In dpdk:
>	int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
>So yes, I'm opposed to add an API which is neither ethdev, neither
>ethtool.
>But I may be missing an obvious justification.
>
>> Or your concern is on the implementation. If that's latter.
>> Do you oppose adding a new library to implement ethtool ops and
>>net_device_ops?
>
>Already answered above
>
>>     If so, are you satisfied with my previous answer on avoiding
>>polluting ethdev APIs?
>>         If not, do you suggest integrating ethtool APIs into ethdev API?
>
>No, it's better as a separate library.
>
>>     If not, is your concern on the implementation of common
>>functionality between ethtool and ethdev APIs?
>>         If so, as explained, it is designed to provide a unified
>>interface to assist users to migrate from kernel ethtool/net-device-op
>>API to DPDK
>
>Do you mean it would help migrating some code from kernel space to dpdk?
>How it would help since the functions and data are different from the
>kernel ones?
>
>> BTW, as my reply to Steve's comment, more ops are on their way. This
>>patch is to open up the interface.
>
>Currently they are only some one-liners plus ethtool_drvinfo formatting
>so there is no real benefit.
>Why not wait to have more ops implemented?
>

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-02 20:56                 ` Wang, Liang-min
@ 2015-06-03  1:00                   ` David Harton (dharton)
  0 siblings, 0 replies; 174+ messages in thread
From: David Harton (dharton) @ 2015-06-03  1:00 UTC (permalink / raw)
  To: Wang, Liang-min, Thomas Monjalon; +Cc: dev

Hi Thomas,

I think Larry explains things pretty clearly below.

A new application facing API is bring provided that avoids reusing kernel specific types and structs or dipping into the kernel itself.  It also clearly separates the user space API from driver related functions/types.

We do want to limit dipping into the kernel for performance reasons.

I hope this helps,
Dave

> -----Original Message-----
> From: Wang, Liang-min [mailto:liang-min.wang@intel.com]
> Sent: Tuesday, June 02, 2015 4:56 PM
> To: Thomas Monjalon
> Cc: dev@dpdk.org; David Harton (dharton)
> Subject: RE: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide
> ethtool-alike APIs
> 
> >I have the feeling we are not progressing in this discussion.
> >Please bring new explanations or I'll give up.
> >David Harton already acked it so maybe he could explain why it is useful.
> >
> >Comments below
> >
> >2015-06-02 17:06, Wang, Liang-min:
> >> >2015-06-02 15:47, Wang, Liang-min:
> >> >> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> >> >> > >>I'm curious to understand how renaming rte_eth_dev_set_mtu()
> >> >> > >>to
> >> >> > >>rte_ethtool_net_change_mtu() will help anyone.
> >> >> >>
> >> >> >> As described, this interface is designed to provide API closely
> to kernel space ethtool ops and net_device_op.
> >> >>
> >> >> >But the application still needs to adapt the code to call rte_*
> functions.
> >> >> >So changing to rte_ethtool_net_change_mtu is equivalent to change
> to the existing rte_eth_dev_set_mtu. I don't see the benefit.
> >> >>
> >> >> The benefit is single interface for users to access. Instead of
> looking into two different interfaces (ethtool, ether).
> >> >
> >> >Sorry it doesn't help to understand.
> >> >Today, there is an ethdev API. Why adding an ethtool-like API would
> help?
> >>
> >> Need to understand your specific concern. Do you oppose introducing new
> API to support ethtool ops and net_device_ops?
> >
> >They are not ethtool/netdev ops but fake ones.
> >In linux:
> >	int dev_set_mtu(struct net_device *dev, int new_mtu) In dpdk:
> >	int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu); So yes,
> I'm opposed to add an API which is neither ethdev, neither ethtool.
> >But I may be missing an obvious justification.
> 
> So, the design purposely stays away from struct net_device to avoid
> carrying kernel states. We consciously choose port in place of net_device.
> The kni already provides ethtool for kernel space code, this interface is
> designed for user-space application (fast-path comparing to kni).
> 
> >> Or your concern is on the implementation. If that's latter.
> >> Do you oppose adding a new library to implement ethtool ops and
> net_device_ops?
> >
> >Already answered above
> >>
> >>     If so, are you satisfied with my previous answer on avoiding
> polluting ethdev APIs?
> >>         If not, do you suggest integrating ethtool APIs into ethdev
> API?
> >
> >No, it's better as a separate library.
> >
> >>     If not, is your concern on the implementation of common
> functionality between ethtool and ethdev APIs?
> >>         If so, as explained, it is designed to provide a unified
> >> interface to assist users to migrate from kernel
> >> ethtool/net-device-op API to DPDK
> >
> >Do you mean it would help migrating some code from kernel space to dpdk?
> >How it would help since the functions and data are different from the
> kernel ones?
> 
> For application that was designed based upon kernel-space ethtool-op and
> net-device-op, the user-space APIs provide a path for quick integration.
> 
> >> BTW, as my reply to Steve's comment, more ops are on their way. This
> patch is to open up the interface.
> >
> >Currently they are only some one-liners plus ethtool_drvinfo formatting
> so there is no real benefit.
> >Why not wait to have more ops implemented?
> Due to amount of code change, I was advised to put into separate release
> and started with APIs that only requires minor changes on ethdev.
> The rest of API requires changes on NIC pmd driver to support ops that are
> not currently supported.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-02 20:37               ` Thomas Monjalon
@ 2015-06-02 20:56                 ` Wang, Liang-min
  2015-06-03  1:00                   ` David Harton (dharton)
  2015-06-03  2:09                 ` Andrew Harvey (agh)
  1 sibling, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-02 20:56 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

>I have the feeling we are not progressing in this discussion.
>Please bring new explanations or I'll give up.
>David Harton already acked it so maybe he could explain why it is useful.
>
>Comments below
>
>2015-06-02 17:06, Wang, Liang-min:
>> >2015-06-02 15:47, Wang, Liang-min:
>> >> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
>> >> > >>I'm curious to understand how renaming rte_eth_dev_set_mtu() to
>> >> > >>rte_ethtool_net_change_mtu() will help anyone.
>> >> >> 
>> >> >> As described, this interface is designed to provide API closely to kernel space ethtool ops and net_device_op.
>> >> 
>> >> >But the application still needs to adapt the code to call rte_* functions.
>> >> >So changing to rte_ethtool_net_change_mtu is equivalent to change to the existing rte_eth_dev_set_mtu. I don't see the benefit.
>> >> 
>> >> The benefit is single interface for users to access. Instead of looking into two different interfaces (ethtool, ether). 
>> >
>> >Sorry it doesn't help to understand.
>> >Today, there is an ethdev API. Why adding an ethtool-like API would help?
>> 
>> Need to understand your specific concern. Do you oppose introducing new API to support ethtool ops and net_device_ops? 
>
>They are not ethtool/netdev ops but fake ones.
>In linux:
>	int dev_set_mtu(struct net_device *dev, int new_mtu) In dpdk:
>	int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu); So yes, I'm opposed to add an API which is neither ethdev, neither ethtool.
>But I may be missing an obvious justification.

So, the design purposely stays away from struct net_device to avoid carrying kernel states. We consciously choose port in place of net_device.
The kni already provides ethtool for kernel space code, this interface is designed for user-space application (fast-path comparing to kni).

>> Or your concern is on the implementation. If that's latter. 
>> Do you oppose adding a new library to implement ethtool ops and net_device_ops?
>
>Already answered above
>>
>>     If so, are you satisfied with my previous answer on avoiding polluting ethdev APIs? 
>>         If not, do you suggest integrating ethtool APIs into ethdev API?
>
>No, it's better as a separate library.
>
>>     If not, is your concern on the implementation of common functionality between ethtool and ethdev APIs?
>>         If so, as explained, it is designed to provide a unified 
>> interface to assist users to migrate from kernel ethtool/net-device-op 
>> API to DPDK
>
>Do you mean it would help migrating some code from kernel space to dpdk?
>How it would help since the functions and data are different from the kernel ones?

For application that was designed based upon kernel-space ethtool-op and net-device-op, the user-space APIs provide a path for quick integration.

>> BTW, as my reply to Steve's comment, more ops are on their way. This patch is to open up the interface.
>
>Currently they are only some one-liners plus ethtool_drvinfo formatting so there is no real benefit.
>Why not wait to have more ops implemented?
Due to amount of code change, I was advised to put into separate release and started with APIs that only requires minor changes on ethdev.
The rest of API requires changes on NIC pmd driver to support ops that are not currently supported.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-02 17:06             ` Wang, Liang-min
@ 2015-06-02 20:37               ` Thomas Monjalon
  2015-06-02 20:56                 ` Wang, Liang-min
  2015-06-03  2:09                 ` Andrew Harvey (agh)
  0 siblings, 2 replies; 174+ messages in thread
From: Thomas Monjalon @ 2015-06-02 20:37 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

I have the feeling we are not progressing in this discussion.
Please bring new explanations or I'll give up.
David Harton already acked it so maybe he could explain why it is useful.

Comments below

2015-06-02 17:06, Wang, Liang-min:
> >2015-06-02 15:47, Wang, Liang-min:
> >> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com] 
> >> > >>I'm curious to understand how renaming rte_eth_dev_set_mtu() to
> >> > >>rte_ethtool_net_change_mtu() will help anyone.
> >> >> 
> >> >> As described, this interface is designed to provide API closely to kernel space ethtool ops and net_device_op.
> >> 
> >> >But the application still needs to adapt the code to call rte_* functions.
> >> >So changing to rte_ethtool_net_change_mtu is equivalent to change to the existing rte_eth_dev_set_mtu. I don't see the benefit.
> >> 
> >> The benefit is single interface for users to access. Instead of looking into two different interfaces (ethtool, ether). 
> >
> >Sorry it doesn't help to understand.
> >Today, there is an ethdev API. Why adding an ethtool-like API would help?
> 
> Need to understand your specific concern. Do you oppose introducing new API to support ethtool ops and net_device_ops? 

They are not ethtool/netdev ops but fake ones.
In linux:
	int dev_set_mtu(struct net_device *dev, int new_mtu)
In dpdk:
	int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
So yes, I'm opposed to add an API which is neither ethdev, neither ethtool.
But I may be missing an obvious justification.

> Or your concern is on the implementation. If that's latter. 
> Do you oppose adding a new library to implement ethtool ops and net_device_ops?

Already answered above

>     If so, are you satisfied with my previous answer on avoiding polluting ethdev APIs? 
>         If not, do you suggest integrating ethtool APIs into ethdev API?

No, it's better as a separate library.

>     If not, is your concern on the implementation of common functionality between ethtool and ethdev APIs?
>         If so, as explained, it is designed to provide a unified interface to assist users to migrate from kernel ethtool/net-device-op API to DPDK

Do you mean it would help migrating some code from kernel space to dpdk?
How it would help since the functions and data are different from the kernel ones?

> BTW, as my reply to Steve's comment, more ops are on their way. This patch is to open up the interface.

Currently they are only some one-liners plus ethtool_drvinfo formatting
so there is no real benefit.
Why not wait to have more ops implemented?

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-02 16:02           ` Thomas Monjalon
@ 2015-06-02 17:06             ` Wang, Liang-min
  2015-06-02 20:37               ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-02 17:06 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

>2015-06-02 15:47, Wang, Liang-min:
>> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com] 
>> > >>I'm curious to understand how renaming rte_eth_dev_set_mtu() to
>> > >>rte_ethtool_net_change_mtu() will help anyone.
>> >> 
>> >> As described, this interface is designed to provide API closely to kernel space ethtool ops and net_device_op.
>> 
>> >But the application still needs to adapt the code to call rte_* functions.
>> >So changing to rte_ethtool_net_change_mtu is equivalent to change to the existing rte_eth_dev_set_mtu. I don't see the benefit.
>> 
>> The benefit is single interface for users to access. Instead of looking into two different interfaces (ethtool, ether). 
>
>Sorry it doesn't help to understand.
>Today, there is an ethdev API. Why adding an ethtool-like API would help?

Need to understand your specific concern. Do you oppose introducing new API to support ethtool ops and net_device_ops? 
Or your concern is on the implementation. If that's latter. 
Do you oppose adding a new library to implement ethtool ops and net_device_ops?
    If so, are you satisfied with my previous answer on avoiding polluting ethdev APIs? 
        If not, do you suggest integrating ethtool APIs into ethdev API?
    If not, is your concern on the implementation of common functionality between ethtool and ethdev APIs?
        If so, as explained, it is designed to provide a unified interface to assist users to migrate from kernel ethtool/net-device-op API to DPDK
BTW, as my reply to Steve's comment, more ops are on their way. This patch is to open up the interface.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-02 15:47         ` Wang, Liang-min
@ 2015-06-02 16:02           ` Thomas Monjalon
  2015-06-02 17:06             ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Thomas Monjalon @ 2015-06-02 16:02 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

2015-06-02 15:47, Wang, Liang-min:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com] 
> > >>I'm curious to understand how renaming rte_eth_dev_set_mtu() to
> > >>rte_ethtool_net_change_mtu() will help anyone.
> >> 
> >> As described, this interface is designed to provide API closely to kernel space ethtool ops and net_device_op.
> 
> >But the application still needs to adapt the code to call rte_* functions.
> >So changing to rte_ethtool_net_change_mtu is equivalent to change to the existing rte_eth_dev_set_mtu. I don't see the benefit.
> 
> The benefit is single interface for users to access. Instead of looking into two different interfaces (ethtool, ether). 

Sorry it doesn't help to understand.
Today, there is an ethdev API. Why adding an ethtool-like API would help?

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-02 14:32       ` Thomas Monjalon
@ 2015-06-02 15:47         ` Wang, Liang-min
  2015-06-02 16:02           ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-02 15:47 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



-----Original Message-----
From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com] 
Sent: Tuesday, June 02, 2015 10:33 AM
To: Wang, Liang-min
Cc: dev@dpdk.org
Subject: Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs

>Wang, hope it's clear that any new development is welcomed.
>One step before integration is to clearly explain why your code is needed. That's why a nack vote may help to discuss and decide.
>
>Comments below
>
>2015-06-02 13:15, Wang, Liang-min:
> >>2015-05-29 15:26, Liang-Min Larry Wang:
> >>> adding a new library based upon ethdev APIs to provide API's that 
> >>> bear the same functionality as ethtool_ops (linux/ethtool.h) and 
> >>> net_device_ops (linux/netdevice.h).
> >>> 
> >>> Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> >>> ---
> >>>  MAINTAINERS                                |   4 +
> >>>  config/common_linuxapp                     |   5 +
> >>>  lib/Makefile                               |   1 +
> >>>  lib/librte_ethtool/Makefile                |  56 +++++++
> >>>  lib/librte_ethtool/rte_ethtool.c           | 155 +++++++++++++++++
> >>>  lib/librte_ethtool/rte_ethtool.h           | 257 +++++++++++++++++++++++++++++
> >>>  lib/librte_ethtool/rte_ethtool_version.map |  18 ++
> >>>  mk/rte.app.mk                              |   1 +
> >>
> >>NACK for several reasons:
> >>- It's unclear what benefits this ethdev wrapper is bringing
>> 
>> Since ethtool is provided to assist users migrating from kernel ethtool/net_device_op based design to user-space DPDK device management. The ethtool API's are created to closely maintain its original interface, therefore this library depends on <linux/ethool.h>. To avoid pollute the existing ethdev interface, a new library is created. To minimize code replication and maintain closely 1:1 API definition with kernel space API, this interface is designed based upon available ethdev APIs and add additional dev_ops if it's necessary.
>> 
> >>- There is no obvious interest (how is it supposed to be used?)
>> There are already two acknowledge on this release. Earlier comment on this patch has that " ... The API's for ethtool like things are valuable ..."

>Stephen had some doubts about the real need and 2 people from Cisco (who never contributed before) give their ack without justification.
>Saying it's "valuable" or "very useful" is not enough.
>A new library needs to demonstrate in which scenario the added-value is.
>Sorry but you have to prove that it deserves to be maintained inside the dpdk project.

Not sure if the question is the usefulness of user-space ethtool (there was request for user-space ethtool @ dpdk.org last year, right, and Steve's comment ...) or the question on putting ethtool on separate library. For the latter concern, as described, the design is to avoid polluting ethdev library by this inevitable including <linux/ethtool.h>

>> >- There is no update in the doc/ directory
>> Need more guidance on that.

>You probably have to add a new chapter in the programmer's guide.

Sure, I would help doc team adding new section into programmer's guide and other if it's necessary. The first thing is to have this API approved for release first.

> >>Other comments:
> >>- the patches are not versioned
>> 
>> There is version file. Not sure what do you mean "the patches are not versioned"

>I mean there is no v2/v3 in the Subject. Please read
>	http://dpdk.org/dev#send

My bad, I will address this issue on next patch

> >>- the copyright starts in 2010
>> 
>> Will fix that.
>> 
> >>I'm curious to understand how renaming rte_eth_dev_set_mtu() to
> >>rte_ethtool_net_change_mtu() will help anyone.
>> 
>> As described, this interface is designed to provide API closely to kernel space ethtool ops and net_device_op.

>But the application still needs to adapt the code to call rte_* functions.
>So changing to rte_ethtool_net_change_mtu is equivalent to change to the existing rte_eth_dev_set_mtu. I don't see the benefit.

The benefit is single interface for users to access. Instead of looking into two different interfaces (ethtool, ether). 

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-02 13:15     ` Wang, Liang-min
@ 2015-06-02 14:32       ` Thomas Monjalon
  2015-06-02 15:47         ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Thomas Monjalon @ 2015-06-02 14:32 UTC (permalink / raw)
  To: Wang, Liang-min; +Cc: dev

Wang, hope it's clear that any new development is welcomed.
One step before integration is to clearly explain why your code
is needed. That's why a nack vote may help to discuss and decide.

Comments below

2015-06-02 13:15, Wang, Liang-min:
> >2015-05-29 15:26, Liang-Min Larry Wang:
> >> adding a new library based upon ethdev APIs to provide API's that bear 
> >> the same functionality as ethtool_ops (linux/ethtool.h) and 
> >> net_device_ops (linux/netdevice.h).
> >> 
> >> Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> >> ---
> >>  MAINTAINERS                                |   4 +
> >>  config/common_linuxapp                     |   5 +
> >>  lib/Makefile                               |   1 +
> >>  lib/librte_ethtool/Makefile                |  56 +++++++
> >>  lib/librte_ethtool/rte_ethtool.c           | 155 +++++++++++++++++
> >>  lib/librte_ethtool/rte_ethtool.h           | 257 +++++++++++++++++++++++++++++
> >>  lib/librte_ethtool/rte_ethtool_version.map |  18 ++
> >>  mk/rte.app.mk                              |   1 +
> >
> >NACK for several reasons:
> >- It's unclear what benefits this ethdev wrapper is bringing
> 
> Since ethtool is provided to assist users migrating from kernel ethtool/net_device_op based design to user-space DPDK device management. The ethtool API's are created to closely maintain its original interface, therefore this library depends on <linux/ethool.h>. To avoid pollute the existing ethdev interface, a new library is created. To minimize code replication and maintain closely 1:1 API definition with kernel space API, this interface is designed based upon available ethdev APIs and add additional dev_ops if it's necessary.
> 
> >- There is no obvious interest (how is it supposed to be used?)
> There are already two acknowledge on this release. Earlier comment on this patch has that " ... The API's for ethtool like things are valuable ..."

Stephen had some doubts about the real need and 2 people from Cisco
(who never contributed before) give their ack without justification.
Saying it's "valuable" or "very useful" is not enough.
A new library needs to demonstrate in which scenario the added-value is.
Sorry but you have to prove that it deserves to be maintained inside
the dpdk project.

> >- There is no update in the doc/ directory
> Need more guidance on that.

You probably have to add a new chapter in the programmer's guide.

> >Other comments:
> >- the patches are not versioned
> 
> There is version file. Not sure what do you mean "the patches are not versioned"

I mean there is no v2/v3 in the Subject. Please read
	http://dpdk.org/dev#send

> >- the copyright starts in 2010
> 
> Will fix that.
> 
> >I'm curious to understand how renaming rte_eth_dev_set_mtu() to
> >rte_ethtool_net_change_mtu() will help anyone.
> 
> As described, this interface is designed to provide API closely to kernel space ethtool ops and net_device_op.

But the application still needs to adapt the code to call rte_* functions.
So changing to rte_ethtool_net_change_mtu is equivalent to change to
the existing rte_eth_dev_set_mtu. I don't see the benefit.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-06-02 12:38   ` Thomas Monjalon
@ 2015-06-02 13:15     ` Wang, Liang-min
  2015-06-02 14:32       ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Wang, Liang-min @ 2015-06-02 13:15 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev


>2015-05-29 15:26, Liang-Min Larry Wang:
>> adding a new library based upon ethdev APIs to provide API's that bear 
>> the same functionality as ethtool_ops (linux/ethtool.h) and 
>> net_device_ops (linux/netdevice.h).
>> 
>> Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
>> ---
>>  MAINTAINERS                                |   4 +
>>  config/common_linuxapp                     |   5 +
>>  lib/Makefile                               |   1 +
>>  lib/librte_ethtool/Makefile                |  56 +++++++
>>  lib/librte_ethtool/rte_ethtool.c           | 155 +++++++++++++++++
>>  lib/librte_ethtool/rte_ethtool.h           | 257 +++++++++++++++++++++++++++++
>>  lib/librte_ethtool/rte_ethtool_version.map |  18 ++
>>  mk/rte.app.mk                              |   1 +
>
>NACK for several reasons:
>- It's unclear what benefits this ethdev wrapper is bringing

Since ethtool is provided to assist users migrating from kernel ethtool/net_device_op based design to user-space DPDK device management. The ethtool API's are created to closely maintain its original interface, therefore this library depends on <linux/ethool.h>. To avoid pollute the existing ethdev interface, a new library is created. To minimize code replication and maintain closely 1:1 API definition with kernel space API, this interface is designed based upon available ethdev APIs and add additional dev_ops if it's necessary.

>- There is no obvious interest (how is it supposed to be used?)
There are already two acknowledge on this release. Earlier comment on this patch has that " ... The API's for ethtool like things are valuable ..."

>- There is no update in the doc/ directory
Need more guidance on that.

>Other comments:
>- the patches are not versioned

There is version file. Not sure what do you mean "the patches are not versioned"

>- the copyright starts in 2010

Will fix that.

>I'm curious to understand how renaming rte_eth_dev_set_mtu() to
>rte_ethtool_net_change_mtu() will help anyone.

As described, this interface is designed to provide API closely to kernel space ethtool ops and net_device_op.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-29 19:26 ` [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs Liang-Min Larry Wang
@ 2015-06-02 12:38   ` Thomas Monjalon
  2015-06-02 13:15     ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Thomas Monjalon @ 2015-06-02 12:38 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev

2015-05-29 15:26, Liang-Min Larry Wang:
> adding a new library based upon ethdev APIs to provide API's that bear
> the same functionality as ethtool_ops (linux/ethtool.h) and net_device_ops
> (linux/netdevice.h).
> 
> Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
> ---
>  MAINTAINERS                                |   4 +
>  config/common_linuxapp                     |   5 +
>  lib/Makefile                               |   1 +
>  lib/librte_ethtool/Makefile                |  56 +++++++
>  lib/librte_ethtool/rte_ethtool.c           | 155 +++++++++++++++++
>  lib/librte_ethtool/rte_ethtool.h           | 257 +++++++++++++++++++++++++++++
>  lib/librte_ethtool/rte_ethtool_version.map |  18 ++
>  mk/rte.app.mk                              |   1 +

NACK for several reasons:
- It's unclear what benefits this ethdev wrapper is bringing
- There is no obvious interest (how is it supposed to be used?)
- There is no update in the doc/ directory

Other comments:
- the patches are not versionned
- the copyright starts in 2010

I'm curious to understand how renaming rte_eth_dev_set_mtu() to
rte_ethtool_net_change_mtu() will help anyone.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-29 19:26 [dpdk-dev] [PATCH 0/2] " Liang-Min Larry Wang
@ 2015-05-29 19:26 ` Liang-Min Larry Wang
  2015-06-02 12:38   ` Thomas Monjalon
  0 siblings, 1 reply; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-05-29 19:26 UTC (permalink / raw)
  To: dev; +Cc: Liang-Min Larry Wang

adding a new library based upon ethdev APIs to provide API's that bear
the same functionality as ethtool_ops (linux/ethtool.h) and net_device_ops
(linux/netdevice.h).

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 MAINTAINERS                                |   4 +
 config/common_linuxapp                     |   5 +
 lib/Makefile                               |   1 +
 lib/librte_ethtool/Makefile                |  56 +++++++
 lib/librte_ethtool/rte_ethtool.c           | 155 +++++++++++++++++
 lib/librte_ethtool/rte_ethtool.h           | 257 +++++++++++++++++++++++++++++
 lib/librte_ethtool/rte_ethtool_version.map |  18 ++
 mk/rte.app.mk                              |   1 +
 8 files changed, 497 insertions(+)
 create mode 100644 lib/librte_ethtool/Makefile
 create mode 100644 lib/librte_ethtool/rte_ethtool.c
 create mode 100644 lib/librte_ethtool/rte_ethtool.h
 create mode 100644 lib/librte_ethtool/rte_ethtool_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 9362c19..b8b481f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -186,6 +186,10 @@ M: Thomas Monjalon <thomas.monjalon@6wind.com>
 F: lib/librte_ether/
 F: scripts/test-null.sh
 
+Ethtool API
+M: Liang-Min Larry Wang <liang-min.wang@intel.com>
+F: lib/librte_ethtool/
+
 
 Drivers
 -------
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 0078dc9..f5759fd 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -129,6 +129,11 @@ CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y
 CONFIG_RTE_LIBRTE_KVARGS=y
 
 #
+# Compile user-space ethtool library
+#
+CONFIG_RTE_LIBRTE_ETHTOOL=y
+
+#
 # Compile generic ethernet library
 #
 CONFIG_RTE_LIBRTE_ETHER=y
diff --git a/lib/Makefile b/lib/Makefile
index 5f480f9..a6c7375 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -41,6 +41,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_TIMER) += librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_CFGFILE) += librte_cfgfile
 DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
+DIRS-$(CONFIG_RTE_LIBRTE_ETHTOOL) += librte_ethtool
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
diff --git a/lib/librte_ethtool/Makefile b/lib/librte_ethtool/Makefile
new file mode 100644
index 0000000..1d981f6
--- /dev/null
+++ b/lib/librte_ethtool/Makefile
@@ -0,0 +1,56 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_ethtool.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_ethtool_version.map
+
+LIBABIVER := 1
+
+SRCS-y += rte_ethtool.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_ethtool.h
+
+# this lib depends upon:
+DEPDIRS-y += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ethtool/rte_ethtool.c b/lib/librte_ethtool/rte_ethtool.c
new file mode 100644
index 0000000..2ccf06f
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.c
@@ -0,0 +1,155 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/lib/librte_ethtool/rte_ethtool.h b/lib/librte_ethtool/rte_ethtool.h
new file mode 100644
index 0000000..cb68d94
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.h
@@ -0,0 +1,257 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::ndo_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/lib/librte_ethtool/rte_ethtool_version.map b/lib/librte_ethtool/rte_ethtool_version.map
new file mode 100644
index 0000000..82fc0d3
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool_version.map
@@ -0,0 +1,18 @@
+DPDK_2.0 {
+	global:
+
+	rte_ethtool_net_open;
+	rte_ethtool_net_stop;
+	rte_ethtool_net_get_mac_addr;
+	rte_ethtool_net_get_mac_addr;
+	rte_ethtool_net_validate_addr;
+	rte_ethtool_net_set_config;
+	rte_ethtool_net_change_mtu;
+	rte_ethtool_net_get_stats64;
+	rte_ethtool_net_vlan_rx_add_vid;
+	rte_ethtool_net_vlan_rx_kill_vid;
+	rte_ethtool_get_drvinfo;
+	rte_ethtool_get_link;
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 1a2043a..86867a6 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -105,6 +105,7 @@ ifeq ($(CONFIG_RTE_BUILD_COMBINE_LIBS),n)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS)         += -lrte_kvargs
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
+_LDLIBS-$(CONFIG_RTE_LIBRTE_ETHTOOL)        += -lrte_ethtool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MALLOC)         += -lrte_malloc
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-29 15:22   ` Stephen Hemminger
@ 2015-05-29 18:17     ` Wang, Liang-min
  0 siblings, 0 replies; 174+ messages in thread
From: Wang, Liang-min @ 2015-05-29 18:17 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev, bruce.richardson


>On Fri, 29 May 2015 09:15:09 -0400
>Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:
>
>> +	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
> >+	drvinfo->testinfo_len = 0;
>
>
>Providing a hook to access more functionality is good and compatiablity with old API's is helpful.  Too bad ethtool is kind of a clunky old inflexible, and easily broken with changes. But >that is not your fault.
>
>Duplicating eth_stats in ethtool is not helpful.
>This is actively discouraged for Linux device drivers.

(I have a typo of David's email, and I corrected it in this email)
This new library is designed to support ethtool alike interface, some of the implementation will be just a placeholder. The rte_ethtool_net_get_stats64 is designed as a place holder to support net_device_ops::ndo_get_stats64. For the legacy support, it is required to provide # of statistic parameters are supported, so caller can allocate right size of buffer to get statistic from device driver.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-29 13:15 ` [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs Liang-Min Larry Wang
@ 2015-05-29 15:22   ` Stephen Hemminger
  2015-05-29 18:17     ` Wang, Liang-min
  0 siblings, 1 reply; 174+ messages in thread
From: Stephen Hemminger @ 2015-05-29 15:22 UTC (permalink / raw)
  To: Liang-Min Larry Wang; +Cc: dev, aharton, bruce.richardson

On Fri, 29 May 2015 09:15:09 -0400
Liang-Min Larry Wang <liang-min.wang@intel.com> wrote:

> +	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
> +	drvinfo->testinfo_len = 0;


Providing a hook to access more functionality is good and compatiablity
with old API's is helpful.  Too bad ethtool is kind of a clunky old
inflexible, and easily broken with changes. But that is not your fault.

Duplicating eth_stats in ethtool is not helpful.
This is actively discouraged for Linux device drivers.

^ permalink raw reply	[flat|nested] 174+ messages in thread

* [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs
  2015-05-29 13:15 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
@ 2015-05-29 13:15 ` Liang-Min Larry Wang
  2015-05-29 15:22   ` Stephen Hemminger
  0 siblings, 1 reply; 174+ messages in thread
From: Liang-Min Larry Wang @ 2015-05-29 13:15 UTC (permalink / raw)
  To: dev; +Cc: aharton, bruce.richardson, Liang-Min Larry Wang

adding a new library based upon ethdev APIs to provide API's that bear
the same functionality as ethtool_ops (linux/ethtool.h) and net_device_ops
(linux/netdevice.h).

Signed-off-by: Liang-Min Larry Wang <liang-min.wang@intel.com>
---
 MAINTAINERS                                |   4 +
 config/common_linuxapp                     |   5 +
 lib/Makefile                               |   1 +
 lib/librte_ethtool/Makefile                |  56 +++++++
 lib/librte_ethtool/rte_ethtool.c           | 155 +++++++++++++++++
 lib/librte_ethtool/rte_ethtool.h           | 257 +++++++++++++++++++++++++++++
 lib/librte_ethtool/rte_ethtool_version.map |  18 ++
 mk/rte.app.mk                              |   1 +
 8 files changed, 497 insertions(+)
 create mode 100644 lib/librte_ethtool/Makefile
 create mode 100644 lib/librte_ethtool/rte_ethtool.c
 create mode 100644 lib/librte_ethtool/rte_ethtool.h
 create mode 100644 lib/librte_ethtool/rte_ethtool_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 9362c19..b8b481f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -186,6 +186,10 @@ M: Thomas Monjalon <thomas.monjalon@6wind.com>
 F: lib/librte_ether/
 F: scripts/test-null.sh
 
+Ethtool API
+M: Liang-Min Larry Wang <liang-min.wang@intel.com>
+F: lib/librte_ethtool/
+
 
 Drivers
 -------
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 0078dc9..f5759fd 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -129,6 +129,11 @@ CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y
 CONFIG_RTE_LIBRTE_KVARGS=y
 
 #
+# Compile user-space ethtool library
+#
+CONFIG_RTE_LIBRTE_ETHTOOL=y
+
+#
 # Compile generic ethernet library
 #
 CONFIG_RTE_LIBRTE_ETHER=y
diff --git a/lib/Makefile b/lib/Makefile
index 5f480f9..a6c7375 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -41,6 +41,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_TIMER) += librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_CFGFILE) += librte_cfgfile
 DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
+DIRS-$(CONFIG_RTE_LIBRTE_ETHTOOL) += librte_ethtool
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
 DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
diff --git a/lib/librte_ethtool/Makefile b/lib/librte_ethtool/Makefile
new file mode 100644
index 0000000..1d981f6
--- /dev/null
+++ b/lib/librte_ethtool/Makefile
@@ -0,0 +1,56 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_ethtool.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_ethtool_version.map
+
+LIBABIVER := 1
+
+SRCS-y += rte_ethtool.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_ethtool.h
+
+# this lib depends upon:
+DEPDIRS-y += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ethtool/rte_ethtool.c b/lib/librte_ethtool/rte_ethtool.c
new file mode 100644
index 0000000..2ccf06f
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.c
@@ -0,0 +1,155 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	snprintf(drvinfo->driver, sizeof(drvinfo->driver), "%s",
+		dev_info.driver_name);
+	snprintf(drvinfo->version, sizeof(drvinfo->version), "%s",
+		rte_version());
+	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+		"%04x:%02x:%02x.%x",
+		dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus,
+		dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
+
+	drvinfo->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	drvinfo->testinfo_len = 0;
+
+	return 0;
+}
+
+int
+rte_ethtool_get_link(uint8_t port_id)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+	return link.link_status;
+}
+
+int
+rte_ethtool_net_open(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return rte_eth_dev_start(port_id);
+}
+
+int
+rte_ethtool_net_stop(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	return rte_eth_dev_default_mac_addr_set(port_id, addr);
+}
+
+int
+rte_ethtool_net_validate_addr(uint8_t port_id __rte_unused,
+	struct ether_addr *addr)
+{
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_set_config(uint8_t port_id, void *config __rte_unused)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == 1)
+		return -EINVAL;
+	return 0;
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	return rte_eth_dev_set_mtu(port_id, (uint16_t)mtu);
+}
+
+int
+rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats)
+{
+	return rte_eth_stats_get(port_id, stats);
+}
+
+int
+rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 1);
+}
+
+int
+rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid)
+{
+	return rte_eth_dev_vlan_filter(port_id, vid, 0);
+}
+
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id __rte_unused)
+{
+	/*
+	 * The set_rx_mode op is part of pmd driver start operation, and
+	 * the ethdev api maintains software configuration parameters and under-
+	 * line hardware states consistent, so no operation is needed for
+	 * rte_ethtool_net_set_rx_mode().
+	 */
+	return 0;
+}
diff --git a/lib/librte_ethtool/rte_ethtool.h b/lib/librte_ethtool/rte_ethtool.h
new file mode 100644
index 0000000..0488e8e
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.h
@@ -0,0 +1,257 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHTOOL_H_
+#define _RTE_ETHTOOL_H_
+
+/*
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_driver:          ethtool_ops::get_driverinfo
+ * rte_ethtool_get_link:            ethtool_ops::get_link
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr
+ * rte_ethtool_net_set_config:      net_device_ops::ndo_set_config
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <rte_ethdev.h>
+#include <linux/ethtool.h>
+
+/**
+ * Retrieve the Ethernet device driver information according to attributes described by
+ * ethtool data structure, ethtool_drvinfo
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param drvinfo
+ *   A pointer to get driver information
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo);
+
+/**
+ * Retrieve the Ethernet device link status
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (1) if link up.
+ *   - (0) if link down.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_get_link(uint8_t port_id);
+
+/**
+ * Start the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_open(uint8_t port_id);
+
+/**
+ * Stop the Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_stop(uint8_t port_id);
+
+/**
+ * Get the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 MAC address of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device MAC address.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 The new MAC addr.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Validate if the provided MAC address is valid unicast address
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param addr
+ *	 A pointer to a buffer (6-byte, 48bit) for the target MAC address
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_validate_addr(uint8_t port_id, struct ether_addr *addr);
+
+/**
+ * Setting the Ethernet device configuration.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param config
+ *	 A opintr to a configuration parameter.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_config(uint8_t port_id, void *config);
+
+/**
+ * Setting the Ethernet device maximum Tx unit.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mtu
+ *	 New MTU
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_change_mtu(uint8_t port_id, int mtu);
+
+/**
+ * Retrieve the Ethernet device traffic statistics
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param stats
+ *	 A pointer to struct rte_eth_stats for statistics parameters
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_get_stats64(uint8_t port_id, struct rte_eth_stats *stats);
+
+/**
+ * Update the Ethernet device VLAN filter with new vid
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_add_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Remove VLAN id from Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param vid
+ *	 A new VLAN id
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_vlan_rx_kill_vid(uint8_t port_id, uint16_t vid);
+
+/**
+ * Setting the Ethernet device rx mode.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_ethtool_net_set_rx_mode(uint8_t port_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/lib/librte_ethtool/rte_ethtool_version.map b/lib/librte_ethtool/rte_ethtool_version.map
new file mode 100644
index 0000000..82fc0d3
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool_version.map
@@ -0,0 +1,18 @@
+DPDK_2.0 {
+	global:
+
+	rte_ethtool_net_open;
+	rte_ethtool_net_stop;
+	rte_ethtool_net_get_mac_addr;
+	rte_ethtool_net_get_mac_addr;
+	rte_ethtool_net_validate_addr;
+	rte_ethtool_net_set_config;
+	rte_ethtool_net_change_mtu;
+	rte_ethtool_net_get_stats64;
+	rte_ethtool_net_vlan_rx_add_vid;
+	rte_ethtool_net_vlan_rx_kill_vid;
+	rte_ethtool_get_drvinfo;
+	rte_ethtool_get_link;
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 1a2043a..86867a6 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -105,6 +105,7 @@ ifeq ($(CONFIG_RTE_BUILD_COMBINE_LIBS),n)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS)         += -lrte_kvargs
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
+_LDLIBS-$(CONFIG_RTE_LIBRTE_ETHTOOL)        += -lrte_ethtool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MALLOC)         += -lrte_malloc
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
-- 
2.1.4

^ permalink raw reply	[flat|nested] 174+ messages in thread

end of thread, other threads:[~2015-07-16 22:15 UTC | newest]

Thread overview: 174+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-30  0:37 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
2015-05-30  0:37 ` [dpdk-dev] [PATCH 1/2] ethdev: add api to set default mac address Liang-Min Larry Wang
2015-05-30  1:57   ` Andrew Harvey (agh)
2015-05-30  0:37 ` [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs Liang-Min Larry Wang
2015-05-30 15:48   ` Stephen Hemminger
2015-05-30 16:16     ` Wang, Liang-min
2015-05-30 19:26       ` Stephen Hemminger
2015-05-30 19:40         ` Wang, Liang-min
2015-05-31 16:48           ` Stephen Hemminger
2015-05-31 17:30             ` Wang, Liang-min
2015-05-31 18:31             ` Wang, Liang-min
2015-06-01 12:42   ` David Harton (dharton)
2015-06-10 15:09 ` [dpdk-dev] [PATCH v4 0/4] User-space Ethtool Liang-Min Larry Wang
2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-06-10 15:21     ` David Harton (dharton)
2015-06-11 12:26     ` Ananyev, Konstantin
2015-06-11 12:57       ` Wang, Liang-min
2015-06-11 13:07         ` Ananyev, Konstantin
2015-06-11 21:51           ` Wang, Liang-min
2015-06-12 12:30             ` Ananyev, Konstantin
2015-06-15 13:26               ` Wang, Liang-min
2015-06-15 13:45                 ` Ananyev, Konstantin
2015-06-15 14:47                   ` Wang, Liang-min
2015-06-15 18:10                     ` Ananyev, Konstantin
2015-06-17 17:25                       ` Ananyev, Konstantin
2015-06-15 16:05                   ` David Harton (dharton)
2015-06-15 18:23                     ` Ananyev, Konstantin
2015-06-16 18:15                       ` Ananyev, Konstantin
2015-06-11 13:14         ` Ananyev, Konstantin
2015-06-11 13:25           ` Wang, Liang-min
2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 3/4] igb: " Liang-Min Larry Wang
2015-06-10 15:09   ` [dpdk-dev] [PATCH v4 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-06-11 21:43 ` [dpdk-dev] [PATCH v5 0/4] User-space Ethtool Liang-Min Larry Wang
2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 3/4] igb: " Liang-Min Larry Wang
2015-06-11 21:43   ` [dpdk-dev] [PATCH v5 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-06-12 22:03 ` [dpdk-dev] [PATCH v6 0/4] User-space Ethtool Liang-Min Larry Wang
2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-06-13 23:25     ` David Harton (dharton)
2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 3/4] igb: " Liang-Min Larry Wang
2015-06-12 22:03   ` [dpdk-dev] [PATCH v6 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-06-13  0:21   ` [dpdk-dev] [PATCH v6 0/4] User-space Ethtool Andrew Harvey (agh)
2015-06-17 22:22 ` [dpdk-dev] [PATCH v7 " Liang-Min Larry Wang
2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-06-25 13:39     ` Stephen Hemminger
2015-06-25 20:58       ` Wang, Liang-min
2015-06-25 13:44     ` Stephen Hemminger
2015-06-25 21:05       ` Wang, Liang-min
2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-06-25 13:45     ` Stephen Hemminger
2015-06-26  6:26       ` Andrew Harvey (agh)
2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 3/4] igb: " Liang-Min Larry Wang
2015-06-17 22:22   ` [dpdk-dev] [PATCH v7 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-06-18  2:04   ` [dpdk-dev] [PATCH v7 0/4] User-space Ethtool Stephen Hemminger
2015-06-18 12:47     ` Wang, Liang-min
2015-06-23 15:19       ` Wang, Liang-min
2015-06-24 13:55   ` Andrew Harvey (agh)
2015-06-24 17:16   ` David Harton (dharton)
2015-06-26 14:26 ` [dpdk-dev] [PATCH v8 0/5] " Liang-Min Larry Wang
2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 1/5] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-06-26 16:51     ` Stephen Hemminger
2015-06-26 17:05       ` Wang, Liang-min
2015-06-27  1:21       ` Wang, Liang-min
2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 2/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 3/5] igb: " Liang-Min Larry Wang
2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 4/5] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-06-26 14:26   ` [dpdk-dev] [PATCH v8 5/5] Changed register tables to const Liang-Min Larry Wang
2015-06-26 19:15   ` [dpdk-dev] [PATCH v8 0/5] User-space Ethtool Ananyev, Konstantin
2015-06-27  1:19 ` [dpdk-dev] [PATCH v9 " Liang-Min Larry Wang
2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 1/5] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 2/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-06-27  1:32     ` Stephen Hemminger
2015-06-27  2:37       ` Wang, Liang-min
2015-06-27  1:34     ` Stephen Hemminger
2015-06-27  2:39       ` Wang, Liang-min
2015-06-27  1:34     ` Stephen Hemminger
2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 3/5] igb: " Liang-Min Larry Wang
2015-06-27  1:35     ` Stephen Hemminger
2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 4/5] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-06-27  1:19   ` [dpdk-dev] [PATCH v9 5/5] ixgbe/igb: changed register tables to const Liang-Min Larry Wang
2015-06-27  1:36     ` Stephen Hemminger
2015-06-27  1:50       ` Wang, Liang-min
2015-06-27  2:40       ` Wang, Liang-min
2015-07-10 12:55       ` Wang, Liang-min
2015-06-27  2:36 ` [dpdk-dev] [PATCH v10 0/4] User-space Ethtool Liang-Min Larry Wang
2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 3/4] igb: " Liang-Min Larry Wang
2015-06-27  2:36   ` [dpdk-dev] [PATCH v10 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-06-27 12:25 ` [dpdk-dev] [PATCH v11 0/4] User-space Ethtool Liang-Min Larry Wang
2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 3/4] igb: " Liang-Min Larry Wang
2015-06-27 12:25   ` [dpdk-dev] [PATCH v11 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-07-07 17:39 ` [dpdk-dev] [PATCH v12 0/4] User-space Ethtool Liang-Min Larry Wang
2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 3/4] igb: " Liang-Min Larry Wang
2015-07-07 17:39   ` [dpdk-dev] [PATCH v12 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-07-10 12:48 ` [dpdk-dev] [PATCH v13 0/4] User-space Ethtool Liang-Min Larry Wang
2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 3/4] igb: " Liang-Min Larry Wang
2015-07-10 12:48   ` [dpdk-dev] [PATCH v13 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-07-12 21:22 ` [dpdk-dev] [PATCH v14 0/4] User-space Ethtool Liang-Min Larry Wang
2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-07-13 22:26     ` Thomas Monjalon
2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 3/4] igb: " Liang-Min Larry Wang
2015-07-12 21:22   ` [dpdk-dev] [PATCH v14 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-07-14  2:18 ` [dpdk-dev] [PATCH v15 0/4] User-space Ethtool Liang-Min Larry Wang
2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 1/4] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-07-15  6:16     ` Thomas Monjalon
2015-07-15 10:07       ` Wang, Liang-min
2015-07-15 10:27         ` Thomas Monjalon
2015-07-15 10:48           ` Wang, Liang-min
2015-07-15 11:20             ` Thomas Monjalon
2015-07-15 11:36               ` Wang, Liang-min
2015-07-15 12:06                 ` Thomas Monjalon
2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 2/4] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 3/4] igb: " Liang-Min Larry Wang
2015-07-14  2:18   ` [dpdk-dev] [PATCH v15 4/4] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-07-14 13:11 ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Liang-Min Larry Wang
2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 1/6] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 2/6] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 3/6] igb: " Liang-Min Larry Wang
2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 4/6] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 5/6] ethdev: change api name, version information and fix macro Liang-Min Larry Wang
2015-07-14 13:11   ` [dpdk-dev] [PATCH v16 6/6] examples/l2fwd-ethtool: replace lib with new API name Liang-Min Larry Wang
2015-07-14 20:13   ` [dpdk-dev] [PATCH v16 0/6] User-space Ethtool Thomas Monjalon
2015-07-14 20:56     ` Wang, Liang-min
2015-07-15  5:53       ` Thomas Monjalon
2015-07-15 10:15         ` Wang, Liang-min
2015-07-15 10:30           ` Thomas Monjalon
2015-07-16 13:25 ` [dpdk-dev] [PATCH v17 0/5] " Liang-Min Larry Wang
2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 1/5] ethdev: add api to support setting default mac addr Liang-Min Larry Wang
2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 2/5] ethdev: add apis to support access device info Liang-Min Larry Wang
2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 3/5] ixgbe: add ops to support ethtool ops Liang-Min Larry Wang
2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 4/5] igb: " Liang-Min Larry Wang
2015-07-16 13:25   ` [dpdk-dev] [PATCH v17 5/5] examples: new example: l2fwd-ethtool Liang-Min Larry Wang
2015-07-16 21:25     ` Thomas Monjalon
2015-07-16 21:48   ` [dpdk-dev] [PATCH v17 0/5] User-space Ethtool Thomas Monjalon
2015-07-16 21:55     ` Wang, Liang-min
2015-07-16 22:09       ` Thomas Monjalon
2015-07-16 22:15         ` Wang, Liang-min
  -- strict thread matches above, loose matches on Subject: below --
2015-05-29 19:26 [dpdk-dev] [PATCH 0/2] " Liang-Min Larry Wang
2015-05-29 19:26 ` [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs Liang-Min Larry Wang
2015-06-02 12:38   ` Thomas Monjalon
2015-06-02 13:15     ` Wang, Liang-min
2015-06-02 14:32       ` Thomas Monjalon
2015-06-02 15:47         ` Wang, Liang-min
2015-06-02 16:02           ` Thomas Monjalon
2015-06-02 17:06             ` Wang, Liang-min
2015-06-02 20:37               ` Thomas Monjalon
2015-06-02 20:56                 ` Wang, Liang-min
2015-06-03  1:00                   ` David Harton (dharton)
2015-06-03  2:09                 ` Andrew Harvey (agh)
2015-06-04 14:25                   ` O'Driscoll, Tim
2015-06-04 14:58                   ` Stephen Hemminger
2015-06-04 22:10                     ` Andrew Harvey (agh)
2015-06-05 10:46                       ` Thomas Monjalon
2015-06-05 11:25                         ` Wang, Liang-min
2015-06-05 12:47                           ` Bruce Richardson
2015-06-05 17:24                             ` Andrew Harvey (agh)
2015-06-05 21:03                               ` Thomas Monjalon
2015-06-05 13:40                           ` Thomas Monjalon
2015-06-05 14:20                             ` Wang, Liang-min
2015-06-05 16:07                         ` Andrew Harvey (agh)
2015-06-05 20:57                           ` Thomas Monjalon
2015-05-29 13:15 [dpdk-dev] [PATCH 0/2] User-space Ethtool Liang-Min Larry Wang
2015-05-29 13:15 ` [dpdk-dev] [PATCH 2/2] ethtool: add new library to provide ethtool-alike APIs Liang-Min Larry Wang
2015-05-29 15:22   ` Stephen Hemminger
2015-05-29 18:17     ` Wang, Liang-min

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).